????

Your IP : 18.216.67.249


Current Path : C:/inetpub/vhost/sdoc.nextform.vn/api/bin/.playwright/package/lib/generated/
Upload File :
Current File : C:/inetpub/vhost/sdoc.nextform.vn/api/bin/.playwright/package/lib/generated/recorderSource.js

"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.source = void 0;
const source = "\nvar __export = (target, all) => {for (var name in all) target[name] = all[name];};\nvar __toCommonJS = mod => ({ ...mod, __esModule: true });\n// packages/playwright-core/src/server/injected/recorder.ts\nvar recorder_exports = {};\n__export(recorder_exports, {\n  PollingRecorder: () => PollingRecorder,\n  Recorder: () => Recorder,\n  default: () => recorder_default\n});\nmodule.exports = __toCommonJS(recorder_exports);\n\n// packages/playwright-core/src/utils/isomorphic/stringUtils.ts\nfunction escapeWithQuotes(text, char = \"'\") {\n  const stringified = JSON.stringify(text);\n  const escapedText = stringified.substring(1, stringified.length - 1).replace(/\\\\\"/g, '\"');\n  if (char === \"'\")\n    return char + escapedText.replace(/[']/g, \"\\\\'\") + char;\n  if (char === '\"')\n    return char + escapedText.replace(/[\"]/g, '\\\\\"') + char;\n  if (char === \"`\")\n    return char + escapedText.replace(/[`]/g, \"`\") + char;\n  throw new Error(\"Invalid escape char\");\n}\nfunction toTitleCase(name) {\n  return name.charAt(0).toUpperCase() + name.substring(1);\n}\nfunction toSnakeCase(name) {\n  return name.replace(/([a-z0-9])([A-Z])/g, \"$1_$2\").replace(/([A-Z])([A-Z][a-z])/g, \"$1_$2\").toLowerCase();\n}\nfunction cssEscape(s) {\n  let result = \"\";\n  for (let i = 0; i < s.length; i++)\n    result += cssEscapeOne(s, i);\n  return result;\n}\nfunction cssEscapeOne(s, i) {\n  const c = s.charCodeAt(i);\n  if (c === 0)\n    return \"\\uFFFD\";\n  if (c >= 1 && c <= 31 || c >= 48 && c <= 57 && (i === 0 || i === 1 && s.charCodeAt(0) === 45))\n    return \"\\\\\" + c.toString(16) + \" \";\n  if (i === 0 && c === 45 && s.length === 1)\n    return \"\\\\\" + s.charAt(i);\n  if (c >= 128 || c === 45 || c === 95 || c >= 48 && c <= 57 || c >= 65 && c <= 90 || c >= 97 && c <= 122)\n    return s.charAt(i);\n  return \"\\\\\" + s.charAt(i);\n}\nfunction normalizeWhiteSpace(text) {\n  return text.replace(/\\u200b/g, \"\").trim().replace(/\\s+/g, \" \");\n}\nfunction escapeForTextSelector(text, exact) {\n  if (typeof text !== \"string\")\n    return String(text);\n  return `${JSON.stringify(text)}${exact ? \"s\" : \"i\"}`;\n}\nfunction escapeForAttributeSelector(value, exact) {\n  return `\"${value.replace(/\\\\/g, \"\\\\\\\\\").replace(/[\"]/g, '\\\\\"')}\"${exact ? \"s\" : \"i\"}`;\n}\n\n// packages/playwright-core/src/server/injected/domUtils.ts\nfunction parentElementOrShadowHost(element) {\n  if (element.parentElement)\n    return element.parentElement;\n  if (!element.parentNode)\n    return;\n  if (element.parentNode.nodeType === 11 && element.parentNode.host)\n    return element.parentNode.host;\n}\nfunction enclosingShadowRootOrDocument(element) {\n  let node = element;\n  while (node.parentNode)\n    node = node.parentNode;\n  if (node.nodeType === 11 || node.nodeType === 9)\n    return node;\n}\nfunction enclosingShadowHost(element) {\n  while (element.parentElement)\n    element = element.parentElement;\n  return parentElementOrShadowHost(element);\n}\nfunction closestCrossShadow(element, css) {\n  while (element) {\n    const closest = element.closest(css);\n    if (closest)\n      return closest;\n    element = enclosingShadowHost(element);\n  }\n}\nfunction getElementComputedStyle(element, pseudo) {\n  return element.ownerDocument && element.ownerDocument.defaultView ? element.ownerDocument.defaultView.getComputedStyle(element, pseudo) : void 0;\n}\nfunction isElementStyleVisibilityVisible(element, style) {\n  style = style != null ? style : getElementComputedStyle(element);\n  if (!style)\n    return true;\n  if (Element.prototype.checkVisibility) {\n    if (!element.checkVisibility({ checkOpacity: false, checkVisibilityCSS: false }))\n      return false;\n  } else {\n    const detailsOrSummary = element.closest(\"details,summary\");\n    if (detailsOrSummary !== element && (detailsOrSummary == null ? void 0 : detailsOrSummary.nodeName) === \"DETAILS\" && !detailsOrSummary.open)\n      return false;\n  }\n  if (style.visibility !== \"visible\")\n    return false;\n  return true;\n}\n\n// packages/playwright-core/src/server/injected/roleUtils.ts\nfunction hasExplicitAccessibleName(e) {\n  return e.hasAttribute(\"aria-label\") || e.hasAttribute(\"aria-labelledby\");\n}\nvar kAncestorPreventingLandmark = \"article:not([role]), aside:not([role]), main:not([role]), nav:not([role]), section:not([role]), [role=article], [role=complementary], [role=main], [role=navigation], [role=region]\";\nvar kGlobalAriaAttributes = [\n  \"aria-atomic\",\n  \"aria-busy\",\n  \"aria-controls\",\n  \"aria-current\",\n  \"aria-describedby\",\n  \"aria-details\",\n  \"aria-disabled\",\n  \"aria-dropeffect\",\n  \"aria-errormessage\",\n  \"aria-flowto\",\n  \"aria-grabbed\",\n  \"aria-haspopup\",\n  \"aria-hidden\",\n  \"aria-invalid\",\n  \"aria-keyshortcuts\",\n  \"aria-label\",\n  \"aria-labelledby\",\n  \"aria-live\",\n  \"aria-owns\",\n  \"aria-relevant\",\n  \"aria-roledescription\"\n];\nfunction hasGlobalAriaAttribute(e) {\n  return kGlobalAriaAttributes.some((a) => e.hasAttribute(a));\n}\nvar kImplicitRoleByTagName = {\n  \"A\": (e) => {\n    return e.hasAttribute(\"href\") ? \"link\" : null;\n  },\n  \"AREA\": (e) => {\n    return e.hasAttribute(\"href\") ? \"link\" : null;\n  },\n  \"ARTICLE\": () => \"article\",\n  \"ASIDE\": () => \"complementary\",\n  \"BLOCKQUOTE\": () => \"blockquote\",\n  \"BUTTON\": () => \"button\",\n  \"CAPTION\": () => \"caption\",\n  \"CODE\": () => \"code\",\n  \"DATALIST\": () => \"listbox\",\n  \"DD\": () => \"definition\",\n  \"DEL\": () => \"deletion\",\n  \"DETAILS\": () => \"group\",\n  \"DFN\": () => \"term\",\n  \"DIALOG\": () => \"dialog\",\n  \"DT\": () => \"term\",\n  \"EM\": () => \"emphasis\",\n  \"FIELDSET\": () => \"group\",\n  \"FIGURE\": () => \"figure\",\n  \"FOOTER\": (e) => closestCrossShadow(e, kAncestorPreventingLandmark) ? null : \"contentinfo\",\n  \"FORM\": (e) => hasExplicitAccessibleName(e) ? \"form\" : null,\n  \"H1\": () => \"heading\",\n  \"H2\": () => \"heading\",\n  \"H3\": () => \"heading\",\n  \"H4\": () => \"heading\",\n  \"H5\": () => \"heading\",\n  \"H6\": () => \"heading\",\n  \"HEADER\": (e) => closestCrossShadow(e, kAncestorPreventingLandmark) ? null : \"banner\",\n  \"HR\": () => \"separator\",\n  \"HTML\": () => \"document\",\n  \"IMG\": (e) => e.getAttribute(\"alt\") === \"\" && !hasGlobalAriaAttribute(e) && Number.isNaN(Number(String(e.getAttribute(\"tabindex\")))) ? \"presentation\" : \"img\",\n  \"INPUT\": (e) => {\n    const type = e.type.toLowerCase();\n    if (type === \"search\")\n      return e.hasAttribute(\"list\") ? \"combobox\" : \"searchbox\";\n    if ([\"email\", \"tel\", \"text\", \"url\", \"\"].includes(type)) {\n      const list = getIdRefs(e, e.getAttribute(\"list\"))[0];\n      return list && list.tagName === \"DATALIST\" ? \"combobox\" : \"textbox\";\n    }\n    if (type === \"hidden\")\n      return \"\";\n    return {\n      \"button\": \"button\",\n      \"checkbox\": \"checkbox\",\n      \"image\": \"button\",\n      \"number\": \"spinbutton\",\n      \"radio\": \"radio\",\n      \"range\": \"slider\",\n      \"reset\": \"button\",\n      \"submit\": \"button\"\n    }[type] || \"textbox\";\n  },\n  \"INS\": () => \"insertion\",\n  \"LI\": () => \"listitem\",\n  \"MAIN\": () => \"main\",\n  \"MARK\": () => \"mark\",\n  \"MATH\": () => \"math\",\n  \"MENU\": () => \"list\",\n  \"METER\": () => \"meter\",\n  \"NAV\": () => \"navigation\",\n  \"OL\": () => \"list\",\n  \"OPTGROUP\": () => \"group\",\n  \"OPTION\": () => \"option\",\n  \"OUTPUT\": () => \"status\",\n  \"P\": () => \"paragraph\",\n  \"PROGRESS\": () => \"progressbar\",\n  \"SECTION\": (e) => hasExplicitAccessibleName(e) ? \"region\" : null,\n  \"SELECT\": (e) => e.hasAttribute(\"multiple\") || e.size > 1 ? \"listbox\" : \"combobox\",\n  \"STRONG\": () => \"strong\",\n  \"SUB\": () => \"subscript\",\n  \"SUP\": () => \"superscript\",\n  \"TABLE\": () => \"table\",\n  \"TBODY\": () => \"rowgroup\",\n  \"TD\": (e) => {\n    const table = closestCrossShadow(e, \"table\");\n    const role = table ? getExplicitAriaRole(table) : \"\";\n    return role === \"grid\" || role === \"treegrid\" ? \"gridcell\" : \"cell\";\n  },\n  \"TEXTAREA\": () => \"textbox\",\n  \"TFOOT\": () => \"rowgroup\",\n  \"TH\": (e) => {\n    if (e.getAttribute(\"scope\") === \"col\")\n      return \"columnheader\";\n    if (e.getAttribute(\"scope\") === \"row\")\n      return \"rowheader\";\n    const table = closestCrossShadow(e, \"table\");\n    const role = table ? getExplicitAriaRole(table) : \"\";\n    return role === \"grid\" || role === \"treegrid\" ? \"gridcell\" : \"cell\";\n  },\n  \"THEAD\": () => \"rowgroup\",\n  \"TIME\": () => \"time\",\n  \"TR\": () => \"row\",\n  \"UL\": () => \"list\"\n};\nvar kPresentationInheritanceParents = {\n  \"DD\": [\"DL\", \"DIV\"],\n  \"DIV\": [\"DL\"],\n  \"DT\": [\"DL\", \"DIV\"],\n  \"LI\": [\"OL\", \"UL\"],\n  \"TBODY\": [\"TABLE\"],\n  \"TD\": [\"TR\"],\n  \"TFOOT\": [\"TABLE\"],\n  \"TH\": [\"TR\"],\n  \"THEAD\": [\"TABLE\"],\n  \"TR\": [\"THEAD\", \"TBODY\", \"TFOOT\", \"TABLE\"]\n};\nfunction getImplicitAriaRole(element) {\n  var _a;\n  const implicitRole = ((_a = kImplicitRoleByTagName[element.tagName]) == null ? void 0 : _a.call(kImplicitRoleByTagName, element)) || \"\";\n  if (!implicitRole)\n    return null;\n  let ancestor = element;\n  while (ancestor) {\n    const parent = parentElementOrShadowHost(ancestor);\n    const parents = kPresentationInheritanceParents[ancestor.tagName];\n    if (!parents || !parent || !parents.includes(parent.tagName))\n      break;\n    const parentExplicitRole = getExplicitAriaRole(parent);\n    if ((parentExplicitRole === \"none\" || parentExplicitRole === \"presentation\") && !hasPresentationConflictResolution(parent))\n      return parentExplicitRole;\n    ancestor = parent;\n  }\n  return implicitRole;\n}\nvar allRoles = [\n  \"alert\",\n  \"alertdialog\",\n  \"application\",\n  \"article\",\n  \"banner\",\n  \"blockquote\",\n  \"button\",\n  \"caption\",\n  \"cell\",\n  \"checkbox\",\n  \"code\",\n  \"columnheader\",\n  \"combobox\",\n  \"command\",\n  \"complementary\",\n  \"composite\",\n  \"contentinfo\",\n  \"definition\",\n  \"deletion\",\n  \"dialog\",\n  \"directory\",\n  \"document\",\n  \"emphasis\",\n  \"feed\",\n  \"figure\",\n  \"form\",\n  \"generic\",\n  \"grid\",\n  \"gridcell\",\n  \"group\",\n  \"heading\",\n  \"img\",\n  \"input\",\n  \"insertion\",\n  \"landmark\",\n  \"link\",\n  \"list\",\n  \"listbox\",\n  \"listitem\",\n  \"log\",\n  \"main\",\n  \"marquee\",\n  \"math\",\n  \"meter\",\n  \"menu\",\n  \"menubar\",\n  \"menuitem\",\n  \"menuitemcheckbox\",\n  \"menuitemradio\",\n  \"navigation\",\n  \"none\",\n  \"note\",\n  \"option\",\n  \"paragraph\",\n  \"presentation\",\n  \"progressbar\",\n  \"radio\",\n  \"radiogroup\",\n  \"range\",\n  \"region\",\n  \"roletype\",\n  \"row\",\n  \"rowgroup\",\n  \"rowheader\",\n  \"scrollbar\",\n  \"search\",\n  \"searchbox\",\n  \"section\",\n  \"sectionhead\",\n  \"select\",\n  \"separator\",\n  \"slider\",\n  \"spinbutton\",\n  \"status\",\n  \"strong\",\n  \"structure\",\n  \"subscript\",\n  \"superscript\",\n  \"switch\",\n  \"tab\",\n  \"table\",\n  \"tablist\",\n  \"tabpanel\",\n  \"term\",\n  \"textbox\",\n  \"time\",\n  \"timer\",\n  \"toolbar\",\n  \"tooltip\",\n  \"tree\",\n  \"treegrid\",\n  \"treeitem\",\n  \"widget\",\n  \"window\"\n];\nvar abstractRoles = [\"command\", \"composite\", \"input\", \"landmark\", \"range\", \"roletype\", \"section\", \"sectionhead\", \"select\", \"structure\", \"widget\", \"window\"];\nvar validRoles = allRoles.filter((role) => !abstractRoles.includes(role));\nfunction getExplicitAriaRole(element) {\n  const roles = (element.getAttribute(\"role\") || \"\").split(\" \").map((role) => role.trim());\n  return roles.find((role) => validRoles.includes(role)) || null;\n}\nfunction hasPresentationConflictResolution(element) {\n  return !hasGlobalAriaAttribute(element);\n}\nfunction getAriaRole(element) {\n  const explicitRole = getExplicitAriaRole(element);\n  if (!explicitRole)\n    return getImplicitAriaRole(element);\n  if ((explicitRole === \"none\" || explicitRole === \"presentation\") && hasPresentationConflictResolution(element))\n    return getImplicitAriaRole(element);\n  return explicitRole;\n}\nfunction getAriaBoolean(attr) {\n  return attr === null ? void 0 : attr.toLowerCase() === \"true\";\n}\nfunction isElementHiddenForAria(element, cache) {\n  if ([\"STYLE\", \"SCRIPT\", \"NOSCRIPT\", \"TEMPLATE\"].includes(element.tagName))\n    return true;\n  const isOptionInsideSelect = element.nodeName === \"OPTION\" && !!element.closest(\"select\");\n  const isSlot = element.nodeName === \"SLOT\";\n  if (!isOptionInsideSelect && !isSlot && !isElementStyleVisibilityVisible(element))\n    return true;\n  return belongsToDisplayNoneOrAriaHidden(element, cache);\n}\nfunction belongsToDisplayNoneOrAriaHidden(element, cache) {\n  if (!cache.has(element)) {\n    const style = getElementComputedStyle(element);\n    let hidden = !style || style.display === \"none\" || getAriaBoolean(element.getAttribute(\"aria-hidden\")) === true;\n    if (!hidden) {\n      const parent = parentElementOrShadowHost(element);\n      if (parent)\n        hidden = hidden || belongsToDisplayNoneOrAriaHidden(parent, cache);\n    }\n    cache.set(element, hidden);\n  }\n  return cache.get(element);\n}\nfunction getIdRefs(element, ref) {\n  if (!ref)\n    return [];\n  const root = enclosingShadowRootOrDocument(element);\n  if (!root)\n    return [];\n  try {\n    const ids = ref.split(\" \").filter((id) => !!id);\n    const set = /* @__PURE__ */ new Set();\n    for (const id of ids) {\n      const firstElement = root.querySelector(\"#\" + CSS.escape(id));\n      if (firstElement)\n        set.add(firstElement);\n    }\n    return [...set];\n  } catch (e) {\n    return [];\n  }\n}\nfunction normalizeAccessbileName(s) {\n  return s.replace(/\\r\\n/g, \"\\n\").replace(/\\u00A0/g, \" \").replace(/\\s\\s+/g, \" \").trim();\n}\nfunction queryInAriaOwned(element, selector) {\n  const result = [...element.querySelectorAll(selector)];\n  for (const owned of getIdRefs(element, element.getAttribute(\"aria-owns\"))) {\n    if (owned.matches(selector))\n      result.push(owned);\n    result.push(...owned.querySelectorAll(selector));\n  }\n  return result;\n}\nfunction getPseudoContent(pseudoStyle) {\n  if (!pseudoStyle)\n    return \"\";\n  const content = pseudoStyle.getPropertyValue(\"content\");\n  if (content[0] === \"'\" && content[content.length - 1] === \"'\" || content[0] === '\"' && content[content.length - 1] === '\"') {\n    const unquoted = content.substring(1, content.length - 1);\n    const display = pseudoStyle.getPropertyValue(\"display\") || \"inline\";\n    if (display !== \"inline\")\n      return \" \" + unquoted + \" \";\n    return unquoted;\n  }\n  return \"\";\n}\nfunction getAriaLabelledByElements(element) {\n  const ref = element.getAttribute(\"aria-labelledby\");\n  if (ref === null)\n    return null;\n  return getIdRefs(element, ref);\n}\nfunction allowsNameFromContent(role, targetDescendant) {\n  const alwaysAllowsNameFromContent = [\"button\", \"cell\", \"checkbox\", \"columnheader\", \"gridcell\", \"heading\", \"link\", \"menuitem\", \"menuitemcheckbox\", \"menuitemradio\", \"option\", \"radio\", \"row\", \"rowheader\", \"switch\", \"tab\", \"tooltip\", \"treeitem\"].includes(role);\n  const descendantAllowsNameFromContent = targetDescendant && [\"\", \"caption\", \"code\", \"contentinfo\", \"definition\", \"deletion\", \"emphasis\", \"insertion\", \"list\", \"listitem\", \"mark\", \"none\", \"paragraph\", \"presentation\", \"region\", \"row\", \"rowgroup\", \"section\", \"strong\", \"subscript\", \"superscript\", \"table\", \"term\", \"time\"].includes(role);\n  return alwaysAllowsNameFromContent || descendantAllowsNameFromContent;\n}\nfunction getElementAccessibleName(element, includeHidden, hiddenCache) {\n  const elementProhibitsNaming = [\"caption\", \"code\", \"definition\", \"deletion\", \"emphasis\", \"generic\", \"insertion\", \"mark\", \"paragraph\", \"presentation\", \"strong\", \"subscript\", \"suggestion\", \"superscript\", \"term\", \"time\"].includes(getAriaRole(element) || \"\");\n  if (elementProhibitsNaming)\n    return \"\";\n  const accessibleName = normalizeAccessbileName(getElementAccessibleNameInternal(element, {\n    includeHidden,\n    hiddenCache,\n    visitedElements: /* @__PURE__ */ new Set(),\n    embeddedInLabelledBy: \"none\",\n    embeddedInLabel: \"none\",\n    embeddedInTextAlternativeElement: false,\n    embeddedInTargetElement: \"self\"\n  }));\n  return accessibleName;\n}\nfunction getElementAccessibleNameInternal(element, options) {\n  if (options.visitedElements.has(element))\n    return \"\";\n  const childOptions = {\n    ...options,\n    embeddedInLabel: options.embeddedInLabel === \"self\" ? \"descendant\" : options.embeddedInLabel,\n    embeddedInLabelledBy: options.embeddedInLabelledBy === \"self\" ? \"descendant\" : options.embeddedInLabelledBy,\n    embeddedInTargetElement: options.embeddedInTargetElement === \"self\" ? \"descendant\" : options.embeddedInTargetElement\n  };\n  if (!options.includeHidden && options.embeddedInLabelledBy !== \"self\" && isElementHiddenForAria(element, options.hiddenCache)) {\n    options.visitedElements.add(element);\n    return \"\";\n  }\n  if (options.embeddedInLabelledBy === \"none\") {\n    const refs = getAriaLabelledByElements(element) || [];\n    const accessibleName = refs.map((ref) => getElementAccessibleNameInternal(ref, {\n      ...options,\n      embeddedInLabelledBy: \"self\",\n      embeddedInTargetElement: \"none\",\n      embeddedInLabel: \"none\",\n      embeddedInTextAlternativeElement: false\n    })).join(\" \");\n    if (accessibleName)\n      return accessibleName;\n  }\n  const role = getAriaRole(element) || \"\";\n  if (options.embeddedInLabel !== \"none\" || options.embeddedInLabelledBy !== \"none\") {\n    const isOwnLabel = [...element.labels || []].includes(element);\n    const isOwnLabelledBy = getIdRefs(element, element.getAttribute(\"aria-labelledby\")).includes(element);\n    if (!isOwnLabel && !isOwnLabelledBy) {\n      if (role === \"textbox\") {\n        options.visitedElements.add(element);\n        if (element.tagName === \"INPUT\" || element.tagName === \"TEXTAREA\")\n          return element.value;\n        return element.textContent || \"\";\n      }\n      if ([\"combobox\", \"listbox\"].includes(role)) {\n        options.visitedElements.add(element);\n        let selectedOptions;\n        if (element.tagName === \"SELECT\") {\n          selectedOptions = [...element.selectedOptions];\n          if (!selectedOptions.length && element.options.length)\n            selectedOptions.push(element.options[0]);\n        } else {\n          const listbox = role === \"combobox\" ? queryInAriaOwned(element, \"*\").find((e) => getAriaRole(e) === \"listbox\") : element;\n          selectedOptions = listbox ? queryInAriaOwned(listbox, '[aria-selected=\"true\"]').filter((e) => getAriaRole(e) === \"option\") : [];\n        }\n        return selectedOptions.map((option) => getElementAccessibleNameInternal(option, childOptions)).join(\" \");\n      }\n      if ([\"progressbar\", \"scrollbar\", \"slider\", \"spinbutton\", \"meter\"].includes(role)) {\n        options.visitedElements.add(element);\n        if (element.hasAttribute(\"aria-valuetext\"))\n          return element.getAttribute(\"aria-valuetext\") || \"\";\n        if (element.hasAttribute(\"aria-valuenow\"))\n          return element.getAttribute(\"aria-valuenow\") || \"\";\n        return element.getAttribute(\"value\") || \"\";\n      }\n      if ([\"menu\"].includes(role)) {\n        options.visitedElements.add(element);\n        return \"\";\n      }\n    }\n  }\n  const ariaLabel = element.getAttribute(\"aria-label\") || \"\";\n  if (ariaLabel.trim()) {\n    options.visitedElements.add(element);\n    return ariaLabel;\n  }\n  if (![\"presentation\", \"none\"].includes(role)) {\n    if (element.tagName === \"INPUT\" && [\"button\", \"submit\", \"reset\"].includes(element.type)) {\n      options.visitedElements.add(element);\n      const value = element.value || \"\";\n      if (value.trim())\n        return value;\n      if (element.type === \"submit\")\n        return \"Submit\";\n      if (element.type === \"reset\")\n        return \"Reset\";\n      const title = element.getAttribute(\"title\") || \"\";\n      return title;\n    }\n    if (element.tagName === \"INPUT\" && element.type === \"image\") {\n      options.visitedElements.add(element);\n      const alt = element.getAttribute(\"alt\") || \"\";\n      if (alt.trim())\n        return alt;\n      const labels = element.labels || [];\n      if (labels.length) {\n        return [...labels].map((label) => getElementAccessibleNameInternal(label, {\n          ...options,\n          embeddedInLabel: \"self\",\n          embeddedInTextAlternativeElement: false,\n          embeddedInLabelledBy: \"none\",\n          embeddedInTargetElement: \"none\"\n        })).filter((accessibleName) => !!accessibleName).join(\" \");\n      }\n      const title = element.getAttribute(\"title\") || \"\";\n      if (title.trim())\n        return title;\n      return \"Submit\";\n    }\n    if (element.tagName === \"TEXTAREA\" || element.tagName === \"SELECT\" || element.tagName === \"INPUT\") {\n      options.visitedElements.add(element);\n      const labels = element.labels || [];\n      if (labels.length) {\n        return [...labels].map((label) => getElementAccessibleNameInternal(label, {\n          ...options,\n          embeddedInLabel: \"self\",\n          embeddedInTextAlternativeElement: false,\n          embeddedInLabelledBy: \"none\",\n          embeddedInTargetElement: \"none\"\n        })).filter((accessibleName) => !!accessibleName).join(\" \");\n      }\n      const usePlaceholder = element.tagName === \"INPUT\" && [\"text\", \"password\", \"search\", \"tel\", \"email\", \"url\"].includes(element.type) || element.tagName === \"TEXTAREA\";\n      const placeholder = element.getAttribute(\"placeholder\") || \"\";\n      const title = element.getAttribute(\"title\") || \"\";\n      if (!usePlaceholder || title)\n        return title;\n      return placeholder;\n    }\n    if (element.tagName === \"FIELDSET\") {\n      options.visitedElements.add(element);\n      for (let child = element.firstElementChild; child; child = child.nextElementSibling) {\n        if (child.tagName === \"LEGEND\") {\n          return getElementAccessibleNameInternal(child, {\n            ...childOptions,\n            embeddedInTextAlternativeElement: true\n          });\n        }\n      }\n      const title = element.getAttribute(\"title\") || \"\";\n      return title;\n    }\n    if (element.tagName === \"FIGURE\") {\n      options.visitedElements.add(element);\n      for (let child = element.firstElementChild; child; child = child.nextElementSibling) {\n        if (child.tagName === \"FIGCAPTION\") {\n          return getElementAccessibleNameInternal(child, {\n            ...childOptions,\n            embeddedInTextAlternativeElement: true\n          });\n        }\n      }\n      const title = element.getAttribute(\"title\") || \"\";\n      return title;\n    }\n    if (element.tagName === \"IMG\") {\n      options.visitedElements.add(element);\n      const alt = element.getAttribute(\"alt\") || \"\";\n      if (alt.trim())\n        return alt;\n      const title = element.getAttribute(\"title\") || \"\";\n      return title;\n    }\n    if (element.tagName === \"TABLE\") {\n      options.visitedElements.add(element);\n      for (let child = element.firstElementChild; child; child = child.nextElementSibling) {\n        if (child.tagName === \"CAPTION\") {\n          return getElementAccessibleNameInternal(child, {\n            ...childOptions,\n            embeddedInTextAlternativeElement: true\n          });\n        }\n      }\n      const summary = element.getAttribute(\"summary\") || \"\";\n      if (summary)\n        return summary;\n    }\n    if (element.tagName === \"AREA\") {\n      options.visitedElements.add(element);\n      const alt = element.getAttribute(\"alt\") || \"\";\n      if (alt.trim())\n        return alt;\n      const title = element.getAttribute(\"title\") || \"\";\n      return title;\n    }\n    if (element.tagName === \"SVG\" && element.ownerSVGElement) {\n      options.visitedElements.add(element);\n      for (let child = element.firstElementChild; child; child = child.nextElementSibling) {\n        if (child.tagName === \"TITLE\" && element.ownerSVGElement) {\n          return getElementAccessibleNameInternal(child, {\n            ...childOptions,\n            embeddedInTextAlternativeElement: true\n          });\n        }\n      }\n    }\n  }\n  if (allowsNameFromContent(role, options.embeddedInTargetElement === \"descendant\") || options.embeddedInLabelledBy !== \"none\" || options.embeddedInLabel !== \"none\" || options.embeddedInTextAlternativeElement) {\n    options.visitedElements.add(element);\n    const tokens = [];\n    const visit = (node, skipSlotted) => {\n      var _a;\n      if (skipSlotted && node.assignedSlot)\n        return;\n      if (node.nodeType === 1) {\n        const display = ((_a = getElementComputedStyle(node)) == null ? void 0 : _a.getPropertyValue(\"display\")) || \"inline\";\n        let token = getElementAccessibleNameInternal(node, childOptions);\n        if (display !== \"inline\" || node.nodeName === \"BR\")\n          token = \" \" + token + \" \";\n        tokens.push(token);\n      } else if (node.nodeType === 3) {\n        tokens.push(node.textContent || \"\");\n      }\n    };\n    tokens.push(getPseudoContent(getElementComputedStyle(element, \"::before\")));\n    const assignedNodes = element.nodeName === \"SLOT\" ? element.assignedNodes() : [];\n    if (assignedNodes.length) {\n      for (const child of assignedNodes)\n        visit(child, false);\n    } else {\n      for (let child = element.firstChild; child; child = child.nextSibling)\n        visit(child, true);\n      if (element.shadowRoot) {\n        for (let child = element.shadowRoot.firstChild; child; child = child.nextSibling)\n          visit(child, true);\n      }\n      for (const owned of getIdRefs(element, element.getAttribute(\"aria-owns\")))\n        visit(owned, true);\n    }\n    tokens.push(getPseudoContent(getElementComputedStyle(element, \"::after\")));\n    const accessibleName = tokens.join(\"\");\n    if (accessibleName.trim())\n      return accessibleName;\n  }\n  if (![\"presentation\", \"none\"].includes(role) || element.tagName === \"IFRAME\") {\n    options.visitedElements.add(element);\n    const title = element.getAttribute(\"title\") || \"\";\n    if (title.trim())\n      return title;\n  }\n  options.visitedElements.add(element);\n  return \"\";\n}\n\n// packages/playwright-core/src/server/injected/selectorUtils.ts\nfunction shouldSkipForTextMatching(element) {\n  const document = element.ownerDocument;\n  return element.nodeName === \"SCRIPT\" || element.nodeName === \"NOSCRIPT\" || element.nodeName === \"STYLE\" || document.head && document.head.contains(element);\n}\nfunction elementText(cache, root) {\n  let value = cache.get(root);\n  if (value === void 0) {\n    value = { full: \"\", immediate: [] };\n    if (!shouldSkipForTextMatching(root)) {\n      let currentImmediate = \"\";\n      if (root instanceof HTMLInputElement && (root.type === \"submit\" || root.type === \"button\")) {\n        value = { full: root.value, immediate: [root.value] };\n      } else {\n        for (let child = root.firstChild; child; child = child.nextSibling) {\n          if (child.nodeType === Node.TEXT_NODE) {\n            value.full += child.nodeValue || \"\";\n            currentImmediate += child.nodeValue || \"\";\n          } else {\n            if (currentImmediate)\n              value.immediate.push(currentImmediate);\n            currentImmediate = \"\";\n            if (child.nodeType === Node.ELEMENT_NODE)\n              value.full += elementText(cache, child).full;\n          }\n        }\n        if (currentImmediate)\n          value.immediate.push(currentImmediate);\n        if (root.shadowRoot)\n          value.full += elementText(cache, root.shadowRoot).full;\n      }\n    }\n    cache.set(root, value);\n  }\n  return value;\n}\n\n// packages/playwright-core/src/server/injected/selectorGenerator.ts\nvar cacheAllowText = /* @__PURE__ */ new Map();\nvar cacheDisallowText = /* @__PURE__ */ new Map();\nvar kTextScoreRange = 10;\nvar kExactPenalty = kTextScoreRange / 2;\nvar kTestIdScore = 1;\nvar kOtherTestIdScore = 2;\nvar kIframeByAttributeScore = 10;\nvar kBeginPenalizedScore = 50;\nvar kPlaceholderScore = 100;\nvar kLabelScore = 120;\nvar kRoleWithNameScore = 140;\nvar kAltTextScore = 160;\nvar kTextScore = 180;\nvar kTitleScore = 200;\nvar kTextScoreRegex = 250;\nvar kPlaceholderScoreExact = kPlaceholderScore + kExactPenalty;\nvar kLabelScoreExact = kLabelScore + kExactPenalty;\nvar kRoleWithNameScoreExact = kRoleWithNameScore + kExactPenalty;\nvar kAltTextScoreExact = kAltTextScore + kExactPenalty;\nvar kTextScoreExact = kTextScore + kExactPenalty;\nvar kTitleScoreExact = kTitleScore + kExactPenalty;\nvar kEndPenalizedScore = 300;\nvar kCSSIdScore = 500;\nvar kRoleWithoutNameScore = 510;\nvar kCSSInputTypeNameScore = 520;\nvar kCSSTagNameScore = 530;\nvar kNthScore = 1e4;\nvar kCSSFallbackScore = 1e7;\nfunction querySelector(injectedScript, selector, ownerDocument) {\n  try {\n    const parsedSelector = injectedScript.parseSelector(selector);\n    return {\n      selector,\n      elements: injectedScript.querySelectorAll(parsedSelector, ownerDocument)\n    };\n  } catch (e) {\n    return {\n      selector,\n      elements: []\n    };\n  }\n}\nfunction generateSelector(injectedScript, targetElement, testIdAttributeName) {\n  injectedScript._evaluator.begin();\n  try {\n    targetElement = targetElement.closest(\"button,select,input,[role=button],[role=checkbox],[role=radio],a,[role=link]\") || targetElement;\n    const targetTokens = generateSelectorFor(injectedScript, targetElement, testIdAttributeName);\n    const bestTokens = targetTokens || cssFallback(injectedScript, targetElement);\n    const selector = joinTokens(bestTokens);\n    const parsedSelector = injectedScript.parseSelector(selector);\n    return {\n      selector,\n      elements: injectedScript.querySelectorAll(parsedSelector, targetElement.ownerDocument)\n    };\n  } finally {\n    cacheAllowText.clear();\n    cacheDisallowText.clear();\n    injectedScript._evaluator.end();\n  }\n}\nfunction filterRegexTokens(textCandidates) {\n  return textCandidates.filter((c) => c[0].selector[0] !== \"/\");\n}\nfunction generateSelectorFor(injectedScript, targetElement, testIdAttributeName) {\n  if (targetElement.ownerDocument.documentElement === targetElement)\n    return [{ engine: \"css\", selector: \"html\", score: 1 }];\n  const accessibleNameCache = /* @__PURE__ */ new Map();\n  const calculate = (element, allowText) => {\n    const allowNthMatch = element === targetElement;\n    let textCandidates = allowText ? buildTextCandidates(injectedScript, element, element === targetElement, accessibleNameCache) : [];\n    if (element !== targetElement) {\n      textCandidates = filterRegexTokens(textCandidates);\n    }\n    const noTextCandidates = buildCandidates(injectedScript, element, testIdAttributeName, accessibleNameCache).map((token) => [token]);\n    let result = chooseFirstSelector(injectedScript, targetElement.ownerDocument, element, [...textCandidates, ...noTextCandidates], allowNthMatch);\n    textCandidates = filterRegexTokens(textCandidates);\n    const checkWithText = (textCandidatesToUse) => {\n      const allowParentText = allowText && !textCandidatesToUse.length;\n      const candidates = [...textCandidatesToUse, ...noTextCandidates].filter((c) => {\n        if (!result)\n          return true;\n        return combineScores(c) < combineScores(result);\n      });\n      let bestPossibleInParent = candidates[0];\n      if (!bestPossibleInParent)\n        return;\n      for (let parent = parentElementOrShadowHost2(element); parent; parent = parentElementOrShadowHost2(parent)) {\n        const parentTokens = calculateCached(parent, allowParentText);\n        if (!parentTokens)\n          continue;\n        if (result && combineScores([...parentTokens, ...bestPossibleInParent]) >= combineScores(result))\n          continue;\n        bestPossibleInParent = chooseFirstSelector(injectedScript, parent, element, candidates, allowNthMatch);\n        if (!bestPossibleInParent)\n          return;\n        const combined = [...parentTokens, ...bestPossibleInParent];\n        if (!result || combineScores(combined) < combineScores(result))\n          result = combined;\n      }\n    };\n    checkWithText(textCandidates);\n    if (element === targetElement && textCandidates.length)\n      checkWithText([]);\n    return result;\n  };\n  const calculateCached = (element, allowText) => {\n    const cache = allowText ? cacheAllowText : cacheDisallowText;\n    let value = cache.get(element);\n    if (value === void 0) {\n      value = calculate(element, allowText);\n      cache.set(element, value);\n    }\n    return value;\n  };\n  return calculateCached(targetElement, true);\n}\nfunction buildCandidates(injectedScript, element, testIdAttributeName, accessibleNameCache) {\n  var _a;\n  const candidates = [];\n  for (const attr of [\"data-testid\", \"data-test-id\", \"data-test\"]) {\n    if (attr !== testIdAttributeName && element.getAttribute(attr))\n      candidates.push({ engine: \"css\", selector: `[${attr}=${quoteAttributeValue(element.getAttribute(attr))}]`, score: kOtherTestIdScore });\n  }\n  const idAttr = element.getAttribute(\"id\");\n  if (idAttr && !isGuidLike(idAttr))\n    candidates.push({ engine: \"css\", selector: makeSelectorForId(idAttr), score: kCSSIdScore });\n  candidates.push({ engine: \"css\", selector: cssEscape(element.nodeName.toLowerCase()), score: kCSSTagNameScore });\n  if (element.nodeName === \"IFRAME\") {\n    for (const attribute of [\"name\", \"title\"]) {\n      if (element.getAttribute(attribute))\n        candidates.push({ engine: \"css\", selector: `${cssEscape(element.nodeName.toLowerCase())}[${attribute}=${quoteAttributeValue(element.getAttribute(attribute))}]`, score: kIframeByAttributeScore });\n    }\n    if (element.getAttribute(testIdAttributeName))\n      candidates.push({ engine: \"css\", selector: `[${testIdAttributeName}=${escapeForAttributeSelector(element.getAttribute(testIdAttributeName), true)}]`, score: kTestIdScore });\n    penalizeScoreForLength([candidates]);\n    return candidates;\n  }\n  if (element.getAttribute(testIdAttributeName))\n    candidates.push({ engine: \"internal:testid\", selector: `[${testIdAttributeName}=${escapeForAttributeSelector(element.getAttribute(testIdAttributeName), true)}]`, score: kTestIdScore });\n  if (element.nodeName === \"INPUT\" || element.nodeName === \"TEXTAREA\") {\n    const input = element;\n    if (input.placeholder) {\n      candidates.push({ engine: \"internal:attr\", selector: `[placeholder=${escapeForAttributeSelector(input.placeholder, false)}]`, score: kPlaceholderScore });\n      candidates.push({ engine: \"internal:attr\", selector: `[placeholder=${escapeForAttributeSelector(input.placeholder, true)}]`, score: kPlaceholderScoreExact });\n    }\n    const label = (_a = input.labels) == null ? void 0 : _a[0];\n    if (label) {\n      const labelText = elementText(injectedScript._evaluator._cacheText, label).full.trim();\n      candidates.push({ engine: \"internal:label\", selector: escapeForTextSelector(labelText, false), score: kLabelScore });\n      candidates.push({ engine: \"internal:label\", selector: escapeForTextSelector(labelText, true), score: kLabelScoreExact });\n    }\n  }\n  const ariaRole = getAriaRole(element);\n  if (ariaRole && ![\"none\", \"presentation\"].includes(ariaRole)) {\n    const ariaName = getElementAccessibleName(element, false, accessibleNameCache);\n    if (ariaName) {\n      candidates.push({ engine: \"internal:role\", selector: `${ariaRole}[name=${escapeForAttributeSelector(ariaName, false)}]`, score: kRoleWithNameScore });\n      candidates.push({ engine: \"internal:role\", selector: `${ariaRole}[name=${escapeForAttributeSelector(ariaName, true)}]`, score: kRoleWithNameScoreExact });\n    } else {\n      candidates.push({ engine: \"internal:role\", selector: ariaRole, score: kRoleWithoutNameScore });\n    }\n  }\n  if (element.getAttribute(\"alt\") && [\"APPLET\", \"AREA\", \"IMG\", \"INPUT\"].includes(element.nodeName)) {\n    candidates.push({ engine: \"internal:attr\", selector: `[alt=${escapeForAttributeSelector(element.getAttribute(\"alt\"), false)}]`, score: kAltTextScore });\n    candidates.push({ engine: \"internal:attr\", selector: `[alt=${escapeForAttributeSelector(element.getAttribute(\"alt\"), true)}]`, score: kAltTextScoreExact });\n  }\n  if (element.getAttribute(\"name\") && [\"BUTTON\", \"FORM\", \"FIELDSET\", \"FRAME\", \"IFRAME\", \"INPUT\", \"KEYGEN\", \"OBJECT\", \"OUTPUT\", \"SELECT\", \"TEXTAREA\", \"MAP\", \"META\", \"PARAM\"].includes(element.nodeName))\n    candidates.push({ engine: \"css\", selector: `${cssEscape(element.nodeName.toLowerCase())}[name=${quoteAttributeValue(element.getAttribute(\"name\"))}]`, score: kCSSInputTypeNameScore });\n  if (element.getAttribute(\"title\")) {\n    candidates.push({ engine: \"internal:attr\", selector: `[title=${escapeForAttributeSelector(element.getAttribute(\"title\"), false)}]`, score: kTitleScore });\n    candidates.push({ engine: \"internal:attr\", selector: `[title=${escapeForAttributeSelector(element.getAttribute(\"title\"), true)}]`, score: kTitleScoreExact });\n  }\n  if ([\"INPUT\", \"TEXTAREA\"].includes(element.nodeName) && element.getAttribute(\"type\") !== \"hidden\") {\n    if (element.getAttribute(\"type\"))\n      candidates.push({ engine: \"css\", selector: `${cssEscape(element.nodeName.toLowerCase())}[type=${quoteAttributeValue(element.getAttribute(\"type\"))}]`, score: kCSSInputTypeNameScore });\n  }\n  if ([\"INPUT\", \"TEXTAREA\", \"SELECT\"].includes(element.nodeName) && element.getAttribute(\"type\") !== \"hidden\")\n    candidates.push({ engine: \"css\", selector: cssEscape(element.nodeName.toLowerCase()), score: kCSSInputTypeNameScore + 1 });\n  penalizeScoreForLength([candidates]);\n  return candidates;\n}\nfunction buildTextCandidates(injectedScript, element, isTargetNode, accessibleNameCache) {\n  if (element.nodeName === \"SELECT\")\n    return [];\n  const text = normalizeWhiteSpace(elementText(injectedScript._evaluator._cacheText, element).full).substring(0, 80);\n  if (!text)\n    return [];\n  const candidates = [];\n  const escaped = escapeForTextSelector(text, false);\n  if (isTargetNode) {\n    candidates.push([{ engine: \"internal:text\", selector: escaped, score: kTextScore }]);\n    candidates.push([{ engine: \"internal:text\", selector: escapeForTextSelector(text, true), score: kTextScoreExact }]);\n  }\n  const ariaRole = getAriaRole(element);\n  const candidate = [];\n  if (ariaRole && ![\"none\", \"presentation\"].includes(ariaRole)) {\n    const ariaName = getElementAccessibleName(element, false, accessibleNameCache);\n    if (ariaName) {\n      candidate.push({ engine: \"internal:role\", selector: `${ariaRole}[name=${escapeForAttributeSelector(ariaName, false)}]`, score: kRoleWithNameScore });\n      candidate.push({ engine: \"internal:role\", selector: `${ariaRole}[name=${escapeForAttributeSelector(ariaName, true)}]`, score: kRoleWithNameScoreExact });\n    } else {\n      candidate.push({ engine: \"internal:role\", selector: ariaRole, score: kRoleWithoutNameScore });\n    }\n  } else {\n    candidate.push({ engine: \"css\", selector: element.nodeName.toLowerCase(), score: kCSSTagNameScore });\n  }\n  candidates.push([...candidate, { engine: \"internal:has-text\", selector: escaped, score: kTextScore }]);\n  if (text.length <= 80)\n    candidates.push([...candidate, { engine: \"internal:has-text\", selector: \"/^\" + escapeRegExp(text) + \"$/\", score: kTextScoreRegex }]);\n  penalizeScoreForLength(candidates);\n  return candidates;\n}\nfunction parentElementOrShadowHost2(element) {\n  if (element.parentElement)\n    return element.parentElement;\n  if (!element.parentNode)\n    return null;\n  if (element.parentNode.nodeType === Node.DOCUMENT_FRAGMENT_NODE && element.parentNode.host)\n    return element.parentNode.host;\n  return null;\n}\nfunction makeSelectorForId(id) {\n  return /^[a-zA-Z][a-zA-Z0-9\\-\\_]+$/.test(id) ? \"#\" + id : `[id=\"${cssEscape(id)}\"]`;\n}\nfunction cssFallback(injectedScript, targetElement) {\n  const root = targetElement.ownerDocument;\n  const tokens = [];\n  function uniqueCSSSelector(prefix) {\n    const path = tokens.slice();\n    if (prefix)\n      path.unshift(prefix);\n    const selector = path.join(\" > \");\n    const parsedSelector = injectedScript.parseSelector(selector);\n    const node = injectedScript.querySelector(parsedSelector, targetElement.ownerDocument, false);\n    return node === targetElement ? selector : void 0;\n  }\n  function makeStrict(selector) {\n    const token = { engine: \"css\", selector, score: kCSSFallbackScore };\n    const parsedSelector = injectedScript.parseSelector(selector);\n    const elements = injectedScript.querySelectorAll(parsedSelector, targetElement.ownerDocument);\n    if (elements.length === 1)\n      return [token];\n    const nth = { engine: \"nth\", selector: String(elements.indexOf(targetElement)), score: kNthScore };\n    return [token, nth];\n  }\n  for (let element = targetElement; element && element !== root; element = parentElementOrShadowHost2(element)) {\n    const nodeName = element.nodeName.toLowerCase();\n    let bestTokenForLevel = \"\";\n    if (element.id) {\n      const token = makeSelectorForId(element.id);\n      const selector = uniqueCSSSelector(token);\n      if (selector)\n        return makeStrict(selector);\n      bestTokenForLevel = token;\n    }\n    const parent = element.parentNode;\n    const classes = [...element.classList];\n    for (let i = 0; i < classes.length; ++i) {\n      const token = \".\" + cssEscape(classes.slice(0, i + 1).join(\".\"));\n      const selector = uniqueCSSSelector(token);\n      if (selector)\n        return makeStrict(selector);\n      if (!bestTokenForLevel && parent) {\n        const sameClassSiblings = parent.querySelectorAll(token);\n        if (sameClassSiblings.length === 1)\n          bestTokenForLevel = token;\n      }\n    }\n    if (parent) {\n      const siblings = [...parent.children];\n      const sameTagSiblings = siblings.filter((sibling) => sibling.nodeName.toLowerCase() === nodeName);\n      const token = sameTagSiblings.indexOf(element) === 0 ? cssEscape(nodeName) : `${cssEscape(nodeName)}:nth-child(${1 + siblings.indexOf(element)})`;\n      const selector = uniqueCSSSelector(token);\n      if (selector)\n        return makeStrict(selector);\n      if (!bestTokenForLevel)\n        bestTokenForLevel = token;\n    } else if (!bestTokenForLevel) {\n      bestTokenForLevel = nodeName;\n    }\n    tokens.unshift(bestTokenForLevel);\n  }\n  return makeStrict(uniqueCSSSelector());\n}\nfunction quoteAttributeValue(text) {\n  return `\"${cssEscape(text).replace(/\\\\ /g, \" \")}\"`;\n}\nfunction penalizeScoreForLength(groups) {\n  for (const group of groups) {\n    for (const token of group) {\n      if (token.score > kBeginPenalizedScore && token.score < kEndPenalizedScore)\n        token.score += Math.min(kTextScoreRange, token.selector.length / 10 | 0);\n    }\n  }\n}\nfunction joinTokens(tokens) {\n  const parts = [];\n  let lastEngine = \"\";\n  for (const { engine, selector } of tokens) {\n    if (parts.length && (lastEngine !== \"css\" || engine !== \"css\" || selector.startsWith(\":nth-match(\")))\n      parts.push(\">>\");\n    lastEngine = engine;\n    if (engine === \"css\")\n      parts.push(selector);\n    else\n      parts.push(`${engine}=${selector}`);\n  }\n  return parts.join(\" \");\n}\nfunction combineScores(tokens) {\n  let score = 0;\n  for (let i = 0; i < tokens.length; i++)\n    score += tokens[i].score * (tokens.length - i);\n  return score;\n}\nfunction chooseFirstSelector(injectedScript, scope, targetElement, selectors, allowNthMatch) {\n  const joined = selectors.map((tokens) => ({ tokens, score: combineScores(tokens) }));\n  joined.sort((a, b) => a.score - b.score);\n  let bestWithIndex = null;\n  for (const { tokens } of joined) {\n    const parsedSelector = injectedScript.parseSelector(joinTokens(tokens));\n    const result = injectedScript.querySelectorAll(parsedSelector, scope);\n    if (result[0] === targetElement && result.length === 1) {\n      return tokens;\n    }\n    const index = result.indexOf(targetElement);\n    if (!allowNthMatch || bestWithIndex || index === -1 || result.length > 5)\n      continue;\n    const nth = { engine: \"nth\", selector: String(index), score: kNthScore };\n    bestWithIndex = [...tokens, nth];\n  }\n  return bestWithIndex;\n}\nfunction isGuidLike(id) {\n  let lastCharacterType;\n  let transitionCount = 0;\n  for (let i = 0; i < id.length; ++i) {\n    const c = id[i];\n    let characterType;\n    if (c === \"-\" || c === \"_\")\n      continue;\n    if (c >= \"a\" && c <= \"z\")\n      characterType = \"lower\";\n    else if (c >= \"A\" && c <= \"Z\")\n      characterType = \"upper\";\n    else if (c >= \"0\" && c <= \"9\")\n      characterType = \"digit\";\n    else\n      characterType = \"other\";\n    if (characterType === \"lower\" && lastCharacterType === \"upper\") {\n      lastCharacterType = characterType;\n      continue;\n    }\n    if (lastCharacterType && lastCharacterType !== characterType)\n      ++transitionCount;\n    lastCharacterType = characterType;\n  }\n  return transitionCount >= id.length / 4;\n}\nfunction escapeRegExp(s) {\n  return s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n// packages/playwright-core/src/utils/isomorphic/cssTokenizer.ts\nvar between = function(num, first, last) {\n  return num >= first && num <= last;\n};\nfunction digit(code) {\n  return between(code, 48, 57);\n}\nfunction hexdigit(code) {\n  return digit(code) || between(code, 65, 70) || between(code, 97, 102);\n}\nfunction uppercaseletter(code) {\n  return between(code, 65, 90);\n}\nfunction lowercaseletter(code) {\n  return between(code, 97, 122);\n}\nfunction letter(code) {\n  return uppercaseletter(code) || lowercaseletter(code);\n}\nfunction nonascii(code) {\n  return code >= 128;\n}\nfunction namestartchar(code) {\n  return letter(code) || nonascii(code) || code === 95;\n}\nfunction namechar(code) {\n  return namestartchar(code) || digit(code) || code === 45;\n}\nfunction nonprintable(code) {\n  return between(code, 0, 8) || code === 11 || between(code, 14, 31) || code === 127;\n}\nfunction newline(code) {\n  return code === 10;\n}\nfunction whitespace(code) {\n  return newline(code) || code === 9 || code === 32;\n}\nvar maximumallowedcodepoint = 1114111;\nvar InvalidCharacterError = class extends Error {\n  constructor(message) {\n    super(message);\n    this.name = \"InvalidCharacterError\";\n  }\n};\nfunction preprocess(str) {\n  const codepoints = [];\n  for (let i = 0; i < str.length; i++) {\n    let code = str.charCodeAt(i);\n    if (code === 13 && str.charCodeAt(i + 1) === 10) {\n      code = 10;\n      i++;\n    }\n    if (code === 13 || code === 12)\n      code = 10;\n    if (code === 0)\n      code = 65533;\n    if (between(code, 55296, 56319) && between(str.charCodeAt(i + 1), 56320, 57343)) {\n      const lead = code - 55296;\n      const trail = str.charCodeAt(i + 1) - 56320;\n      code = Math.pow(2, 16) + lead * Math.pow(2, 10) + trail;\n      i++;\n    }\n    codepoints.push(code);\n  }\n  return codepoints;\n}\nfunction stringFromCode(code) {\n  if (code <= 65535)\n    return String.fromCharCode(code);\n  code -= Math.pow(2, 16);\n  const lead = Math.floor(code / Math.pow(2, 10)) + 55296;\n  const trail = code % Math.pow(2, 10) + 56320;\n  return String.fromCharCode(lead) + String.fromCharCode(trail);\n}\nfunction tokenize(str1) {\n  const str = preprocess(str1);\n  let i = -1;\n  const tokens = [];\n  let code;\n  let line = 0;\n  let column = 0;\n  let lastLineLength = 0;\n  const incrLineno = function() {\n    line += 1;\n    lastLineLength = column;\n    column = 0;\n  };\n  const locStart = { line, column };\n  const codepoint = function(i2) {\n    if (i2 >= str.length)\n      return -1;\n    return str[i2];\n  };\n  const next = function(num) {\n    if (num === void 0)\n      num = 1;\n    if (num > 3)\n      throw \"Spec Error: no more than three codepoints of lookahead.\";\n    return codepoint(i + num);\n  };\n  const consume = function(num) {\n    if (num === void 0)\n      num = 1;\n    i += num;\n    code = codepoint(i);\n    if (newline(code))\n      incrLineno();\n    else\n      column += num;\n    return true;\n  };\n  const reconsume = function() {\n    i -= 1;\n    if (newline(code)) {\n      line -= 1;\n      column = lastLineLength;\n    } else {\n      column -= 1;\n    }\n    locStart.line = line;\n    locStart.column = column;\n    return true;\n  };\n  const eof = function(codepoint2) {\n    if (codepoint2 === void 0)\n      codepoint2 = code;\n    return codepoint2 === -1;\n  };\n  const donothing = function() {\n  };\n  const parseerror = function() {\n  };\n  const consumeAToken = function() {\n    consumeComments();\n    consume();\n    if (whitespace(code)) {\n      while (whitespace(next()))\n        consume();\n      return new WhitespaceToken();\n    } else if (code === 34) {\n      return consumeAStringToken();\n    } else if (code === 35) {\n      if (namechar(next()) || areAValidEscape(next(1), next(2))) {\n        const token = new HashToken(\"\");\n        if (wouldStartAnIdentifier(next(1), next(2), next(3)))\n          token.type = \"id\";\n        token.value = consumeAName();\n        return token;\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 36) {\n      if (next() === 61) {\n        consume();\n        return new SuffixMatchToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 39) {\n      return consumeAStringToken();\n    } else if (code === 40) {\n      return new OpenParenToken();\n    } else if (code === 41) {\n      return new CloseParenToken();\n    } else if (code === 42) {\n      if (next() === 61) {\n        consume();\n        return new SubstringMatchToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 43) {\n      if (startsWithANumber()) {\n        reconsume();\n        return consumeANumericToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 44) {\n      return new CommaToken();\n    } else if (code === 45) {\n      if (startsWithANumber()) {\n        reconsume();\n        return consumeANumericToken();\n      } else if (next(1) === 45 && next(2) === 62) {\n        consume(2);\n        return new CDCToken();\n      } else if (startsWithAnIdentifier()) {\n        reconsume();\n        return consumeAnIdentlikeToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 46) {\n      if (startsWithANumber()) {\n        reconsume();\n        return consumeANumericToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 58) {\n      return new ColonToken();\n    } else if (code === 59) {\n      return new SemicolonToken();\n    } else if (code === 60) {\n      if (next(1) === 33 && next(2) === 45 && next(3) === 45) {\n        consume(3);\n        return new CDOToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 64) {\n      if (wouldStartAnIdentifier(next(1), next(2), next(3)))\n        return new AtKeywordToken(consumeAName());\n      else\n        return new DelimToken(code);\n    } else if (code === 91) {\n      return new OpenSquareToken();\n    } else if (code === 92) {\n      if (startsWithAValidEscape()) {\n        reconsume();\n        return consumeAnIdentlikeToken();\n      } else {\n        parseerror();\n        return new DelimToken(code);\n      }\n    } else if (code === 93) {\n      return new CloseSquareToken();\n    } else if (code === 94) {\n      if (next() === 61) {\n        consume();\n        return new PrefixMatchToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 123) {\n      return new OpenCurlyToken();\n    } else if (code === 124) {\n      if (next() === 61) {\n        consume();\n        return new DashMatchToken();\n      } else if (next() === 124) {\n        consume();\n        return new ColumnToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (code === 125) {\n      return new CloseCurlyToken();\n    } else if (code === 126) {\n      if (next() === 61) {\n        consume();\n        return new IncludeMatchToken();\n      } else {\n        return new DelimToken(code);\n      }\n    } else if (digit(code)) {\n      reconsume();\n      return consumeANumericToken();\n    } else if (namestartchar(code)) {\n      reconsume();\n      return consumeAnIdentlikeToken();\n    } else if (eof()) {\n      return new EOFToken();\n    } else {\n      return new DelimToken(code);\n    }\n  };\n  const consumeComments = function() {\n    while (next(1) === 47 && next(2) === 42) {\n      consume(2);\n      while (true) {\n        consume();\n        if (code === 42 && next() === 47) {\n          consume();\n          break;\n        } else if (eof()) {\n          parseerror();\n          return;\n        }\n      }\n    }\n  };\n  const consumeANumericToken = function() {\n    const num = consumeANumber();\n    if (wouldStartAnIdentifier(next(1), next(2), next(3))) {\n      const token = new DimensionToken();\n      token.value = num.value;\n      token.repr = num.repr;\n      token.type = num.type;\n      token.unit = consumeAName();\n      return token;\n    } else if (next() === 37) {\n      consume();\n      const token = new PercentageToken();\n      token.value = num.value;\n      token.repr = num.repr;\n      return token;\n    } else {\n      const token = new NumberToken();\n      token.value = num.value;\n      token.repr = num.repr;\n      token.type = num.type;\n      return token;\n    }\n  };\n  const consumeAnIdentlikeToken = function() {\n    const str2 = consumeAName();\n    if (str2.toLowerCase() === \"url\" && next() === 40) {\n      consume();\n      while (whitespace(next(1)) && whitespace(next(2)))\n        consume();\n      if (next() === 34 || next() === 39)\n        return new FunctionToken(str2);\n      else if (whitespace(next()) && (next(2) === 34 || next(2) === 39))\n        return new FunctionToken(str2);\n      else\n        return consumeAURLToken();\n    } else if (next() === 40) {\n      consume();\n      return new FunctionToken(str2);\n    } else {\n      return new IdentToken(str2);\n    }\n  };\n  const consumeAStringToken = function(endingCodePoint) {\n    if (endingCodePoint === void 0)\n      endingCodePoint = code;\n    let string = \"\";\n    while (consume()) {\n      if (code === endingCodePoint || eof()) {\n        return new StringToken(string);\n      } else if (newline(code)) {\n        parseerror();\n        reconsume();\n        return new BadStringToken();\n      } else if (code === 92) {\n        if (eof(next()))\n          donothing();\n        else if (newline(next()))\n          consume();\n        else\n          string += stringFromCode(consumeEscape());\n      } else {\n        string += stringFromCode(code);\n      }\n    }\n    throw new Error(\"Internal error\");\n  };\n  const consumeAURLToken = function() {\n    const token = new URLToken(\"\");\n    while (whitespace(next()))\n      consume();\n    if (eof(next()))\n      return token;\n    while (consume()) {\n      if (code === 41 || eof()) {\n        return token;\n      } else if (whitespace(code)) {\n        while (whitespace(next()))\n          consume();\n        if (next() === 41 || eof(next())) {\n          consume();\n          return token;\n        } else {\n          consumeTheRemnantsOfABadURL();\n          return new BadURLToken();\n        }\n      } else if (code === 34 || code === 39 || code === 40 || nonprintable(code)) {\n        parseerror();\n        consumeTheRemnantsOfABadURL();\n        return new BadURLToken();\n      } else if (code === 92) {\n        if (startsWithAValidEscape()) {\n          token.value += stringFromCode(consumeEscape());\n        } else {\n          parseerror();\n          consumeTheRemnantsOfABadURL();\n          return new BadURLToken();\n        }\n      } else {\n        token.value += stringFromCode(code);\n      }\n    }\n    throw new Error(\"Internal error\");\n  };\n  const consumeEscape = function() {\n    consume();\n    if (hexdigit(code)) {\n      const digits = [code];\n      for (let total = 0; total < 5; total++) {\n        if (hexdigit(next())) {\n          consume();\n          digits.push(code);\n        } else {\n          break;\n        }\n      }\n      if (whitespace(next()))\n        consume();\n      let value = parseInt(digits.map(function(x) {\n        return String.fromCharCode(x);\n      }).join(\"\"), 16);\n      if (value > maximumallowedcodepoint)\n        value = 65533;\n      return value;\n    } else if (eof()) {\n      return 65533;\n    } else {\n      return code;\n    }\n  };\n  const areAValidEscape = function(c1, c2) {\n    if (c1 !== 92)\n      return false;\n    if (newline(c2))\n      return false;\n    return true;\n  };\n  const startsWithAValidEscape = function() {\n    return areAValidEscape(code, next());\n  };\n  const wouldStartAnIdentifier = function(c1, c2, c3) {\n    if (c1 === 45)\n      return namestartchar(c2) || c2 === 45 || areAValidEscape(c2, c3);\n    else if (namestartchar(c1))\n      return true;\n    else if (c1 === 92)\n      return areAValidEscape(c1, c2);\n    else\n      return false;\n  };\n  const startsWithAnIdentifier = function() {\n    return wouldStartAnIdentifier(code, next(1), next(2));\n  };\n  const wouldStartANumber = function(c1, c2, c3) {\n    if (c1 === 43 || c1 === 45) {\n      if (digit(c2))\n        return true;\n      if (c2 === 46 && digit(c3))\n        return true;\n      return false;\n    } else if (c1 === 46) {\n      if (digit(c2))\n        return true;\n      return false;\n    } else if (digit(c1)) {\n      return true;\n    } else {\n      return false;\n    }\n  };\n  const startsWithANumber = function() {\n    return wouldStartANumber(code, next(1), next(2));\n  };\n  const consumeAName = function() {\n    let result = \"\";\n    while (consume()) {\n      if (namechar(code)) {\n        result += stringFromCode(code);\n      } else if (startsWithAValidEscape()) {\n        result += stringFromCode(consumeEscape());\n      } else {\n        reconsume();\n        return result;\n      }\n    }\n    throw new Error(\"Internal parse error\");\n  };\n  const consumeANumber = function() {\n    let repr = \"\";\n    let type = \"integer\";\n    if (next() === 43 || next() === 45) {\n      consume();\n      repr += stringFromCode(code);\n    }\n    while (digit(next())) {\n      consume();\n      repr += stringFromCode(code);\n    }\n    if (next(1) === 46 && digit(next(2))) {\n      consume();\n      repr += stringFromCode(code);\n      consume();\n      repr += stringFromCode(code);\n      type = \"number\";\n      while (digit(next())) {\n        consume();\n        repr += stringFromCode(code);\n      }\n    }\n    const c1 = next(1), c2 = next(2), c3 = next(3);\n    if ((c1 === 69 || c1 === 101) && digit(c2)) {\n      consume();\n      repr += stringFromCode(code);\n      consume();\n      repr += stringFromCode(code);\n      type = \"number\";\n      while (digit(next())) {\n        consume();\n        repr += stringFromCode(code);\n      }\n    } else if ((c1 === 69 || c1 === 101) && (c2 === 43 || c2 === 45) && digit(c3)) {\n      consume();\n      repr += stringFromCode(code);\n      consume();\n      repr += stringFromCode(code);\n      consume();\n      repr += stringFromCode(code);\n      type = \"number\";\n      while (digit(next())) {\n        consume();\n        repr += stringFromCode(code);\n      }\n    }\n    const value = convertAStringToANumber(repr);\n    return { type, value, repr };\n  };\n  const convertAStringToANumber = function(string) {\n    return +string;\n  };\n  const consumeTheRemnantsOfABadURL = function() {\n    while (consume()) {\n      if (code === 41 || eof()) {\n        return;\n      } else if (startsWithAValidEscape()) {\n        consumeEscape();\n        donothing();\n      } else {\n        donothing();\n      }\n    }\n  };\n  let iterationCount = 0;\n  while (!eof(next())) {\n    tokens.push(consumeAToken());\n    iterationCount++;\n    if (iterationCount > str.length * 2)\n      throw new Error(\"I'm infinite-looping!\");\n  }\n  return tokens;\n}\nvar CSSParserToken = class {\n  constructor() {\n    this.tokenType = \"\";\n  }\n  toJSON() {\n    return { token: this.tokenType };\n  }\n  toString() {\n    return this.tokenType;\n  }\n  toSource() {\n    return \"\" + this;\n  }\n};\nvar BadStringToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \"BADSTRING\";\n  }\n};\nvar BadURLToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \"BADURL\";\n  }\n};\nvar WhitespaceToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \"WHITESPACE\";\n  }\n  toString() {\n    return \"WS\";\n  }\n  toSource() {\n    return \" \";\n  }\n};\nvar CDOToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \"CDO\";\n  }\n  toSource() {\n    return \"<!--\";\n  }\n};\nvar CDCToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \"CDC\";\n  }\n  toSource() {\n    return \"-->\";\n  }\n};\nvar ColonToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \":\";\n  }\n};\nvar SemicolonToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \";\";\n  }\n};\nvar CommaToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \",\";\n  }\n};\nvar GroupingToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.value = \"\";\n    this.mirror = \"\";\n  }\n};\nvar OpenCurlyToken = class extends GroupingToken {\n  constructor() {\n    super();\n    this.tokenType = \"{\";\n    this.value = \"{\";\n    this.mirror = \"}\";\n  }\n};\nvar CloseCurlyToken = class extends GroupingToken {\n  constructor() {\n    super();\n    this.tokenType = \"}\";\n    this.value = \"}\";\n    this.mirror = \"{\";\n  }\n};\nvar OpenSquareToken = class extends GroupingToken {\n  constructor() {\n    super();\n    this.tokenType = \"[\";\n    this.value = \"[\";\n    this.mirror = \"]\";\n  }\n};\nvar CloseSquareToken = class extends GroupingToken {\n  constructor() {\n    super();\n    this.tokenType = \"]\";\n    this.value = \"]\";\n    this.mirror = \"[\";\n  }\n};\nvar OpenParenToken = class extends GroupingToken {\n  constructor() {\n    super();\n    this.tokenType = \"(\";\n    this.value = \"(\";\n    this.mirror = \")\";\n  }\n};\nvar CloseParenToken = class extends GroupingToken {\n  constructor() {\n    super();\n    this.tokenType = \")\";\n    this.value = \")\";\n    this.mirror = \"(\";\n  }\n};\nvar IncludeMatchToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \"~=\";\n  }\n};\nvar DashMatchToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \"|=\";\n  }\n};\nvar PrefixMatchToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \"^=\";\n  }\n};\nvar SuffixMatchToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \"$=\";\n  }\n};\nvar SubstringMatchToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \"*=\";\n  }\n};\nvar ColumnToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \"||\";\n  }\n};\nvar EOFToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.tokenType = \"EOF\";\n  }\n  toSource() {\n    return \"\";\n  }\n};\nvar DelimToken = class extends CSSParserToken {\n  constructor(code) {\n    super();\n    this.tokenType = \"DELIM\";\n    this.value = \"\";\n    this.value = stringFromCode(code);\n  }\n  toString() {\n    return \"DELIM(\" + this.value + \")\";\n  }\n  toJSON() {\n    const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);\n    json.value = this.value;\n    return json;\n  }\n  toSource() {\n    if (this.value === \"\\\\\")\n      return \"\\\\\\n\";\n    else\n      return this.value;\n  }\n};\nvar StringValuedToken = class extends CSSParserToken {\n  constructor() {\n    super(...arguments);\n    this.value = \"\";\n  }\n  ASCIIMatch(str) {\n    return this.value.toLowerCase() === str.toLowerCase();\n  }\n  toJSON() {\n    const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);\n    json.value = this.value;\n    return json;\n  }\n};\nvar IdentToken = class extends StringValuedToken {\n  constructor(val) {\n    super();\n    this.tokenType = \"IDENT\";\n    this.value = val;\n  }\n  toString() {\n    return \"IDENT(\" + this.value + \")\";\n  }\n  toSource() {\n    return escapeIdent(this.value);\n  }\n};\nvar FunctionToken = class extends StringValuedToken {\n  constructor(val) {\n    super();\n    this.tokenType = \"FUNCTION\";\n    this.value = val;\n    this.mirror = \")\";\n  }\n  toString() {\n    return \"FUNCTION(\" + this.value + \")\";\n  }\n  toSource() {\n    return escapeIdent(this.value) + \"(\";\n  }\n};\nvar AtKeywordToken = class extends StringValuedToken {\n  constructor(val) {\n    super();\n    this.tokenType = \"AT-KEYWORD\";\n    this.value = val;\n  }\n  toString() {\n    return \"AT(\" + this.value + \")\";\n  }\n  toSource() {\n    return \"@\" + escapeIdent(this.value);\n  }\n};\nvar HashToken = class extends StringValuedToken {\n  constructor(val) {\n    super();\n    this.tokenType = \"HASH\";\n    this.value = val;\n    this.type = \"unrestricted\";\n  }\n  toString() {\n    return \"HASH(\" + this.value + \")\";\n  }\n  toJSON() {\n    const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);\n    json.value = this.value;\n    json.type = this.type;\n    return json;\n  }\n  toSource() {\n    if (this.type === \"id\")\n      return \"#\" + escapeIdent(this.value);\n    else\n      return \"#\" + escapeHash(this.value);\n  }\n};\nvar StringToken = class extends StringValuedToken {\n  constructor(val) {\n    super();\n    this.tokenType = \"STRING\";\n    this.value = val;\n  }\n  toString() {\n    return '\"' + escapeString(this.value) + '\"';\n  }\n};\nvar URLToken = class extends StringValuedToken {\n  constructor(val) {\n    super();\n    this.tokenType = \"URL\";\n    this.value = val;\n  }\n  toString() {\n    return \"URL(\" + this.value + \")\";\n  }\n  toSource() {\n    return 'url(\"' + escapeString(this.value) + '\")';\n  }\n};\nvar NumberToken = class extends CSSParserToken {\n  constructor() {\n    super();\n    this.tokenType = \"NUMBER\";\n    this.type = \"integer\";\n    this.repr = \"\";\n  }\n  toString() {\n    if (this.type === \"integer\")\n      return \"INT(\" + this.value + \")\";\n    return \"NUMBER(\" + this.value + \")\";\n  }\n  toJSON() {\n    const json = super.toJSON();\n    json.value = this.value;\n    json.type = this.type;\n    json.repr = this.repr;\n    return json;\n  }\n  toSource() {\n    return this.repr;\n  }\n};\nvar PercentageToken = class extends CSSParserToken {\n  constructor() {\n    super();\n    this.tokenType = \"PERCENTAGE\";\n    this.repr = \"\";\n  }\n  toString() {\n    return \"PERCENTAGE(\" + this.value + \")\";\n  }\n  toJSON() {\n    const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);\n    json.value = this.value;\n    json.repr = this.repr;\n    return json;\n  }\n  toSource() {\n    return this.repr + \"%\";\n  }\n};\nvar DimensionToken = class extends CSSParserToken {\n  constructor() {\n    super();\n    this.tokenType = \"DIMENSION\";\n    this.type = \"integer\";\n    this.repr = \"\";\n    this.unit = \"\";\n  }\n  toString() {\n    return \"DIM(\" + this.value + \",\" + this.unit + \")\";\n  }\n  toJSON() {\n    const json = this.constructor.prototype.constructor.prototype.toJSON.call(this);\n    json.value = this.value;\n    json.type = this.type;\n    json.repr = this.repr;\n    json.unit = this.unit;\n    return json;\n  }\n  toSource() {\n    const source = this.repr;\n    let unit = escapeIdent(this.unit);\n    if (unit[0].toLowerCase() === \"e\" && (unit[1] === \"-\" || between(unit.charCodeAt(1), 48, 57))) {\n      unit = \"\\\\65 \" + unit.slice(1, unit.length);\n    }\n    return source + unit;\n  }\n};\nfunction escapeIdent(string) {\n  string = \"\" + string;\n  let result = \"\";\n  const firstcode = string.charCodeAt(0);\n  for (let i = 0; i < string.length; i++) {\n    const code = string.charCodeAt(i);\n    if (code === 0)\n      throw new InvalidCharacterError(\"Invalid character: the input contains U+0000.\");\n    if (between(code, 1, 31) || code === 127 || i === 0 && between(code, 48, 57) || i === 1 && between(code, 48, 57) && firstcode === 45)\n      result += \"\\\\\" + code.toString(16) + \" \";\n    else if (code >= 128 || code === 45 || code === 95 || between(code, 48, 57) || between(code, 65, 90) || between(code, 97, 122))\n      result += string[i];\n    else\n      result += \"\\\\\" + string[i];\n  }\n  return result;\n}\nfunction escapeHash(string) {\n  string = \"\" + string;\n  let result = \"\";\n  for (let i = 0; i < string.length; i++) {\n    const code = string.charCodeAt(i);\n    if (code === 0)\n      throw new InvalidCharacterError(\"Invalid character: the input contains U+0000.\");\n    if (code >= 128 || code === 45 || code === 95 || between(code, 48, 57) || between(code, 65, 90) || between(code, 97, 122))\n      result += string[i];\n    else\n      result += \"\\\\\" + code.toString(16) + \" \";\n  }\n  return result;\n}\nfunction escapeString(string) {\n  string = \"\" + string;\n  let result = \"\";\n  for (let i = 0; i < string.length; i++) {\n    const code = string.charCodeAt(i);\n    if (code === 0)\n      throw new InvalidCharacterError(\"Invalid character: the input contains U+0000.\");\n    if (between(code, 1, 31) || code === 127)\n      result += \"\\\\\" + code.toString(16) + \" \";\n    else if (code === 34 || code === 92)\n      result += \"\\\\\" + string[i];\n    else\n      result += string[i];\n  }\n  return result;\n}\n\n// packages/playwright-core/src/utils/isomorphic/cssParser.ts\nvar InvalidSelectorError = class extends Error {\n};\nfunction parseCSS(selector, customNames) {\n  let tokens;\n  try {\n    tokens = tokenize(selector);\n    if (!(tokens[tokens.length - 1] instanceof EOFToken))\n      tokens.push(new EOFToken());\n  } catch (e) {\n    const newMessage = e.message + ` while parsing selector \"${selector}\"`;\n    const index = (e.stack || \"\").indexOf(e.message);\n    if (index !== -1)\n      e.stack = e.stack.substring(0, index) + newMessage + e.stack.substring(index + e.message.length);\n    e.message = newMessage;\n    throw e;\n  }\n  const unsupportedToken = tokens.find((token) => {\n    return token instanceof AtKeywordToken || token instanceof BadStringToken || token instanceof BadURLToken || token instanceof ColumnToken || token instanceof CDOToken || token instanceof CDCToken || token instanceof SemicolonToken || token instanceof OpenCurlyToken || token instanceof CloseCurlyToken || token instanceof URLToken || token instanceof PercentageToken;\n  });\n  if (unsupportedToken)\n    throw new InvalidSelectorError(`Unsupported token \"${unsupportedToken.toSource()}\" while parsing selector \"${selector}\"`);\n  let pos = 0;\n  const names = /* @__PURE__ */ new Set();\n  function unexpected() {\n    return new InvalidSelectorError(`Unexpected token \"${tokens[pos].toSource()}\" while parsing selector \"${selector}\"`);\n  }\n  function skipWhitespace() {\n    while (tokens[pos] instanceof WhitespaceToken)\n      pos++;\n  }\n  function isIdent(p = pos) {\n    return tokens[p] instanceof IdentToken;\n  }\n  function isString(p = pos) {\n    return tokens[p] instanceof StringToken;\n  }\n  function isNumber(p = pos) {\n    return tokens[p] instanceof NumberToken;\n  }\n  function isComma(p = pos) {\n    return tokens[p] instanceof CommaToken;\n  }\n  function isCloseParen(p = pos) {\n    return tokens[p] instanceof CloseParenToken;\n  }\n  function isStar(p = pos) {\n    return tokens[p] instanceof DelimToken && tokens[p].value === \"*\";\n  }\n  function isEOF(p = pos) {\n    return tokens[p] instanceof EOFToken;\n  }\n  function isClauseCombinator(p = pos) {\n    return tokens[p] instanceof DelimToken && [\">\", \"+\", \"~\"].includes(tokens[p].value);\n  }\n  function isSelectorClauseEnd(p = pos) {\n    return isComma(p) || isCloseParen(p) || isEOF(p) || isClauseCombinator(p) || tokens[p] instanceof WhitespaceToken;\n  }\n  function consumeFunctionArguments() {\n    const result2 = [consumeArgument()];\n    while (true) {\n      skipWhitespace();\n      if (!isComma())\n        break;\n      pos++;\n      result2.push(consumeArgument());\n    }\n    return result2;\n  }\n  function consumeArgument() {\n    skipWhitespace();\n    if (isNumber())\n      return tokens[pos++].value;\n    if (isString())\n      return tokens[pos++].value;\n    return consumeComplexSelector();\n  }\n  function consumeComplexSelector() {\n    const result2 = { simples: [] };\n    skipWhitespace();\n    if (isClauseCombinator()) {\n      result2.simples.push({ selector: { functions: [{ name: \"scope\", args: [] }] }, combinator: \"\" });\n    } else {\n      result2.simples.push({ selector: consumeSimpleSelector(), combinator: \"\" });\n    }\n    while (true) {\n      skipWhitespace();\n      if (isClauseCombinator()) {\n        result2.simples[result2.simples.length - 1].combinator = tokens[pos++].value;\n        skipWhitespace();\n      } else if (isSelectorClauseEnd()) {\n        break;\n      }\n      result2.simples.push({ combinator: \"\", selector: consumeSimpleSelector() });\n    }\n    return result2;\n  }\n  function consumeSimpleSelector() {\n    let rawCSSString = \"\";\n    const functions = [];\n    while (!isSelectorClauseEnd()) {\n      if (isIdent() || isStar()) {\n        rawCSSString += tokens[pos++].toSource();\n      } else if (tokens[pos] instanceof HashToken) {\n        rawCSSString += tokens[pos++].toSource();\n      } else if (tokens[pos] instanceof DelimToken && tokens[pos].value === \".\") {\n        pos++;\n        if (isIdent())\n          rawCSSString += \".\" + tokens[pos++].toSource();\n        else\n          throw unexpected();\n      } else if (tokens[pos] instanceof ColonToken) {\n        pos++;\n        if (isIdent()) {\n          if (!customNames.has(tokens[pos].value.toLowerCase())) {\n            rawCSSString += \":\" + tokens[pos++].toSource();\n          } else {\n            const name = tokens[pos++].value.toLowerCase();\n            functions.push({ name, args: [] });\n            names.add(name);\n          }\n        } else if (tokens[pos] instanceof FunctionToken) {\n          const name = tokens[pos++].value.toLowerCase();\n          if (!customNames.has(name)) {\n            rawCSSString += `:${name}(${consumeBuiltinFunctionArguments()})`;\n          } else {\n            functions.push({ name, args: consumeFunctionArguments() });\n            names.add(name);\n          }\n          skipWhitespace();\n          if (!isCloseParen())\n            throw unexpected();\n          pos++;\n        } else {\n          throw unexpected();\n        }\n      } else if (tokens[pos] instanceof OpenSquareToken) {\n        rawCSSString += \"[\";\n        pos++;\n        while (!(tokens[pos] instanceof CloseSquareToken) && !isEOF())\n          rawCSSString += tokens[pos++].toSource();\n        if (!(tokens[pos] instanceof CloseSquareToken))\n          throw unexpected();\n        rawCSSString += \"]\";\n        pos++;\n      } else {\n        throw unexpected();\n      }\n    }\n    if (!rawCSSString && !functions.length)\n      throw unexpected();\n    return { css: rawCSSString || void 0, functions };\n  }\n  function consumeBuiltinFunctionArguments() {\n    let s = \"\";\n    while (!isCloseParen() && !isEOF())\n      s += tokens[pos++].toSource();\n    return s;\n  }\n  const result = consumeFunctionArguments();\n  if (!isEOF())\n    throw new InvalidSelectorError(`Error while parsing selector \"${selector}\"`);\n  if (result.some((arg) => typeof arg !== \"object\" || !(\"simples\" in arg)))\n    throw new InvalidSelectorError(`Error while parsing selector \"${selector}\"`);\n  return { selector: result, names: Array.from(names) };\n}\n\n// packages/playwright-core/src/utils/isomorphic/selectorParser.ts\nvar kNestedSelectorNames = /* @__PURE__ */ new Set([\"internal:has\", \"left-of\", \"right-of\", \"above\", \"below\", \"near\"]);\nvar kNestedSelectorNamesWithDistance = /* @__PURE__ */ new Set([\"left-of\", \"right-of\", \"above\", \"below\", \"near\"]);\nvar customCSSNames = /* @__PURE__ */ new Set([\"not\", \"is\", \"where\", \"has\", \"scope\", \"light\", \"visible\", \"text\", \"text-matches\", \"text-is\", \"has-text\", \"above\", \"below\", \"right-of\", \"left-of\", \"near\", \"nth-match\"]);\nfunction parseSelector(selector) {\n  const result = parseSelectorString(selector);\n  const parts = result.parts.map((part) => {\n    if (part.name === \"css\" || part.name === \"css:light\") {\n      if (part.name === \"css:light\")\n        part.body = \":light(\" + part.body + \")\";\n      const parsedCSS = parseCSS(part.body, customCSSNames);\n      return {\n        name: \"css\",\n        body: parsedCSS.selector,\n        source: part.body\n      };\n    }\n    if (kNestedSelectorNames.has(part.name)) {\n      let innerSelector;\n      let distance;\n      try {\n        const unescaped = JSON.parse(\"[\" + part.body + \"]\");\n        if (!Array.isArray(unescaped) || unescaped.length < 1 || unescaped.length > 2 || typeof unescaped[0] !== \"string\")\n          throw new InvalidSelectorError(`Malformed selector: ${part.name}=` + part.body);\n        innerSelector = unescaped[0];\n        if (unescaped.length === 2) {\n          if (typeof unescaped[1] !== \"number\" || !kNestedSelectorNamesWithDistance.has(part.name))\n            throw new InvalidSelectorError(`Malformed selector: ${part.name}=` + part.body);\n          distance = unescaped[1];\n        }\n      } catch (e) {\n        throw new InvalidSelectorError(`Malformed selector: ${part.name}=` + part.body);\n      }\n      const result2 = { name: part.name, source: part.body, body: { parsed: parseSelector(innerSelector), distance } };\n      if (result2.body.parsed.parts.some((part2) => part2.name === \"internal:control\" && part2.body === \"enter-frame\"))\n        throw new InvalidSelectorError(`Frames are not allowed inside \"${part.name}\" selectors`);\n      return result2;\n    }\n    return { ...part, source: part.body };\n  });\n  if (kNestedSelectorNames.has(parts[0].name))\n    throw new InvalidSelectorError(`\"${parts[0].name}\" selector cannot be first`);\n  return {\n    capture: result.capture,\n    parts\n  };\n}\nfunction stringifySelector(selector) {\n  if (typeof selector === \"string\")\n    return selector;\n  return selector.parts.map((p, i) => {\n    const prefix = p.name === \"css\" ? \"\" : p.name + \"=\";\n    return `${i === selector.capture ? \"*\" : \"\"}${prefix}${p.source}`;\n  }).join(\" >> \");\n}\nfunction parseSelectorString(selector) {\n  let index = 0;\n  let quote;\n  let start = 0;\n  const result = { parts: [] };\n  const append = () => {\n    const part = selector.substring(start, index).trim();\n    const eqIndex = part.indexOf(\"=\");\n    let name;\n    let body;\n    if (eqIndex !== -1 && part.substring(0, eqIndex).trim().match(/^[a-zA-Z_0-9-+:*]+$/)) {\n      name = part.substring(0, eqIndex).trim();\n      body = part.substring(eqIndex + 1);\n    } else if (part.length > 1 && part[0] === '\"' && part[part.length - 1] === '\"') {\n      name = \"text\";\n      body = part;\n    } else if (part.length > 1 && part[0] === \"'\" && part[part.length - 1] === \"'\") {\n      name = \"text\";\n      body = part;\n    } else if (/^\\(*\\/\\//.test(part) || part.startsWith(\"..\")) {\n      name = \"xpath\";\n      body = part;\n    } else {\n      name = \"css\";\n      body = part;\n    }\n    let capture = false;\n    if (name[0] === \"*\") {\n      capture = true;\n      name = name.substring(1);\n    }\n    result.parts.push({ name, body });\n    if (capture) {\n      if (result.capture !== void 0)\n        throw new InvalidSelectorError(`Only one of the selectors can capture using * modifier`);\n      result.capture = result.parts.length - 1;\n    }\n  };\n  if (!selector.includes(\">>\")) {\n    index = selector.length;\n    append();\n    return result;\n  }\n  const shouldIgnoreTextSelectorQuote = () => {\n    const prefix = selector.substring(start, index);\n    const match = prefix.match(/^\\s*text\\s*=(.*)$/);\n    return !!match && !!match[1];\n  };\n  while (index < selector.length) {\n    const c = selector[index];\n    if (c === \"\\\\\" && index + 1 < selector.length) {\n      index += 2;\n    } else if (c === quote) {\n      quote = void 0;\n      index++;\n    } else if (!quote && (c === '\"' || c === \"'\" || c === \"`\") && !shouldIgnoreTextSelectorQuote()) {\n      quote = c;\n      index++;\n    } else if (!quote && c === \">\" && selector[index + 1] === \">\") {\n      append();\n      index += 2;\n      start = index;\n    } else {\n      index++;\n    }\n  }\n  append();\n  return result;\n}\nfunction parseAttributeSelector(selector, allowUnquotedStrings) {\n  let wp = 0;\n  let EOL = selector.length === 0;\n  const next = () => selector[wp] || \"\";\n  const eat1 = () => {\n    const result2 = next();\n    ++wp;\n    EOL = wp >= selector.length;\n    return result2;\n  };\n  const syntaxError = (stage) => {\n    if (EOL)\n      throw new InvalidSelectorError(`Unexpected end of selector while parsing selector \\`${selector}\\``);\n    throw new InvalidSelectorError(`Error while parsing selector \\`${selector}\\` - unexpected symbol \"${next()}\" at position ${wp}` + (stage ? \" during \" + stage : \"\"));\n  };\n  function skipSpaces() {\n    while (!EOL && /\\s/.test(next()))\n      eat1();\n  }\n  function isCSSNameChar(char) {\n    return char >= \"\\x80\" || char >= \"0\" && char <= \"9\" || char >= \"A\" && char <= \"Z\" || char >= \"a\" && char <= \"z\" || char >= \"0\" && char <= \"9\" || char === \"_\" || char === \"-\";\n  }\n  function readIdentifier() {\n    let result2 = \"\";\n    skipSpaces();\n    while (!EOL && isCSSNameChar(next()))\n      result2 += eat1();\n    return result2;\n  }\n  function readQuotedString(quote) {\n    let result2 = eat1();\n    if (result2 !== quote)\n      syntaxError(\"parsing quoted string\");\n    while (!EOL && next() !== quote) {\n      if (next() === \"\\\\\")\n        eat1();\n      result2 += eat1();\n    }\n    if (next() !== quote)\n      syntaxError(\"parsing quoted string\");\n    result2 += eat1();\n    return result2;\n  }\n  function readRegularExpression() {\n    if (eat1() !== \"/\")\n      syntaxError(\"parsing regular expression\");\n    let source = \"\";\n    let inClass = false;\n    while (!EOL) {\n      if (next() === \"\\\\\") {\n        source += eat1();\n        if (EOL)\n          syntaxError(\"parsing regular expressiion\");\n      } else if (inClass && next() === \"]\") {\n        inClass = false;\n      } else if (!inClass && next() === \"[\") {\n        inClass = true;\n      } else if (!inClass && next() === \"/\") {\n        break;\n      }\n      source += eat1();\n    }\n    if (eat1() !== \"/\")\n      syntaxError(\"parsing regular expression\");\n    let flags = \"\";\n    while (!EOL && next().match(/[dgimsuy]/))\n      flags += eat1();\n    try {\n      return new RegExp(source, flags);\n    } catch (e) {\n      throw new InvalidSelectorError(`Error while parsing selector \\`${selector}\\`: ${e.message}`);\n    }\n  }\n  function readAttributeToken() {\n    let token = \"\";\n    skipSpaces();\n    if (next() === `'` || next() === `\"`)\n      token = readQuotedString(next()).slice(1, -1);\n    else\n      token = readIdentifier();\n    if (!token)\n      syntaxError(\"parsing property path\");\n    return token;\n  }\n  function readOperator() {\n    skipSpaces();\n    let op = \"\";\n    if (!EOL)\n      op += eat1();\n    if (!EOL && op !== \"=\")\n      op += eat1();\n    if (![\"=\", \"*=\", \"^=\", \"$=\", \"|=\", \"~=\"].includes(op))\n      syntaxError(\"parsing operator\");\n    return op;\n  }\n  function readAttribute() {\n    eat1();\n    const jsonPath = [];\n    jsonPath.push(readAttributeToken());\n    skipSpaces();\n    while (next() === \".\") {\n      eat1();\n      jsonPath.push(readAttributeToken());\n      skipSpaces();\n    }\n    if (next() === \"]\") {\n      eat1();\n      return { name: jsonPath.join(\".\"), jsonPath, op: \"<truthy>\", value: null, caseSensitive: false };\n    }\n    const operator = readOperator();\n    let value = void 0;\n    let caseSensitive = true;\n    skipSpaces();\n    if (next() === \"/\") {\n      if (operator !== \"=\")\n        throw new InvalidSelectorError(`Error while parsing selector \\`${selector}\\` - cannot use ${operator} in attribute with regular expression`);\n      value = readRegularExpression();\n    } else if (next() === `'` || next() === `\"`) {\n      value = readQuotedString(next()).slice(1, -1);\n      skipSpaces();\n      if (next() === \"i\" || next() === \"I\") {\n        caseSensitive = false;\n        eat1();\n      } else if (next() === \"s\" || next() === \"S\") {\n        caseSensitive = true;\n        eat1();\n      }\n    } else {\n      value = \"\";\n      while (!EOL && (isCSSNameChar(next()) || next() === \"+\" || next() === \".\"))\n        value += eat1();\n      if (value === \"true\") {\n        value = true;\n      } else if (value === \"false\") {\n        value = false;\n      } else {\n        if (!allowUnquotedStrings) {\n          value = +value;\n          if (Number.isNaN(value))\n            syntaxError(\"parsing attribute value\");\n        }\n      }\n    }\n    skipSpaces();\n    if (next() !== \"]\")\n      syntaxError(\"parsing attribute value\");\n    eat1();\n    if (operator !== \"=\" && typeof value !== \"string\")\n      throw new InvalidSelectorError(`Error while parsing selector \\`${selector}\\` - cannot use ${operator} in attribute with non-string matching value - ${value}`);\n    return { name: jsonPath.join(\".\"), jsonPath, op: operator, value, caseSensitive };\n  }\n  const result = {\n    name: \"\",\n    attributes: []\n  };\n  result.name = readIdentifier();\n  skipSpaces();\n  while (next() === \"[\") {\n    result.attributes.push(readAttribute());\n    skipSpaces();\n  }\n  if (!EOL)\n    syntaxError(void 0);\n  if (!result.name && !result.attributes.length)\n    throw new InvalidSelectorError(`Error while parsing selector \\`${selector}\\` - selector cannot be empty`);\n  return result;\n}\n\n// packages/playwright-core/src/utils/isomorphic/locatorGenerators.ts\nfunction asLocator(lang, selector, isFrameLocator = false, playSafe = false) {\n  if (playSafe) {\n    try {\n      return innerAsLocator(generators[lang], parseSelector(selector), isFrameLocator);\n    } catch (e) {\n      return selector;\n    }\n  } else {\n    return innerAsLocator(generators[lang], parseSelector(selector), isFrameLocator);\n  }\n}\nfunction innerAsLocator(factory, parsed, isFrameLocator = false) {\n  const parts = [...parsed.parts];\n  for (let index = 0; index < parts.length - 1; index++) {\n    if (parts[index].name === \"nth\" && parts[index + 1].name === \"internal:control\" && parts[index + 1].body === \"enter-frame\") {\n      const [nth] = parts.splice(index, 1);\n      parts.splice(index + 1, 0, nth);\n    }\n  }\n  const tokens = [];\n  let nextBase = isFrameLocator ? \"frame-locator\" : \"page\";\n  for (let index = 0; index < parts.length; index++) {\n    const part = parts[index];\n    const base = nextBase;\n    nextBase = \"locator\";\n    if (part.name === \"nth\") {\n      if (part.body === \"0\")\n        tokens.push(factory.generateLocator(base, \"first\", \"\"));\n      else if (part.body === \"-1\")\n        tokens.push(factory.generateLocator(base, \"last\", \"\"));\n      else\n        tokens.push(factory.generateLocator(base, \"nth\", part.body));\n      continue;\n    }\n    if (part.name === \"internal:text\") {\n      const { exact, text } = detectExact(part.body);\n      tokens.push(factory.generateLocator(base, \"text\", text, { exact }));\n      continue;\n    }\n    if (part.name === \"internal:has-text\") {\n      const { exact, text } = detectExact(part.body);\n      if (!exact) {\n        tokens.push(factory.generateLocator(base, \"has-text\", text, { exact }));\n        continue;\n      }\n    }\n    if (part.name === \"internal:has\") {\n      const inner = innerAsLocator(factory, part.body.parsed);\n      tokens.push(factory.generateLocator(base, \"has\", inner));\n      continue;\n    }\n    if (part.name === \"internal:label\") {\n      const { exact, text } = detectExact(part.body);\n      tokens.push(factory.generateLocator(base, \"label\", text, { exact }));\n      continue;\n    }\n    if (part.name === \"internal:role\") {\n      const attrSelector = parseAttributeSelector(part.body, true);\n      const options = { attrs: [] };\n      for (const attr of attrSelector.attributes) {\n        if (attr.name === \"name\") {\n          options.exact = attr.caseSensitive;\n          options.name = attr.value;\n        } else {\n          if (attr.name === \"level\" && typeof attr.value === \"string\")\n            attr.value = +attr.value;\n          options.attrs.push({ name: attr.name === \"include-hidden\" ? \"includeHidden\" : attr.name, value: attr.value });\n        }\n      }\n      tokens.push(factory.generateLocator(base, \"role\", attrSelector.name, options));\n      continue;\n    }\n    if (part.name === \"internal:testid\") {\n      const attrSelector = parseAttributeSelector(part.body, true);\n      const { value } = attrSelector.attributes[0];\n      tokens.push(factory.generateLocator(base, \"test-id\", value));\n      continue;\n    }\n    if (part.name === \"internal:attr\") {\n      const attrSelector = parseAttributeSelector(part.body, true);\n      const { name, value, caseSensitive } = attrSelector.attributes[0];\n      const text = value;\n      const exact = !!caseSensitive;\n      if (name === \"placeholder\") {\n        tokens.push(factory.generateLocator(base, \"placeholder\", text, { exact }));\n        continue;\n      }\n      if (name === \"alt\") {\n        tokens.push(factory.generateLocator(base, \"alt\", text, { exact }));\n        continue;\n      }\n      if (name === \"title\") {\n        tokens.push(factory.generateLocator(base, \"title\", text, { exact }));\n        continue;\n      }\n    }\n    let locatorType = \"default\";\n    const nextPart = parts[index + 1];\n    if (nextPart && nextPart.name === \"internal:control\" && nextPart.body === \"enter-frame\") {\n      locatorType = \"frame\";\n      nextBase = \"frame-locator\";\n      index++;\n    }\n    const p = { parts: [part] };\n    tokens.push(factory.generateLocator(base, locatorType, stringifySelector(p)));\n  }\n  return tokens.join(\".\");\n}\nfunction detectExact(text) {\n  let exact = false;\n  const match = text.match(/^\\/(.*)\\/([igm]*)$/);\n  if (match)\n    return { text: new RegExp(match[1], match[2]) };\n  if (text.endsWith('\"')) {\n    text = JSON.parse(text);\n    exact = true;\n  } else if (text.endsWith('\"s')) {\n    text = JSON.parse(text.substring(0, text.length - 1));\n    exact = true;\n  } else if (text.endsWith('\"i')) {\n    text = JSON.parse(text.substring(0, text.length - 1));\n    exact = false;\n  }\n  return { exact, text };\n}\nvar JavaScriptLocatorFactory = class {\n  generateLocator(base, kind, body, options = {}) {\n    switch (kind) {\n      case \"default\":\n        return `locator(${this.quote(body)})`;\n      case \"frame\":\n        return `frameLocator(${this.quote(body)})`;\n      case \"nth\":\n        return `nth(${body})`;\n      case \"first\":\n        return `first()`;\n      case \"last\":\n        return `last()`;\n      case \"role\":\n        const attrs = [];\n        if (isRegExp(options.name)) {\n          attrs.push(`name: ${options.name}`);\n        } else if (typeof options.name === \"string\") {\n          attrs.push(`name: ${this.quote(options.name)}`);\n          if (options.exact)\n            attrs.push(`exact: true`);\n        }\n        for (const { name, value } of options.attrs)\n          attrs.push(`${name}: ${typeof value === \"string\" ? this.quote(value) : value}`);\n        const attrString = attrs.length ? `, { ${attrs.join(\", \")} }` : \"\";\n        return `getByRole(${this.quote(body)}${attrString})`;\n      case \"has-text\":\n        return `filter({ hasText: ${this.toHasText(body)} })`;\n      case \"has\":\n        return `filter({ has: ${body} })`;\n      case \"test-id\":\n        return `getByTestId(${this.quote(body)})`;\n      case \"text\":\n        return this.toCallWithExact(\"getByText\", body, !!options.exact);\n      case \"alt\":\n        return this.toCallWithExact(\"getByAltText\", body, !!options.exact);\n      case \"placeholder\":\n        return this.toCallWithExact(\"getByPlaceholder\", body, !!options.exact);\n      case \"label\":\n        return this.toCallWithExact(\"getByLabel\", body, !!options.exact);\n      case \"title\":\n        return this.toCallWithExact(\"getByTitle\", body, !!options.exact);\n      default:\n        throw new Error(\"Unknown selector kind \" + kind);\n    }\n  }\n  toCallWithExact(method, body, exact) {\n    if (isRegExp(body))\n      return `${method}(${body})`;\n    return exact ? `${method}(${this.quote(body)}, { exact: true })` : `${method}(${this.quote(body)})`;\n  }\n  toHasText(body) {\n    if (isRegExp(body))\n      return String(body);\n    return this.quote(body);\n  }\n  quote(text) {\n    return escapeWithQuotes(text, \"'\");\n  }\n};\nvar PythonLocatorFactory = class {\n  generateLocator(base, kind, body, options = {}) {\n    switch (kind) {\n      case \"default\":\n        return `locator(${this.quote(body)})`;\n      case \"frame\":\n        return `frame_locator(${this.quote(body)})`;\n      case \"nth\":\n        return `nth(${body})`;\n      case \"first\":\n        return `first`;\n      case \"last\":\n        return `last`;\n      case \"role\":\n        const attrs = [];\n        if (isRegExp(options.name)) {\n          attrs.push(`name=${this.regexToString(options.name)}`);\n        } else if (typeof options.name === \"string\") {\n          attrs.push(`name=${this.quote(options.name)}`);\n          if (options.exact)\n            attrs.push(`exact=True`);\n        }\n        for (const { name, value } of options.attrs) {\n          let valueString = typeof value === \"string\" ? this.quote(value) : value;\n          if (typeof value === \"boolean\")\n            valueString = value ? \"True\" : \"False\";\n          attrs.push(`${toSnakeCase(name)}=${valueString}`);\n        }\n        const attrString = attrs.length ? `, ${attrs.join(\", \")}` : \"\";\n        return `get_by_role(${this.quote(body)}${attrString})`;\n      case \"has-text\":\n        return `filter(has_text=${this.toHasText(body)})`;\n      case \"has\":\n        return `filter(has=${body})`;\n      case \"test-id\":\n        return `get_by_test_id(${this.quote(body)})`;\n      case \"text\":\n        return this.toCallWithExact(\"get_by_text\", body, !!options.exact);\n      case \"alt\":\n        return this.toCallWithExact(\"get_by_alt_text\", body, !!options.exact);\n      case \"placeholder\":\n        return this.toCallWithExact(\"get_by_placeholder\", body, !!options.exact);\n      case \"label\":\n        return this.toCallWithExact(\"get_by_label\", body, !!options.exact);\n      case \"title\":\n        return this.toCallWithExact(\"get_by_title\", body, !!options.exact);\n      default:\n        throw new Error(\"Unknown selector kind \" + kind);\n    }\n  }\n  regexToString(body) {\n    const suffix = body.flags.includes(\"i\") ? \", re.IGNORECASE\" : \"\";\n    return `re.compile(r\"${body.source.replace(/\\\\\\//, \"/\").replace(/\"/g, '\\\\\"')}\"${suffix})`;\n  }\n  toCallWithExact(method, body, exact) {\n    if (isRegExp(body))\n      return `${method}(${this.regexToString(body)})`;\n    if (exact)\n      return `${method}(${this.quote(body)}, exact=True)`;\n    return `${method}(${this.quote(body)})`;\n  }\n  toHasText(body) {\n    if (isRegExp(body))\n      return this.regexToString(body);\n    return `${this.quote(body)}`;\n  }\n  quote(text) {\n    return escapeWithQuotes(text, '\"');\n  }\n};\nvar JavaLocatorFactory = class {\n  generateLocator(base, kind, body, options = {}) {\n    let clazz;\n    switch (base) {\n      case \"page\":\n        clazz = \"Page\";\n        break;\n      case \"frame-locator\":\n        clazz = \"FrameLocator\";\n        break;\n      case \"locator\":\n        clazz = \"Locator\";\n        break;\n    }\n    switch (kind) {\n      case \"default\":\n        return `locator(${this.quote(body)})`;\n      case \"frame\":\n        return `frameLocator(${this.quote(body)})`;\n      case \"nth\":\n        return `nth(${body})`;\n      case \"first\":\n        return `first()`;\n      case \"last\":\n        return `last()`;\n      case \"role\":\n        const attrs = [];\n        if (isRegExp(options.name)) {\n          attrs.push(`.setName(${this.regexToString(options.name)})`);\n        } else if (typeof options.name === \"string\") {\n          attrs.push(`.setName(${this.quote(options.name)})`);\n          if (options.exact)\n            attrs.push(`.setExact(true)`);\n        }\n        for (const { name, value } of options.attrs)\n          attrs.push(`.set${toTitleCase(name)}(${typeof value === \"string\" ? this.quote(value) : value})`);\n        const attrString = attrs.length ? `, new ${clazz}.GetByRoleOptions()${attrs.join(\"\")}` : \"\";\n        return `getByRole(AriaRole.${toSnakeCase(body).toUpperCase()}${attrString})`;\n      case \"has-text\":\n        return `filter(new ${clazz}.FilterOptions().setHasText(${this.toHasText(body)}))`;\n      case \"has\":\n        return `filter(new ${clazz}.FilterOptions().setHas(${body}))`;\n      case \"test-id\":\n        return `getByTestId(${this.quote(body)})`;\n      case \"text\":\n        return this.toCallWithExact(clazz, \"getByText\", body, !!options.exact);\n      case \"alt\":\n        return this.toCallWithExact(clazz, \"getByAltText\", body, !!options.exact);\n      case \"placeholder\":\n        return this.toCallWithExact(clazz, \"getByPlaceholder\", body, !!options.exact);\n      case \"label\":\n        return this.toCallWithExact(clazz, \"getByLabel\", body, !!options.exact);\n      case \"title\":\n        return this.toCallWithExact(clazz, \"getByTitle\", body, !!options.exact);\n      default:\n        throw new Error(\"Unknown selector kind \" + kind);\n    }\n  }\n  regexToString(body) {\n    const suffix = body.flags.includes(\"i\") ? \", Pattern.CASE_INSENSITIVE\" : \"\";\n    return `Pattern.compile(${this.quote(body.source)}${suffix})`;\n  }\n  toCallWithExact(clazz, method, body, exact) {\n    if (isRegExp(body))\n      return `${method}(${this.regexToString(body)})`;\n    if (exact)\n      return `${method}(${this.quote(body)}, new ${clazz}.${toTitleCase(method)}Options().setExact(true))`;\n    return `${method}(${this.quote(body)})`;\n  }\n  toHasText(body) {\n    if (isRegExp(body))\n      return this.regexToString(body);\n    return this.quote(body);\n  }\n  quote(text) {\n    return escapeWithQuotes(text, '\"');\n  }\n};\nvar CSharpLocatorFactory = class {\n  generateLocator(base, kind, body, options = {}) {\n    switch (kind) {\n      case \"default\":\n        return `Locator(${this.quote(body)})`;\n      case \"frame\":\n        return `FrameLocator(${this.quote(body)})`;\n      case \"nth\":\n        return `Nth(${body})`;\n      case \"first\":\n        return `First`;\n      case \"last\":\n        return `Last`;\n      case \"role\":\n        const attrs = [];\n        if (isRegExp(options.name)) {\n          attrs.push(`NameRegex = ${this.regexToString(options.name)}`);\n        } else if (typeof options.name === \"string\") {\n          attrs.push(`Name = ${this.quote(options.name)}`);\n          if (options.exact)\n            attrs.push(`Exact = true`);\n        }\n        for (const { name, value } of options.attrs)\n          attrs.push(`${toTitleCase(name)} = ${typeof value === \"string\" ? this.quote(value) : value}`);\n        const attrString = attrs.length ? `, new() { ${attrs.join(\", \")} }` : \"\";\n        return `GetByRole(AriaRole.${toTitleCase(body)}${attrString})`;\n      case \"has-text\":\n        return `Filter(new() { ${this.toHasText(body)} })`;\n      case \"has\":\n        return `Filter(new() { Has = ${body} })`;\n      case \"test-id\":\n        return `GetByTestId(${this.quote(body)})`;\n      case \"text\":\n        return this.toCallWithExact(\"GetByText\", body, !!options.exact);\n      case \"alt\":\n        return this.toCallWithExact(\"GetByAltText\", body, !!options.exact);\n      case \"placeholder\":\n        return this.toCallWithExact(\"GetByPlaceholder\", body, !!options.exact);\n      case \"label\":\n        return this.toCallWithExact(\"GetByLabel\", body, !!options.exact);\n      case \"title\":\n        return this.toCallWithExact(\"GetByTitle\", body, !!options.exact);\n      default:\n        throw new Error(\"Unknown selector kind \" + kind);\n    }\n  }\n  regexToString(body) {\n    const suffix = body.flags.includes(\"i\") ? \", RegexOptions.IgnoreCase\" : \"\";\n    return `new Regex(${this.quote(body.source)}${suffix})`;\n  }\n  toCallWithExact(method, body, exact) {\n    if (isRegExp(body))\n      return `${method}(${this.regexToString(body)})`;\n    if (exact)\n      return `${method}(${this.quote(body)}, new() { Exact = true })`;\n    return `${method}(${this.quote(body)})`;\n  }\n  toHasText(body) {\n    if (isRegExp(body))\n      return `HasTextRegex = ${this.regexToString(body)}`;\n    return `HasText = ${this.quote(body)}`;\n  }\n  quote(text) {\n    return escapeWithQuotes(text, '\"');\n  }\n};\nvar generators = {\n  javascript: new JavaScriptLocatorFactory(),\n  python: new PythonLocatorFactory(),\n  java: new JavaLocatorFactory(),\n  csharp: new CSharpLocatorFactory()\n};\nfunction isRegExp(obj) {\n  return obj instanceof RegExp;\n}\n\n// packages/playwright-core/src/server/injected/highlight.ts\nvar Highlight = class {\n  constructor(injectedScript) {\n    this._highlightEntries = [];\n    this._language = \"javascript\";\n    this._injectedScript = injectedScript;\n    const document = injectedScript.document;\n    this._isUnderTest = injectedScript.isUnderTest;\n    this._glassPaneElement = document.createElement(\"x-pw-glass\");\n    this._glassPaneElement.style.position = \"fixed\";\n    this._glassPaneElement.style.top = \"0\";\n    this._glassPaneElement.style.right = \"0\";\n    this._glassPaneElement.style.bottom = \"0\";\n    this._glassPaneElement.style.left = \"0\";\n    this._glassPaneElement.style.zIndex = \"2147483647\";\n    this._glassPaneElement.style.pointerEvents = \"none\";\n    this._glassPaneElement.style.display = \"flex\";\n    this._actionPointElement = document.createElement(\"x-pw-action-point\");\n    this._actionPointElement.setAttribute(\"hidden\", \"true\");\n    this._glassPaneShadow = this._glassPaneElement.attachShadow({ mode: this._isUnderTest ? \"open\" : \"closed\" });\n    this._glassPaneShadow.appendChild(this._actionPointElement);\n    const styleElement = document.createElement(\"style\");\n    styleElement.textContent = `\n        x-pw-tooltip {\n          align-items: center;\n          backdrop-filter: blur(5px);\n          background-color: rgba(0, 0, 0, 0.7);\n          border-radius: 2px;\n          box-shadow: rgba(0, 0, 0, 0.1) 0px 3.6px 3.7px,\n                      rgba(0, 0, 0, 0.15) 0px 12.1px 12.3px,\n                      rgba(0, 0, 0, 0.1) 0px -2px 4px,\n                      rgba(0, 0, 0, 0.15) 0px -12.1px 24px,\n                      rgba(0, 0, 0, 0.25) 0px 54px 55px;\n          color: rgb(204, 204, 204);\n          display: none;\n          font-family: 'Dank Mono', 'Operator Mono', Inconsolata, 'Fira Mono',\n                      'SF Mono', Monaco, 'Droid Sans Mono', 'Source Code Pro', monospace;\n          font-size: 12.8px;\n          font-weight: normal;\n          left: 0;\n          line-height: 1.5;\n          max-width: 600px;\n          padding: 3.2px 5.12px 3.2px;\n          position: absolute;\n          top: 0;\n        }\n        x-pw-action-point {\n          position: absolute;\n          width: 20px;\n          height: 20px;\n          background: red;\n          border-radius: 10px;\n          pointer-events: none;\n          margin: -10px 0 0 -10px;\n          z-index: 2;\n        }\n        *[hidden] {\n          display: none !important;\n        }\n    `;\n    this._glassPaneShadow.appendChild(styleElement);\n  }\n  install() {\n    this._injectedScript.document.documentElement.appendChild(this._glassPaneElement);\n  }\n  setLanguage(language) {\n    this._language = language;\n  }\n  runHighlightOnRaf(selector) {\n    if (this._rafRequest)\n      cancelAnimationFrame(this._rafRequest);\n    this.updateHighlight(this._injectedScript.querySelectorAll(selector, this._injectedScript.document.documentElement), stringifySelector(selector), false);\n    this._rafRequest = requestAnimationFrame(() => this.runHighlightOnRaf(selector));\n  }\n  uninstall() {\n    if (this._rafRequest)\n      cancelAnimationFrame(this._rafRequest);\n    this._glassPaneElement.remove();\n  }\n  isInstalled() {\n    return this._glassPaneElement.parentElement === this._injectedScript.document.documentElement && !this._glassPaneElement.nextElementSibling;\n  }\n  showActionPoint(x, y) {\n    this._actionPointElement.style.top = y + \"px\";\n    this._actionPointElement.style.left = x + \"px\";\n    this._actionPointElement.hidden = false;\n    if (this._isUnderTest)\n      console.error(\"Action point for test: \" + JSON.stringify({ x, y }));\n  }\n  hideActionPoint() {\n    this._actionPointElement.hidden = true;\n  }\n  clearHighlight() {\n    var _a, _b;\n    for (const entry of this._highlightEntries) {\n      (_a = entry.highlightElement) == null ? void 0 : _a.remove();\n      (_b = entry.tooltipElement) == null ? void 0 : _b.remove();\n    }\n    this._highlightEntries = [];\n  }\n  updateHighlight(elements, selector, isRecording) {\n    let color;\n    if (isRecording)\n      color = \"#dc6f6f7f\";\n    else\n      color = elements.length > 1 ? \"#f6b26b7f\" : \"#6fa8dc7f\";\n    this._innerUpdateHighlight(elements, { color, tooltipText: selector ? asLocator(this._language, selector) : \"\" });\n  }\n  maskElements(elements) {\n    this._innerUpdateHighlight(elements, { color: \"#F0F\" });\n  }\n  _innerUpdateHighlight(elements, options) {\n    if (this._highlightIsUpToDate(elements, options.tooltipText))\n      return;\n    this.clearHighlight();\n    for (let i = 0; i < elements.length; ++i) {\n      const highlightElement = this._createHighlightElement();\n      this._glassPaneShadow.appendChild(highlightElement);\n      let tooltipElement;\n      if (options.tooltipText) {\n        tooltipElement = this._injectedScript.document.createElement(\"x-pw-tooltip\");\n        this._glassPaneShadow.appendChild(tooltipElement);\n        const suffix = elements.length > 1 ? ` [${i + 1} of ${elements.length}]` : \"\";\n        tooltipElement.textContent = options.tooltipText + suffix;\n        tooltipElement.style.top = \"0\";\n        tooltipElement.style.left = \"0\";\n        tooltipElement.style.display = \"flex\";\n      }\n      this._highlightEntries.push({ targetElement: elements[i], tooltipElement, highlightElement, tooltipText: options.tooltipText });\n    }\n    for (const entry of this._highlightEntries) {\n      entry.box = entry.targetElement.getBoundingClientRect();\n      if (!entry.tooltipElement)\n        continue;\n      const tooltipWidth = entry.tooltipElement.offsetWidth;\n      const tooltipHeight = entry.tooltipElement.offsetHeight;\n      const totalWidth = this._glassPaneElement.offsetWidth;\n      const totalHeight = this._glassPaneElement.offsetHeight;\n      let anchorLeft = entry.box.left;\n      if (anchorLeft + tooltipWidth > totalWidth - 5)\n        anchorLeft = totalWidth - tooltipWidth - 5;\n      let anchorTop = entry.box.bottom + 5;\n      if (anchorTop + tooltipHeight > totalHeight - 5) {\n        if (entry.box.top > tooltipHeight + 5) {\n          anchorTop = entry.box.top - tooltipHeight - 5;\n        } else {\n          anchorTop = totalHeight - 5 - tooltipHeight;\n        }\n      }\n      entry.tooltipTop = anchorTop;\n      entry.tooltipLeft = anchorLeft;\n    }\n    for (const entry of this._highlightEntries) {\n      if (entry.tooltipElement) {\n        entry.tooltipElement.style.top = entry.tooltipTop + \"px\";\n        entry.tooltipElement.style.left = entry.tooltipLeft + \"px\";\n      }\n      const box = entry.box;\n      entry.highlightElement.style.backgroundColor = options.color;\n      entry.highlightElement.style.left = box.x + \"px\";\n      entry.highlightElement.style.top = box.y + \"px\";\n      entry.highlightElement.style.width = box.width + \"px\";\n      entry.highlightElement.style.height = box.height + \"px\";\n      entry.highlightElement.style.display = \"block\";\n      if (this._isUnderTest)\n        console.error(\"Highlight box for test: \" + JSON.stringify({ x: box.x, y: box.y, width: box.width, height: box.height }));\n    }\n  }\n  _highlightIsUpToDate(elements, tooltipText) {\n    if (elements.length !== this._highlightEntries.length)\n      return false;\n    for (let i = 0; i < this._highlightEntries.length; ++i) {\n      if (tooltipText !== this._highlightEntries[i].tooltipText)\n        return false;\n      if (elements[i] !== this._highlightEntries[i].targetElement)\n        return false;\n      const oldBox = this._highlightEntries[i].box;\n      if (!oldBox)\n        return false;\n      const box = elements[i].getBoundingClientRect();\n      if (box.top !== oldBox.top || box.right !== oldBox.right || box.bottom !== oldBox.bottom || box.left !== oldBox.left)\n        return false;\n    }\n    return true;\n  }\n  _createHighlightElement() {\n    const highlightElement = this._injectedScript.document.createElement(\"x-pw-highlight\");\n    highlightElement.style.position = \"absolute\";\n    highlightElement.style.top = \"0\";\n    highlightElement.style.left = \"0\";\n    highlightElement.style.width = \"0\";\n    highlightElement.style.height = \"0\";\n    highlightElement.style.boxSizing = \"border-box\";\n    return highlightElement;\n  }\n};\n\n// packages/playwright-core/src/server/injected/recorder.ts\nvar Recorder = class {\n  constructor(injectedScript, delegate) {\n    this._performingAction = false;\n    this._listeners = [];\n    this._hoveredModel = null;\n    this._hoveredElement = null;\n    this._activeModel = null;\n    this._expectProgrammaticKeyUp = false;\n    this._mode = \"none\";\n    this._testIdAttributeName = \"data-testid\";\n    this.document = injectedScript.document;\n    this._injectedScript = injectedScript;\n    this._delegate = delegate;\n    this._highlight = new Highlight(injectedScript);\n    this.refreshListenersIfNeeded();\n    if (injectedScript.isUnderTest)\n      console.error(\"Recorder script ready for test\");\n  }\n  refreshListenersIfNeeded() {\n    if (this._highlight.isInstalled())\n      return;\n    removeEventListeners(this._listeners);\n    this._listeners = [\n      addEventListener(this.document, \"click\", (event) => this._onClick(event), true),\n      addEventListener(this.document, \"auxclick\", (event) => this._onClick(event), true),\n      addEventListener(this.document, \"input\", (event) => this._onInput(event), true),\n      addEventListener(this.document, \"keydown\", (event) => this._onKeyDown(event), true),\n      addEventListener(this.document, \"keyup\", (event) => this._onKeyUp(event), true),\n      addEventListener(this.document, \"mousedown\", (event) => this._onMouseDown(event), true),\n      addEventListener(this.document, \"mouseup\", (event) => this._onMouseUp(event), true),\n      addEventListener(this.document, \"mousemove\", (event) => this._onMouseMove(event), true),\n      addEventListener(this.document, \"mouseleave\", (event) => this._onMouseLeave(event), true),\n      addEventListener(this.document, \"focus\", (event) => event.isTrusted && this._onFocus(true), true),\n      addEventListener(this.document, \"scroll\", (event) => {\n        if (!event.isTrusted)\n          return;\n        this._hoveredModel = null;\n        this._highlight.hideActionPoint();\n        this._updateHighlight();\n      }, true)\n    ];\n    this._highlight.install();\n  }\n  setUIState(state) {\n    var _a;\n    const { mode, actionPoint, actionSelector, language, testIdAttributeName } = state;\n    this._testIdAttributeName = testIdAttributeName;\n    this._highlight.setLanguage(language);\n    if (mode !== this._mode) {\n      this._mode = mode;\n      this._clearHighlight();\n    }\n    if (actionPoint && this._actionPoint && actionPoint.x === this._actionPoint.x && actionPoint.y === this._actionPoint.y) {\n    } else if (!actionPoint && !this._actionPoint) {\n    } else {\n      if (actionPoint)\n        this._highlight.showActionPoint(actionPoint.x, actionPoint.y);\n      else\n        this._highlight.hideActionPoint();\n      this._actionPoint = actionPoint;\n    }\n    if (this._actionSelector && !((_a = this._hoveredModel) == null ? void 0 : _a.elements.length))\n      this._actionSelector = void 0;\n    if (actionSelector !== this._actionSelector) {\n      this._hoveredModel = actionSelector ? querySelector(this._injectedScript, actionSelector, this.document) : null;\n      this._updateHighlight();\n      this._actionSelector = actionSelector;\n    }\n  }\n  _clearHighlight() {\n    this._hoveredModel = null;\n    this._activeModel = null;\n    this._updateHighlight();\n  }\n  _actionInProgress(event) {\n    if (this._performingAction)\n      return true;\n    consumeEvent(event);\n    return false;\n  }\n  _consumedDueToNoModel(event, model) {\n    if (model)\n      return false;\n    consumeEvent(event);\n    return true;\n  }\n  _consumedDueWrongTarget(event) {\n    if (this._activeModel && this._activeModel.elements[0] === this._deepEventTarget(event))\n      return false;\n    consumeEvent(event);\n    return true;\n  }\n  _onClick(event) {\n    var _a, _b;\n    if (!event.isTrusted)\n      return;\n    if (this._mode === \"inspecting\")\n      (_b = (_a = this._delegate).setSelector) == null ? void 0 : _b.call(_a, this._hoveredModel ? this._hoveredModel.selector : \"\");\n    if (this._shouldIgnoreMouseEvent(event))\n      return;\n    if (this._actionInProgress(event))\n      return;\n    if (this._consumedDueToNoModel(event, this._hoveredModel))\n      return;\n    const checkbox = asCheckbox(this._deepEventTarget(event));\n    if (checkbox) {\n      this._performAction({\n        name: checkbox.checked ? \"check\" : \"uncheck\",\n        selector: this._hoveredModel.selector,\n        signals: []\n      });\n      return;\n    }\n    this._performAction({\n      name: \"click\",\n      selector: this._hoveredModel.selector,\n      position: positionForEvent(event),\n      signals: [],\n      button: buttonForEvent(event),\n      modifiers: modifiersForEvent(event),\n      clickCount: event.detail\n    });\n  }\n  _shouldIgnoreMouseEvent(event) {\n    const target = this._deepEventTarget(event);\n    if (this._mode === \"none\")\n      return true;\n    if (this._mode === \"inspecting\") {\n      consumeEvent(event);\n      return true;\n    }\n    const nodeName = target.nodeName;\n    if (nodeName === \"SELECT\" || nodeName === \"OPTION\")\n      return true;\n    if (nodeName === \"INPUT\" && [\"date\"].includes(target.type))\n      return true;\n    return false;\n  }\n  _onMouseDown(event) {\n    if (!event.isTrusted)\n      return;\n    if (this._shouldIgnoreMouseEvent(event))\n      return;\n    if (!this._performingAction)\n      consumeEvent(event);\n    this._activeModel = this._hoveredModel;\n  }\n  _onMouseUp(event) {\n    if (!event.isTrusted)\n      return;\n    if (this._shouldIgnoreMouseEvent(event))\n      return;\n    if (!this._performingAction)\n      consumeEvent(event);\n  }\n  _onMouseMove(event) {\n    if (!event.isTrusted)\n      return;\n    if (this._mode === \"none\")\n      return;\n    const target = this._deepEventTarget(event);\n    if (this._hoveredElement === target)\n      return;\n    this._hoveredElement = target;\n    this._updateModelForHoveredElement();\n  }\n  _onMouseLeave(event) {\n    if (!event.isTrusted)\n      return;\n    if (this._injectedScript.window.top !== this._injectedScript.window && this._deepEventTarget(event).nodeType === Node.DOCUMENT_NODE) {\n      this._hoveredElement = null;\n      this._updateModelForHoveredElement();\n    }\n  }\n  _onFocus(userGesture) {\n    if (this._mode === \"none\")\n      return;\n    const activeElement = this._deepActiveElement(this.document);\n    if (userGesture && activeElement === this.document.body)\n      return;\n    const result = activeElement ? generateSelector(this._injectedScript, activeElement, this._testIdAttributeName) : null;\n    this._activeModel = result && result.selector ? result : null;\n    if (userGesture)\n      this._hoveredElement = activeElement;\n    this._updateModelForHoveredElement();\n  }\n  _updateModelForHoveredElement() {\n    if (!this._hoveredElement) {\n      this._hoveredModel = null;\n      this._updateHighlight();\n      return;\n    }\n    const hoveredElement = this._hoveredElement;\n    const { selector, elements } = generateSelector(this._injectedScript, hoveredElement, this._testIdAttributeName);\n    if (this._hoveredModel && this._hoveredModel.selector === selector)\n      return;\n    this._hoveredModel = selector ? { selector, elements } : null;\n    this._updateHighlight();\n  }\n  _updateHighlight() {\n    const elements = this._hoveredModel ? this._hoveredModel.elements : [];\n    const selector = this._hoveredModel ? this._hoveredModel.selector : \"\";\n    this._highlight.updateHighlight(elements, selector, this._mode === \"recording\");\n  }\n  _onInput(event) {\n    var _a, _b, _c, _d;\n    if (this._mode !== \"recording\")\n      return true;\n    const target = this._deepEventTarget(event);\n    if (target.nodeName === \"INPUT\" && target.type.toLowerCase() === \"file\") {\n      (_b = (_a = this._delegate).recordAction) == null ? void 0 : _b.call(_a, {\n        name: \"setInputFiles\",\n        selector: this._activeModel.selector,\n        signals: [],\n        files: [...target.files || []].map((file) => file.name)\n      });\n      return;\n    }\n    if ([\"INPUT\", \"TEXTAREA\"].includes(target.nodeName) || target.isContentEditable) {\n      if (target.nodeName === \"INPUT\" && [\"checkbox\", \"radio\"].includes(target.type.toLowerCase())) {\n        return;\n      }\n      if (this._consumedDueWrongTarget(event))\n        return;\n      (_d = (_c = this._delegate).recordAction) == null ? void 0 : _d.call(_c, {\n        name: \"fill\",\n        selector: this._activeModel.selector,\n        signals: [],\n        text: target.isContentEditable ? target.innerText : target.value\n      });\n    }\n    if (target.nodeName === \"SELECT\") {\n      const selectElement = target;\n      if (this._actionInProgress(event))\n        return;\n      this._performAction({\n        name: \"select\",\n        selector: this._hoveredModel.selector,\n        options: [...selectElement.selectedOptions].map((option) => option.value),\n        signals: []\n      });\n    }\n  }\n  _shouldGenerateKeyPressFor(event) {\n    if ([\"Backspace\", \"Delete\", \"AltGraph\"].includes(event.key))\n      return false;\n    if (event.key === \"@\" && event.code === \"KeyL\")\n      return false;\n    if (navigator.platform.includes(\"Mac\")) {\n      if (event.key === \"v\" && event.metaKey)\n        return false;\n    } else {\n      if (event.key === \"v\" && event.ctrlKey)\n        return false;\n      if (event.key === \"Insert\" && event.shiftKey)\n        return false;\n    }\n    if ([\"Shift\", \"Control\", \"Meta\", \"Alt\", \"Process\"].includes(event.key))\n      return false;\n    const hasModifier = event.ctrlKey || event.altKey || event.metaKey;\n    if (event.key.length === 1 && !hasModifier)\n      return !!asCheckbox(this._deepEventTarget(event));\n    return true;\n  }\n  _onKeyDown(event) {\n    if (!event.isTrusted)\n      return;\n    if (this._mode === \"inspecting\") {\n      consumeEvent(event);\n      return;\n    }\n    if (this._mode !== \"recording\")\n      return;\n    if (!this._shouldGenerateKeyPressFor(event))\n      return;\n    if (this._actionInProgress(event)) {\n      this._expectProgrammaticKeyUp = true;\n      return;\n    }\n    if (this._consumedDueWrongTarget(event))\n      return;\n    if (event.key === \" \") {\n      const checkbox = asCheckbox(this._deepEventTarget(event));\n      if (checkbox) {\n        this._performAction({\n          name: checkbox.checked ? \"uncheck\" : \"check\",\n          selector: this._activeModel.selector,\n          signals: []\n        });\n        return;\n      }\n    }\n    this._performAction({\n      name: \"press\",\n      selector: this._activeModel.selector,\n      signals: [],\n      key: event.key,\n      modifiers: modifiersForEvent(event)\n    });\n  }\n  _onKeyUp(event) {\n    if (!event.isTrusted)\n      return;\n    if (this._mode === \"none\")\n      return;\n    if (!this._shouldGenerateKeyPressFor(event))\n      return;\n    if (!this._expectProgrammaticKeyUp) {\n      consumeEvent(event);\n      return;\n    }\n    this._expectProgrammaticKeyUp = false;\n  }\n  async _performAction(action) {\n    var _a, _b;\n    this._clearHighlight();\n    this._performingAction = true;\n    await ((_b = (_a = this._delegate).performAction) == null ? void 0 : _b.call(_a, action).catch(() => {\n    }));\n    this._performingAction = false;\n    this._onFocus(false);\n    if (this._injectedScript.isUnderTest) {\n      console.error(\"Action performed for test: \" + JSON.stringify({\n        hovered: this._hoveredModel ? this._hoveredModel.selector : null,\n        active: this._activeModel ? this._activeModel.selector : null\n      }));\n    }\n  }\n  _deepEventTarget(event) {\n    return event.composedPath()[0];\n  }\n  _deepActiveElement(document) {\n    let activeElement = document.activeElement;\n    while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement)\n      activeElement = activeElement.shadowRoot.activeElement;\n    return activeElement;\n  }\n};\nfunction modifiersForEvent(event) {\n  return (event.altKey ? 1 : 0) | (event.ctrlKey ? 2 : 0) | (event.metaKey ? 4 : 0) | (event.shiftKey ? 8 : 0);\n}\nfunction buttonForEvent(event) {\n  switch (event.which) {\n    case 1:\n      return \"left\";\n    case 2:\n      return \"middle\";\n    case 3:\n      return \"right\";\n  }\n  return \"left\";\n}\nfunction positionForEvent(event) {\n  const targetElement = event.target;\n  if (targetElement.nodeName !== \"CANVAS\")\n    return;\n  return {\n    x: event.offsetX,\n    y: event.offsetY\n  };\n}\nfunction consumeEvent(e) {\n  e.preventDefault();\n  e.stopPropagation();\n  e.stopImmediatePropagation();\n}\nfunction asCheckbox(node) {\n  if (!node || node.nodeName !== \"INPUT\")\n    return null;\n  const inputElement = node;\n  return [\"checkbox\", \"radio\"].includes(inputElement.type) ? inputElement : null;\n}\nfunction addEventListener(target, eventName, listener, useCapture) {\n  target.addEventListener(eventName, listener, useCapture);\n  const remove = () => {\n    target.removeEventListener(eventName, listener, useCapture);\n  };\n  return remove;\n}\nfunction removeEventListeners(listeners) {\n  for (const listener of listeners)\n    listener();\n  listeners.splice(0, listeners.length);\n}\nvar PollingRecorder = class {\n  constructor(injectedScript) {\n    this._recorder = new Recorder(injectedScript, this);\n    this._embedder = injectedScript.window;\n    injectedScript.onGlobalListenersRemoved.add(() => this._recorder.refreshListenersIfNeeded());\n    const refreshOverlay = () => {\n      this._pollRecorderMode().catch((e) => console.log(e));\n    };\n    this._embedder.__pw_refreshOverlay = refreshOverlay;\n    refreshOverlay();\n  }\n  async _pollRecorderMode() {\n    const pollPeriod = 1e3;\n    if (this._pollRecorderModeTimer)\n      clearTimeout(this._pollRecorderModeTimer);\n    const state = await this._embedder.__pw_recorderState().catch(() => {\n    });\n    if (!state) {\n      this._pollRecorderModeTimer = setTimeout(() => this._pollRecorderMode(), pollPeriod);\n      return;\n    }\n    this._recorder.setUIState(state);\n    this._pollRecorderModeTimer = setTimeout(() => this._pollRecorderMode(), pollPeriod);\n  }\n  async performAction(action) {\n    await this._embedder.__pw_recorderPerformAction(action);\n  }\n  async recordAction(action) {\n    await this._embedder.__pw_recorderRecordAction(action);\n  }\n  async __pw_recorderState() {\n    return await this._embedder.__pw_recorderState();\n  }\n  async setSelector(selector) {\n    await this._embedder.__pw_recorderSetSelector(selector);\n  }\n};\nvar recorder_default = PollingRecorder;\n";
exports.source = source;