"use strict";
var pwExport = 
/******/ (function (modules) {
    /******/ // The module cache
    /******/ var installedModules = {};
    /******/
    /******/ // The require function
    /******/ function __webpack_require__(moduleId) {
        /******/
        /******/ // Check if module is in cache
        /******/ if (installedModules[moduleId]) {
            /******/ return installedModules[moduleId].exports;
            /******/ }
        /******/ // Create a new module (and put it into the cache)
        /******/ var module = installedModules[moduleId] = {
            /******/ i: moduleId,
            /******/ l: false,
            /******/ exports: {}
            /******/ 
        };
        /******/
        /******/ // Execute the module function
        /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
        /******/
        /******/ // Flag the module as loaded
        /******/ module.l = true;
        /******/
        /******/ // Return the exports of the module
        /******/ return module.exports;
        /******/ 
    }
    /******/
    /******/
    /******/ // expose the modules object (__webpack_modules__)
    /******/ __webpack_require__.m = modules;
    /******/
    /******/ // expose the module cache
    /******/ __webpack_require__.c = installedModules;
    /******/
    /******/ // define getter function for harmony exports
    /******/ __webpack_require__.d = function (exports, name, getter) {
        /******/ if (!__webpack_require__.o(exports, name)) {
            /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
            /******/ }
        /******/ 
    };
    /******/
    /******/ // define __esModule on exports
    /******/ __webpack_require__.r = function (exports) {
        /******/ if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
            /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
            /******/ }
        /******/ Object.defineProperty(exports, '__esModule', { value: true });
        /******/ 
    };
    /******/
    /******/ // create a fake namespace object
    /******/ // mode & 1: value is a module id, require it
    /******/ // mode & 2: merge all properties of value into the ns
    /******/ // mode & 4: return value when already ns object
    /******/ // mode & 8|1: behave like require
    /******/ __webpack_require__.t = function (value, mode) {
        /******/ if (mode & 1)
            value = __webpack_require__(value);
        /******/ if (mode & 8)
            return value;
        /******/ if ((mode & 4) && typeof value === 'object' && value && value.__esModule)
            return value;
        /******/ var ns = Object.create(null);
        /******/ __webpack_require__.r(ns);
        /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
        /******/ if (mode & 2 && typeof value != 'string')
            for (var key in value)
                __webpack_require__.d(ns, key, function (key) { return value[key]; }.bind(null, key));
        /******/ return ns;
        /******/ 
    };
    /******/
    /******/ // getDefaultExport function for compatibility with non-harmony modules
    /******/ __webpack_require__.n = function (module) {
        /******/ var getter = module && module.__esModule ?
            /******/ function getDefault() { return module['default']; } :
            /******/ function getModuleExports() { return module; };
        /******/ __webpack_require__.d(getter, 'a', getter);
        /******/ return getter;
        /******/ 
    };
    /******/
    /******/ // Object.prototype.hasOwnProperty.call
    /******/ __webpack_require__.o = function (object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
    /******/
    /******/ // __webpack_public_path__
    /******/ __webpack_require__.p = "";
    /******/
    /******/
    /******/ // Load entry module and return exports
    /******/ return __webpack_require__(__webpack_require__.s = "./src/server/supplements/injected/recorder.ts");
    /******/ 
})({
    /***/ "./src/server/supplements/injected/html.ts": 
    /*!*************************************************!*\
      !*** ./src/server/supplements/injected/html.ts ***!
      \*************************************************/
    /*! no static exports found */
    /***/ (function (module, exports, __webpack_require__) {
        "use strict";
        /**
         * Copyright (c) Microsoft Corporation.
         *
         * Licensed under the Apache License, Version 2.0 (the "License");
         * you may not use this file except in compliance with the License.
         * You may obtain a copy of the License at
         *
         * http://www.apache.org/licenses/LICENSE-2.0
         *
         * Unless required by applicable law or agreed to in writing, software
         * distributed under the License is distributed on an "AS IS" BASIS,
         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
         * See the License for the specific language governing permissions and
         * limitations under the License.
         */
        Object.defineProperty(exports, "__esModule", { value: true });
        exports.deepActiveElement = exports.html = exports.onDOMResize = exports.onDOMEvent = void 0;
        const templateCache = new Map();
        const BOOLEAN_ATTRS = new Set([
            'async', 'autofocus', 'autoplay', 'checked', 'contenteditable', 'controls',
            'default', 'defer', 'disabled', 'expanded', 'formNoValidate', 'frameborder', 'hidden',
            'ismap', 'itemscope', 'loop', 'multiple', 'muted', 'nomodule', 'novalidate',
            'open', 'readonly', 'required', 'reversed', 'scoped', 'selected', 'typemustmatch',
        ]);
        function onDOMEvent(target, name, listener, capturing = false) {
            target.addEventListener(name, listener, capturing);
            return () => {
                target.removeEventListener(name, listener, capturing);
            };
        }
        exports.onDOMEvent = onDOMEvent;
        function onDOMResize(target, callback) {
            const resizeObserver = new window.ResizeObserver(callback);
            resizeObserver.observe(target);
            return () => resizeObserver.disconnect();
        }
        exports.onDOMResize = onDOMResize;
        function html(strings, ...values) {
            let cache = templateCache.get(strings);
            if (!cache) {
                cache = prepareTemplate(strings);
                templateCache.set(strings, cache);
            }
            const node = renderTemplate(cache.template, cache.subs, values);
            if (node.querySelector) {
                node.$ = node.querySelector.bind(node);
                node.$$ = node.querySelectorAll.bind(node);
            }
            return node;
        }
        exports.html = html;
        const SPACE_REGEX = /^\s*\n\s*$/;
        const MARKER_REGEX = /---dom-template-\d+---/;
        function prepareTemplate(strings) {
            const template = document.createElement('template');
            let html = '';
            for (let i = 0; i < strings.length - 1; ++i) {
                html += strings[i];
                html += `---dom-template-${i}---`;
            }
            html += strings[strings.length - 1];
            template.innerHTML = html;
            const walker = template.ownerDocument.createTreeWalker(template.content, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT, null, false);
            const emptyTextNodes = [];
            const subs = [];
            while (walker.nextNode()) {
                const node = walker.currentNode;
                if (node.nodeType === Node.ELEMENT_NODE && MARKER_REGEX.test(node.tagName))
                    throw new Error('Should not use a parameter as an html tag');
                if (node.nodeType === Node.ELEMENT_NODE && node.hasAttributes()) {
                    const element = node;
                    for (let i = 0; i < element.attributes.length; i++) {
                        const name = element.attributes[i].name;
                        const nameParts = name.split(MARKER_REGEX);
                        const valueParts = element.attributes[i].value.split(MARKER_REGEX);
                        const isSimpleValue = valueParts.length === 2 && valueParts[0] === '' && valueParts[1] === '';
                        if (nameParts.length > 1 || valueParts.length > 1)
                            subs.push({ node: element, nameParts, valueParts, isSimpleValue, attr: name });
                    }
                }
                else if (node.nodeType === Node.TEXT_NODE && MARKER_REGEX.test(node.data)) {
                    const text = node;
                    const texts = text.data.split(MARKER_REGEX);
                    text.data = texts[0];
                    const anchor = node.nextSibling;
                    for (let i = 1; i < texts.length; ++i) {
                        const span = document.createElement('span');
                        node.parentNode.insertBefore(span, anchor);
                        node.parentNode.insertBefore(document.createTextNode(texts[i]), anchor);
                        subs.push({
                            node: span,
                            type: 'replace-node',
                        });
                    }
                    if (shouldRemoveTextNode(text))
                        emptyTextNodes.push(text);
                }
                else if (node.nodeType === Node.TEXT_NODE && shouldRemoveTextNode(node)) {
                    emptyTextNodes.push(node);
                }
            }
            for (const emptyTextNode of emptyTextNodes)
                emptyTextNode.remove();
            const markedNodes = new Map();
            for (const sub of subs) {
                let index = markedNodes.get(sub.node);
                if (index === undefined) {
                    index = markedNodes.size;
                    sub.node.setAttribute('dom-template-marked', 'true');
                    markedNodes.set(sub.node, index);
                }
                sub.nodeIndex = index;
            }
            return { template, subs };
        }
        function shouldRemoveTextNode(node) {
            if (!node.previousSibling && !node.nextSibling)
                return !node.data.length;
            return (!node.previousSibling || node.previousSibling.nodeType === Node.ELEMENT_NODE) &&
                (!node.nextSibling || node.nextSibling.nodeType === Node.ELEMENT_NODE) &&
                (!node.data.length || SPACE_REGEX.test(node.data));
        }
        function renderTemplate(template, subs, values) {
            const content = template.ownerDocument.importNode(template.content, true);
            const boundElements = Array.from(content.querySelectorAll('[dom-template-marked]'));
            for (const node of boundElements)
                node.removeAttribute('dom-template-marked');
            let valueIndex = 0;
            const interpolateText = (texts) => {
                let newText = texts[0];
                for (let i = 1; i < texts.length; ++i) {
                    newText += values[valueIndex++];
                    newText += texts[i];
                }
                return newText;
            };
            for (const sub of subs) {
                const n = boundElements[sub.nodeIndex];
                if (sub.attr) {
                    n.removeAttribute(sub.attr);
                    const name = interpolateText(sub.nameParts);
                    const value = sub.isSimpleValue ? values[valueIndex++] : interpolateText(sub.valueParts);
                    if (BOOLEAN_ATTRS.has(name))
                        n.toggleAttribute(name, !!value);
                    else
                        n.setAttribute(name, String(value));
                }
                else if (sub.type === 'replace-node') {
                    const replacement = values[valueIndex++];
                    if (Array.isArray(replacement)) {
                        const fragment = document.createDocumentFragment();
                        for (const node of replacement)
                            fragment.appendChild(node);
                        n.replaceWith(fragment);
                    }
                    else if (replacement instanceof Node) {
                        n.replaceWith(replacement);
                    }
                    else {
                        n.replaceWith(document.createTextNode(replacement || ''));
                    }
                }
            }
            return content.firstChild && content.firstChild === content.lastChild ? content.firstChild : content;
        }
        function deepActiveElement() {
            let activeElement = document.activeElement;
            while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement)
                activeElement = activeElement.shadowRoot.activeElement;
            return activeElement;
        }
        exports.deepActiveElement = deepActiveElement;
        /***/ 
    }),
    /***/ "./src/server/supplements/injected/recorder.ts": 
    /*!*****************************************************!*\
      !*** ./src/server/supplements/injected/recorder.ts ***!
      \*****************************************************/
    /*! no static exports found */
    /***/ (function (module, exports, __webpack_require__) {
        "use strict";
        /**
         * Copyright (c) Microsoft Corporation.
         *
         * Licensed under the Apache License, Version 2.0 (the "License");
         * you may not use this file except in compliance with the License.
         * You may obtain a copy of the License at
         *
         * http://www.apache.org/licenses/LICENSE-2.0
         *
         * Unless required by applicable law or agreed to in writing, software
         * distributed under the License is distributed on an "AS IS" BASIS,
         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
         * See the License for the specific language governing permissions and
         * limitations under the License.
         */
        Object.defineProperty(exports, "__esModule", { value: true });
        exports.Recorder = void 0;
        const selectorGenerator_1 = __webpack_require__(/*! ./selectorGenerator */ "./src/server/supplements/injected/selectorGenerator.ts");
        const html_1 = __webpack_require__(/*! ./html */ "./src/server/supplements/injected/html.ts");
        const scriptSymbol = Symbol('scriptSymbol');
        class Recorder {
            constructor(injectedScript) {
                this._performingAction = false;
                this._highlightElements = [];
                this._listeners = [];
                this._hoveredModel = null;
                this._hoveredElement = null;
                this._activeModel = null;
                this._expectProgrammaticKeyUp = false;
                this._state = {
                    uiState: {
                        mode: 'none',
                    },
                    isPaused: false
                };
                this._injectedScript = injectedScript;
                this._outerGlassPaneElement = html_1.html `
      <x-pw-glass style="
        position: fixed;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        z-index: 2147483647;
        pointer-events: none;
        display: flex;
      ">
      </x-pw-glass>`;
                this._tooltipElement = html_1.html `<x-pw-tooltip></x-pw-tooltip>`;
                this._innerGlassPaneElement = html_1.html `
      <x-pw-glass-inner style="flex: auto">
        ${this._tooltipElement}
      </x-pw-glass-inner>`;
                // Use a closed shadow root to prevent selectors matching our internal previews.
                this._glassPaneShadow = this._outerGlassPaneElement.attachShadow({ mode: 'closed' });
                this._glassPaneShadow.appendChild(this._innerGlassPaneElement);
                this._glassPaneShadow.appendChild(html_1.html `
      <style>
        x-pw-tooltip {
          align-items: center;
          backdrop-filter: blur(5px);
          background-color: rgba(0, 0, 0, 0.7);
          border-radius: 2px;
          box-shadow: rgba(0, 0, 0, 0.1) 0px 3.6px 3.7px,
                      rgba(0, 0, 0, 0.15) 0px 12.1px 12.3px,
                      rgba(0, 0, 0, 0.1) 0px -2px 4px,
                      rgba(0, 0, 0, 0.15) 0px -12.1px 24px,
                      rgba(0, 0, 0, 0.25) 0px 54px 55px;
          color: rgb(204, 204, 204);
          display: none;
          font-family: 'Dank Mono', 'Operator Mono', Inconsolata, 'Fira Mono',
                       'SF Mono', Monaco, 'Droid Sans Mono', 'Source Code Pro', monospace;
          font-size: 12.8px;
          font-weight: normal;
          left: 0;
          line-height: 1.5;
          max-width: 600px;
          padding: 3.2px 5.12px 3.2px;
          position: absolute;
          top: 0;
        }
      </style>
    `);
                this._toolbar = html_1.html `
      <x-pw-toolbar class="vertical">
        ${commonStyles()}
        <x-pw-button-group>
          <x-pw-button id="pw-button-playwright" tabIndex=0 title="Playwright">
            <x-pw-icon>
              <svg xmlns="http://www.w3.org/2000/svg" width="400" height="400" fill="none"><path d="M136 222c-12 3-21 10-26 16 5-5 12-9 22-12 10-2 18-2 25-1v-6c-6 0-13 0-21 3zm-27-46l-48 12 3 3 40-10s0 7-5 14c9-7 10-19 10-19zm40 112C82 306 46 228 35 188a227 227 0 01-7-45c-4 1-6 2-5 8 0 9 2 23 7 42 11 40 47 118 114 100 15-4 26-11 34-20-7 7-17 12-29 15zm13-160v5h26l-2-5h-24z" fill="#2D4552"/><path d="M194 168c12 3 18 11 21 19l14 3s-2-25-25-32c-22-6-36 12-37 14 6-4 15-8 27-4zm105 19c-21-6-35 12-36 14 6-4 15-8 27-5 12 4 18 12 21 19l14 4s-2-26-26-32zm-13 68l-110-31s1 6 6 14l93 26 11-9zm-76 66c-87-23-77-134-63-187 6-22 12-38 17-49-3 0-5 1-8 6-5 11-12 28-18 52-14 53-25 164 62 188 41 11 73-6 97-32a90 90 0 01-87 22z" fill="#2D4552"/><path d="M162 262v-22l-63 18s5-27 37-36c10-3 19-3 26-2v-92h31l-10-24c-4-9-9-3-19 6-8 6-27 19-55 27-29 8-52 6-61 4-14-2-21-5-20 5 0 9 2 23 7 42 11 40 47 118 114 100 18-4 30-14 39-26h-26zM61 188l48-12s-1 18-19 23-29-11-29-11z" fill="#E2574C"/><path d="M342 129c-13 2-43 5-79-5-37-10-62-27-71-35-14-12-20-20-26-8-5 11-12 29-19 53-14 53-24 164 63 187s134-78 148-131c6-24 9-42 10-54 1-14-9-10-26-7zm-176 44s14-22 38-15c23 7 25 32 25 32l-63-17zm57 96c-41-12-47-45-47-45l110 31s-22 26-63 14zm39-68s14-21 37-14c24 6 26 32 26 32l-63-18z" fill="#2EAD33"/><path d="M140 246l-41 12s5-26 35-36l-23-86-2 1c-29 8-52 6-61 4-14-2-21-5-20 5 0 9 2 23 7 42 11 40 47 118 114 100h2l-11-42zm-79-58l48-12s-1 18-19 23-29-11-29-11z" fill="#D65348"/><path d="M225 269h-2c-41-12-47-45-47-45l57 16 30-116c-37-10-62-27-71-35-14-12-20-20-26-8-5 11-12 29-19 53-14 53-24 164 63 187l2 1 13-53zm-59-96s14-22 38-15c23 7 25 32 25 32l-63-17z" fill="#1D8D22"/><path d="M142 245l-11 4c3 14 7 28 14 40l4-1 9-3c-8-12-13-25-16-40zm-4-102c-6 21-11 51-10 81l8-2 2-1a273 273 0 0114-103l-8 5-6 20z" fill="#C04B41"/></svg>
            </x-pw-icon>
          </x-pw-button>
        </x-pw-button-group>
        <x-pw-button-group>
          <x-pw-button id="pw-button-inspect" tabIndex=0 title="Inspect selectors">
            <svg xmlns="http://www.w3.org/2000/svg" height="24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm8.94 3c-.46-4.17-3.77-7.48-7.94-7.94V1h-2v2.06C6.83 3.52 3.52 6.83 3.06 11H1v2h2.06c.46 4.17 3.77 7.48 7.94 7.94V23h2v-2.06c4.17-.46 7.48-3.77 7.94-7.94H23v-2h-2.06zM12 19c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z"/></svg>
          </x-pw-button>
          <x-pw-button id="pw-button-record" class="record" tabIndex=0 title="Record script">
            <div class="record-button">
              <div class="record-button-glow"></div>
            </div>
          </x-pw-button>
        </x-pw-button-group>
        <x-pw-button-group id="pw-button-resume-group" class="hidden" title="Resume execution">
          <x-pw-button id="pw-button-resume" tabIndex=0>
            <svg xmlns="http://www.w3.org/2000/svg" height="24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M8 5v14l11-7z"/></svg>
          </x-pw-button>
        </x-pw-button-group>
      </x-pw-toolbar>`;
                this._outerToolbarElement = html_1.html `<x-pw-div style="position: fixed; top: 100px; left: 10px; flex-direction: column; z-index: 2147483646;"></x-pw-div>`;
                const toolbarShadow = this._outerToolbarElement.attachShadow({ mode: 'open' });
                toolbarShadow.appendChild(this._toolbar);
                this._hydrate();
                this._refreshListenersIfNeeded();
                setInterval(() => {
                    this._refreshListenersIfNeeded();
                    if (window._recorderScriptReadyForTest)
                        window._recorderScriptReadyForTest();
                }, 500);
                this._pollRecorderMode(true).catch(e => console.log(e)); // eslint-disable-line no-console
            }
            _hydrate() {
                this._toolbar.addEventListener('mousedown', e => {
                    if (e.target !== this._toolbar)
                        return;
                    this._outerGlassPaneElement.style.pointerEvents = 'initial';
                    this._outerGlassPaneElement.style.cursor = 'grab';
                    this._outerGlassPaneElement.setAttribute('tabIndex', '0');
                    const offsetLeft = e.pageX - this._outerToolbarElement.offsetLeft;
                    const offsetTop = e.pageY - this._outerToolbarElement.offsetTop;
                    const toolbarWidth = this._outerToolbarElement.offsetWidth;
                    const toolbarHeight = this._outerToolbarElement.offsetHeight;
                    const glassWidth = this._outerGlassPaneElement.offsetWidth;
                    const glassHeight = this._outerGlassPaneElement.offsetHeight;
                    const maxX = glassWidth - toolbarWidth;
                    const maxY = glassHeight - toolbarHeight;
                    const onMouseMove = (e) => {
                        this._outerToolbarElement.style.top = Math.min(maxY, Math.max(e.pageY - offsetTop, 0)) + 'px';
                        this._outerToolbarElement.style.left = Math.min(maxX, Math.max(e.pageX - offsetLeft, 0)) + 'px';
                    };
                    const onMouseUp = () => {
                        this._outerGlassPaneElement.removeEventListener('mousemove', onMouseMove);
                        this._outerGlassPaneElement.removeEventListener('mouseup', onMouseUp);
                        this._outerGlassPaneElement.removeEventListener('blur', onMouseUp);
                        this._outerGlassPaneElement.style.pointerEvents = 'none';
                        this._outerGlassPaneElement.style.background = 'initial';
                        this._outerGlassPaneElement.removeAttribute('tabIndex');
                        this._outerGlassPaneElement.style.cursor = 'initial';
                    };
                    this._outerGlassPaneElement.addEventListener('mousemove', onMouseMove);
                    this._outerGlassPaneElement.addEventListener('mouseup', onMouseUp);
                    this._outerGlassPaneElement.addEventListener('blur', onMouseUp);
                });
                this._toolbar.$('#pw-button-inspect').addEventListener('click', () => {
                    if (this._toolbar.$('#pw-button-inspect').classList.contains('disabled'))
                        return;
                    this._toolbar.$('#pw-button-inspect').classList.toggle('toggled');
                    this._updateUIState({
                        mode: this._toolbar.$('#pw-button-inspect').classList.contains('toggled') ? 'inspecting' : 'none'
                    });
                });
                this._toolbar.$('#pw-button-record').addEventListener('click', () => this._toggleRecording());
                this._toolbar.$('#pw-button-resume').addEventListener('click', () => {
                    if (this._toolbar.$('#pw-button-resume').classList.contains('disabled'))
                        return;
                    this._updateUIState({ mode: 'none' });
                    window._playwrightResume().catch(() => { });
                });
                this._toolbar.$('#pw-button-playwright').addEventListener('click', () => {
                    if (this._toolbar.$('#pw-button-playwright').classList.contains('disabled'))
                        return;
                    this._toolbar.$('#pw-button-playwright').classList.toggle('toggled');
                    window._playwrightRecorderShowRecorderPage().catch(() => { });
                });
            }
            _refreshListenersIfNeeded() {
                if (document.documentElement[scriptSymbol])
                    return;
                document.documentElement[scriptSymbol] = true;
                removeEventListeners(this._listeners);
                this._listeners = [
                    addEventListener(document, 'click', event => this._onClick(event), true),
                    addEventListener(document, 'input', event => this._onInput(event), true),
                    addEventListener(document, 'keydown', event => this._onKeyDown(event), true),
                    addEventListener(document, 'keyup', event => this._onKeyUp(event), true),
                    addEventListener(document, 'mousedown', event => this._onMouseDown(event), true),
                    addEventListener(document, 'mouseup', event => this._onMouseUp(event), true),
                    addEventListener(document, 'mousemove', event => this._onMouseMove(event), true),
                    addEventListener(document, 'mouseleave', event => this._onMouseLeave(event), true),
                    addEventListener(document, 'focus', () => this._onFocus(), true),
                    addEventListener(document, 'scroll', () => {
                        this._hoveredModel = null;
                        this._updateHighlight();
                    }, true),
                ];
                document.documentElement.appendChild(this._outerGlassPaneElement);
                if (window.top === window) {
                    let moveCount = 0;
                    this._listeners.push(addEventListener(document, 'mousedown', e => moveCount = 0));
                    this._listeners.push(addEventListener(document, 'mousemove', e => {
                        ++moveCount;
                        if (++moveCount === 10)
                            this._ensureToolbarVisible();
                    }));
                }
            }
            _ensureToolbarVisible() {
                if (!this._outerToolbarElement.parentElement)
                    document.documentElement.appendChild(this._outerToolbarElement);
            }
            _toggleRecording() {
                this._toolbar.$('#pw-button-record').classList.toggle('toggled');
                this._updateUIState({
                    ...this._state.uiState,
                    mode: this._toolbar.$('#pw-button-record').classList.contains('toggled') ? 'recording' : 'none',
                });
            }
            async _updateUIState(uiState) {
                window._playwrightRecorderSetUIState(uiState).then(() => this._pollRecorderMode());
            }
            async _pollRecorderMode(skipAnimations = false) {
                if (this._pollRecorderModeTimer)
                    clearTimeout(this._pollRecorderModeTimer);
                const state = await window._playwrightRecorderState().catch(e => null);
                if (!state) {
                    this._pollRecorderModeTimer = setTimeout(() => this._pollRecorderMode(), 250);
                    return;
                }
                const { isPaused, uiState } = state;
                if (uiState.mode !== this._state.uiState.mode) {
                    this._state.uiState.mode = uiState.mode;
                    this._toolbar.$('#pw-button-inspect').classList.toggle('toggled', uiState.mode === 'inspecting');
                    this._toolbar.$('#pw-button-record').classList.toggle('toggled', uiState.mode === 'recording');
                    this._toolbar.$('#pw-button-resume').classList.toggle('disabled', uiState.mode === 'recording');
                    this._clearHighlight();
                }
                if (isPaused !== this._state.isPaused) {
                    this._state.isPaused = isPaused;
                    if (isPaused)
                        this._ensureToolbarVisible();
                    this._toolbar.$('#pw-button-resume-group').classList.toggle('hidden', !isPaused);
                }
                this._state = state;
                this._pollRecorderModeTimer = setTimeout(() => this._pollRecorderMode(), 250);
            }
            _clearHighlight() {
                this._hoveredModel = null;
                this._activeModel = null;
                this._updateHighlight();
            }
            _actionInProgress(event) {
                // If Playwright is performing action for us, bail.
                if (this._performingAction)
                    return true;
                // Consume as the first thing.
                consumeEvent(event);
                return false;
            }
            _consumedDueToNoModel(event, model) {
                if (model)
                    return false;
                consumeEvent(event);
                return true;
            }
            _consumedDueWrongTarget(event) {
                if (this._activeModel && this._activeModel.elements[0] === this._deepEventTarget(event))
                    return false;
                consumeEvent(event);
                return true;
            }
            _onClick(event) {
                if (this._state.uiState.mode === 'inspecting' && !this._isInToolbar(event.target)) {
                    if (this._hoveredModel) {
                        copy(this._hoveredModel.selector);
                        window._playwrightRecorderPrintSelector(this._hoveredModel.selector);
                    }
                }
                if (this._shouldIgnoreMouseEvent(event))
                    return;
                if (this._actionInProgress(event))
                    return;
                if (this._consumedDueToNoModel(event, this._hoveredModel))
                    return;
                const checkbox = asCheckbox(this._deepEventTarget(event));
                if (checkbox) {
                    // Interestingly, inputElement.checked is reversed inside this event handler.
                    this._performAction({
                        name: checkbox.checked ? 'check' : 'uncheck',
                        selector: this._hoveredModel.selector,
                        signals: [],
                    });
                    return;
                }
                this._performAction({
                    name: 'click',
                    selector: this._hoveredModel.selector,
                    signals: [],
                    button: buttonForEvent(event),
                    modifiers: modifiersForEvent(event),
                    clickCount: event.detail
                });
            }
            _isInToolbar(element) {
                if (element && element.parentElement && element.parentElement.nodeName.toLowerCase().startsWith('x-pw-'))
                    return true;
                return !!element && element.nodeName.toLowerCase().startsWith('x-pw-');
            }
            _shouldIgnoreMouseEvent(event) {
                const target = this._deepEventTarget(event);
                if (this._isInToolbar(target))
                    return true;
                if (this._state.uiState.mode === 'none')
                    return true;
                if (this._state.uiState.mode === 'inspecting') {
                    consumeEvent(event);
                    return true;
                }
                const nodeName = target.nodeName;
                if (nodeName === 'SELECT')
                    return true;
                if (nodeName === 'INPUT' && ['date'].includes(target.type))
                    return true;
                return false;
            }
            _onMouseDown(event) {
                if (this._shouldIgnoreMouseEvent(event))
                    return;
                if (!this._performingAction)
                    consumeEvent(event);
                this._activeModel = this._hoveredModel;
            }
            _onMouseUp(event) {
                if (this._shouldIgnoreMouseEvent(event))
                    return;
                if (!this._performingAction)
                    consumeEvent(event);
            }
            _onMouseMove(event) {
                if (this._state.uiState.mode === 'none')
                    return;
                const target = this._deepEventTarget(event);
                if (this._isInToolbar(target))
                    return;
                if (this._hoveredElement === target)
                    return;
                this._hoveredElement = target;
                // Mouse moved -> mark last action as committed via committing a commit action.
                this._commitActionAndUpdateModelForHoveredElement();
            }
            _onMouseLeave(event) {
                // Leaving iframe.
                if (this._deepEventTarget(event).nodeType === Node.DOCUMENT_NODE) {
                    this._hoveredElement = null;
                    this._commitActionAndUpdateModelForHoveredElement();
                }
            }
            _onFocus() {
                const activeElement = this._deepActiveElement(document);
                const result = activeElement ? selectorGenerator_1.generateSelector(this._injectedScript, activeElement) : null;
                this._activeModel = result && result.selector ? result : null;
                if (window._highlightUpdatedForTest)
                    window._highlightUpdatedForTest(result ? result.selector : null);
            }
            _commitActionAndUpdateModelForHoveredElement() {
                if (!this._hoveredElement) {
                    this._hoveredModel = null;
                    this._updateHighlight();
                    return;
                }
                const hoveredElement = this._hoveredElement;
                const { selector, elements } = selectorGenerator_1.generateSelector(this._injectedScript, hoveredElement);
                if ((this._hoveredModel && this._hoveredModel.selector === selector) || this._hoveredElement !== hoveredElement)
                    return;
                window._playwrightRecorderCommitAction();
                this._hoveredModel = selector ? { selector, elements } : null;
                this._updateHighlight();
                if (window._highlightUpdatedForTest)
                    window._highlightUpdatedForTest(selector);
            }
            _updateHighlight() {
                const elements = this._hoveredModel ? this._hoveredModel.elements : [];
                // Code below should trigger one layout and leave with the
                // destroyed layout.
                // Destroy the layout
                this._tooltipElement.textContent = this._hoveredModel ? this._hoveredModel.selector : '';
                this._tooltipElement.style.top = '0';
                this._tooltipElement.style.left = '0';
                this._tooltipElement.style.display = 'flex';
                // Trigger layout.
                const boxes = elements.map(e => e.getBoundingClientRect());
                const tooltipWidth = this._tooltipElement.offsetWidth;
                const tooltipHeight = this._tooltipElement.offsetHeight;
                const totalWidth = this._innerGlassPaneElement.offsetWidth;
                const totalHeight = this._innerGlassPaneElement.offsetHeight;
                // Destroy the layout again.
                if (boxes.length) {
                    const primaryBox = boxes[0];
                    let anchorLeft = primaryBox.left;
                    if (anchorLeft + tooltipWidth > totalWidth - 5)
                        anchorLeft = totalWidth - tooltipWidth - 5;
                    let anchorTop = primaryBox.bottom + 5;
                    if (anchorTop + tooltipHeight > totalHeight - 5) {
                        // If can't fit below, either position above...
                        if (primaryBox.top > tooltipHeight + 5) {
                            anchorTop = primaryBox.top - tooltipHeight - 5;
                        }
                        else {
                            // Or on top in case of large element
                            anchorTop = totalHeight - 5 - tooltipHeight;
                        }
                    }
                    this._tooltipElement.style.top = anchorTop + 'px';
                    this._tooltipElement.style.left = anchorLeft + 'px';
                }
                else {
                    this._tooltipElement.style.display = 'none';
                }
                const pool = this._highlightElements;
                this._highlightElements = [];
                for (const box of boxes) {
                    const highlightElement = pool.length ? pool.shift() : this._createHighlightElement();
                    highlightElement.style.backgroundColor = this._highlightElements.length ? '#f6b26b7f' : '#6fa8dc7f';
                    highlightElement.style.left = box.x + 'px';
                    highlightElement.style.top = box.y + 'px';
                    highlightElement.style.width = box.width + 'px';
                    highlightElement.style.height = box.height + 'px';
                    highlightElement.style.display = 'block';
                    this._highlightElements.push(highlightElement);
                }
                for (const highlightElement of pool) {
                    highlightElement.style.display = 'none';
                    this._highlightElements.push(highlightElement);
                }
            }
            _createHighlightElement() {
                const highlightElement = html_1.html `
      <x-pw-highlight style="
        position: absolute;
        top: 0;
        left: 0;
        width: 0;
        height: 0;
        box-sizing: border-box;">
      </x-pw-highlight>`;
                this._glassPaneShadow.appendChild(highlightElement);
                return highlightElement;
            }
            _onInput(event) {
                if (this._state.uiState.mode !== 'recording')
                    return true;
                const target = this._deepEventTarget(event);
                if (['INPUT', 'TEXTAREA'].includes(target.nodeName)) {
                    const inputElement = target;
                    const elementType = (inputElement.type || '').toLowerCase();
                    if (elementType === 'checkbox') {
                        // Checkbox is handled in click, we can't let input trigger on checkbox - that would mean we dispatched click events while recording.
                        return;
                    }
                    if (elementType === 'file') {
                        window._playwrightRecorderRecordAction({
                            name: 'setInputFiles',
                            selector: this._activeModel.selector,
                            signals: [],
                            files: [...(inputElement.files || [])].map(file => file.name),
                        });
                        return;
                    }
                    // Non-navigating actions are simply recorded by Playwright.
                    if (this._consumedDueWrongTarget(event))
                        return;
                    window._playwrightRecorderRecordAction({
                        name: 'fill',
                        selector: this._activeModel.selector,
                        signals: [],
                        text: inputElement.value,
                    });
                }
                if (target.nodeName === 'SELECT') {
                    const selectElement = target;
                    if (this._actionInProgress(event))
                        return;
                    this._performAction({
                        name: 'select',
                        selector: this._hoveredModel.selector,
                        options: [...selectElement.selectedOptions].map(option => option.value),
                        signals: []
                    });
                }
            }
            _shouldGenerateKeyPressFor(event) {
                // Backspace, Delete are changing input, will handle it there.
                if (['Backspace', 'Delete'].includes(event.key))
                    return false;
                // Ignore the QWERTZ shortcut for creating a at sign on MacOS
                if (event.key === '@' && event.code === 'KeyL')
                    return false;
                // Allow and ignore common used shortcut for pasting.
                if (navigator.platform.includes('Mac')) {
                    if (event.key === 'v' && event.metaKey)
                        return false;
                }
                else {
                    if (event.key === 'v' && event.ctrlKey)
                        return false;
                    if (event.key === 'Insert' && event.shiftKey)
                        return false;
                }
                if (['Shift', 'Control', 'Meta', 'Alt'].includes(event.key))
                    return false;
                const hasModifier = event.ctrlKey || event.altKey || event.metaKey;
                if (event.key.length === 1 && !hasModifier)
                    return !!asCheckbox(this._deepEventTarget(event));
                return true;
            }
            _onKeyDown(event) {
                if (this._state.uiState.mode === 'inspecting') {
                    consumeEvent(event);
                    return;
                }
                if (this._state.uiState.mode !== 'recording')
                    return true;
                if (!this._shouldGenerateKeyPressFor(event))
                    return;
                if (this._actionInProgress(event)) {
                    this._expectProgrammaticKeyUp = true;
                    return;
                }
                if (this._consumedDueWrongTarget(event))
                    return;
                // Similarly to click, trigger checkbox on key event, not input.
                if (event.key === ' ') {
                    const checkbox = asCheckbox(this._deepEventTarget(event));
                    if (checkbox) {
                        this._performAction({
                            name: checkbox.checked ? 'uncheck' : 'check',
                            selector: this._activeModel.selector,
                            signals: [],
                        });
                        return;
                    }
                }
                this._performAction({
                    name: 'press',
                    selector: this._activeModel.selector,
                    signals: [],
                    key: event.key,
                    modifiers: modifiersForEvent(event),
                });
            }
            _onKeyUp(event) {
                if (!this._shouldGenerateKeyPressFor(event))
                    return;
                // Only allow programmatic keyups, ignore user input.
                if (!this._expectProgrammaticKeyUp) {
                    consumeEvent(event);
                    return;
                }
                this._expectProgrammaticKeyUp = false;
            }
            async _performAction(action) {
                this._performingAction = true;
                await window._playwrightRecorderPerformAction(action).catch(() => { });
                this._performingAction = false;
                // Action could have changed DOM, update hovered model selectors.
                this._commitActionAndUpdateModelForHoveredElement();
                // If that was a keyboard action, it similarly requires new selectors for active model.
                this._onFocus();
                if (window._actionPerformedForTest) {
                    window._actionPerformedForTest({
                        hovered: this._hoveredModel ? this._hoveredModel.selector : null,
                        active: this._activeModel ? this._activeModel.selector : null,
                    });
                }
            }
            _deepEventTarget(event) {
                return event.composedPath()[0];
            }
            _deepActiveElement(document) {
                let activeElement = document.activeElement;
                while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement)
                    activeElement = activeElement.shadowRoot.activeElement;
                return activeElement;
            }
        }
        exports.Recorder = Recorder;
        function modifiersForEvent(event) {
            return (event.altKey ? 1 : 0) | (event.ctrlKey ? 2 : 0) | (event.metaKey ? 4 : 0) | (event.shiftKey ? 8 : 0);
        }
        function buttonForEvent(event) {
            switch (event.which) {
                case 1: return 'left';
                case 2: return 'middle';
                case 3: return 'right';
            }
            return 'left';
        }
        function consumeEvent(e) {
            e.preventDefault();
            e.stopPropagation();
            e.stopImmediatePropagation();
        }
        function asCheckbox(node) {
            if (!node || node.nodeName !== 'INPUT')
                return null;
            const inputElement = node;
            return inputElement.type === 'checkbox' ? inputElement : null;
        }
        function addEventListener(target, eventName, listener, useCapture) {
            target.addEventListener(eventName, listener, useCapture);
            const remove = () => {
                target.removeEventListener(eventName, listener, useCapture);
            };
            return remove;
        }
        function removeEventListeners(listeners) {
            for (const listener of listeners)
                listener();
            listeners.splice(0, listeners.length);
        }
        function copy(text) {
            const input = html_1.html `<textarea style="position: absolute; z-index: -1000;"></textarea>`;
            input.value = text;
            document.body.appendChild(input);
            input.select();
            document.execCommand('copy');
            input.remove();
        }
        function commonStyles() {
            return html_1.html `
<style>
* {
  box-sizing: border-box;
  min-width: 0;
  min-height: 0;
}
x-pw-toolbar {
  display: flex;
  align-items: center;
  fill: #333;
  flex: none;
  padding-top: 10px;
  cursor: grab;
}
x-pw-toolbar.vertical {
  flex-direction: column;
}
x-pw-button-group {
  display: flex;
  align-items: center;
  background-color: #ffffffe6;
  padding: 4px;
  border-radius: 22px;
  box-shadow: rgba(0, 0, 0, 0.1) 0px 0.25em 0.5em;
  margin: 4px 0px;
}
x-pw-toolbar.vertical x-pw-button-group {
  flex-direction: column;
}
x-pw-button {
  position: relative;
  width: 36px;
  height: 36px;
  background-position: center;
  background-repeat: no-repeat;
  border-radius: 16px;
  cursor: pointer;
  outline: none;
  display: flex;
  align-items: center;
  justify-content: center;
}
x-pw-button:hover:not(.disabled) {
  background-color: #f2f2f2;
}
x-pw-toolbar.dark x-pw-button {
  fill: #ccc;
}
x-pw-toolbar.dark x-pw-button:hover:not(.disabled) {
  background-color: inherit;
}
x-pw-toolbar.dark x-pw-button:hover:not(.disabled) {
  fill: #eee;
}
x-pw-toolbar.dark x-pw-button:active:not(.disabled) {
  fill: #fff;
}
x-pw-icon {
  width: 32px;
  height: 32px;
}
x-pw-button.toggled {
  fill: #468fd2;
}
.record-button {
  position: relative;
  background: #333;
  border-radius: 8px;
  width: 16px;
  height: 16px;
  pointer-events: none;
}
.record-button-glow {
  opacity: 0;
  background: red;
  border-radius: 9px;
  width: 18px;
  height: 18px;
  margin: -1px;
}
x-pw-button.record.toggled .record-button {
  background: red;
}
x-pw-button.record.toggled .record-button-glow {
  transition: opacity 0.3s;
  opacity: 0.7;
}
x-pw-button.disabled {
  fill: #777777 !important;
  cursor: inherit;
}
.hidden {
  display: none;
}
x-pw-button svg {
  pointer-events: none;
}
x-pw-icon svg {
  transform: scale(0.08);
  margin-left: -182px;
  margin-top: -182px;
}
</style>`;
        }
        exports.default = Recorder;
        /***/ 
    }),
    /***/ "./src/server/supplements/injected/selectorGenerator.ts": 
    /*!**************************************************************!*\
      !*** ./src/server/supplements/injected/selectorGenerator.ts ***!
      \**************************************************************/
    /*! no static exports found */
    /***/ (function (module, exports, __webpack_require__) {
        "use strict";
        /**
         * Copyright (c) Microsoft Corporation.
         *
         * Licensed under the Apache License, Version 2.0 (the "License");
         * you may not use this file except in compliance with the License.
         * You may obtain a copy of the License at
         *
         * http://www.apache.org/licenses/LICENSE-2.0
         *
         * Unless required by applicable law or agreed to in writing, software
         * distributed under the License is distributed on an "AS IS" BASIS,
         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
         * See the License for the specific language governing permissions and
         * limitations under the License.
         */
        Object.defineProperty(exports, "__esModule", { value: true });
        exports.generateSelector = void 0;
        function generateSelector(injectedScript, targetElement) {
            const path = [];
            let numberOfMatchingElements = Number.MAX_SAFE_INTEGER;
            for (let element = targetElement; element && element !== document.documentElement; element = parentElementOrShadowHost(element)) {
                const selector = buildSelectorCandidate(element);
                if (!selector)
                    continue;
                const fullSelector = joinSelector([selector, ...path]);
                const parsedSelector = injectedScript.parseSelector(fullSelector);
                const selectorTargets = injectedScript.querySelectorAll(parsedSelector, targetElement.ownerDocument);
                if (!selectorTargets.length)
                    break;
                if (selectorTargets[0] === targetElement)
                    return { selector: fullSelector, elements: selectorTargets };
                if (selectorTargets.length && numberOfMatchingElements > selectorTargets.length) {
                    numberOfMatchingElements = selectorTargets.length;
                    path.unshift(selector);
                }
            }
            if (document.documentElement === targetElement) {
                return {
                    selector: '/html',
                    elements: [document.documentElement]
                };
            }
            const selector = createXPath(document.documentElement, targetElement) ||
                cssSelectorForElement(injectedScript, targetElement);
            const parsedSelector = injectedScript.parseSelector(selector);
            return {
                selector,
                elements: injectedScript.querySelectorAll(parsedSelector, targetElement.ownerDocument)
            };
        }
        exports.generateSelector = generateSelector;
        function buildSelectorCandidate(element) {
            const nodeName = element.nodeName.toLowerCase();
            for (const attribute of ['data-testid', 'data-test-id', 'data-test']) {
                if (element.hasAttribute(attribute))
                    return { engine: 'css', selector: `${nodeName}[${attribute}=${quoteString(element.getAttribute(attribute))}]` };
            }
            for (const attribute of ['aria-label', 'role']) {
                if (element.hasAttribute(attribute))
                    return { engine: 'css', selector: `${element.nodeName.toLocaleLowerCase()}[${attribute}=${quoteString(element.getAttribute(attribute))}]` };
            }
            if (['INPUT', 'TEXTAREA'].includes(element.nodeName)) {
                const nodeNameLowercase = element.nodeName.toLowerCase();
                if (element.getAttribute('name'))
                    return { engine: 'css', selector: `${nodeNameLowercase}[name=${quoteString(element.getAttribute('name'))}]` };
                if (element.getAttribute('placeholder'))
                    return { engine: 'css', selector: `${nodeNameLowercase}[placeholder=${quoteString(element.getAttribute('placeholder'))}]` };
                if (element.getAttribute('type'))
                    return { engine: 'css', selector: `${nodeNameLowercase}[type=${quoteString(element.getAttribute('type'))}]` };
            }
            else if (element.nodeName === 'IMG') {
                if (element.getAttribute('alt'))
                    return { engine: 'css', selector: `img[alt=${quoteString(element.getAttribute('alt'))}]` };
            }
            const textSelector = textSelectorForElement(element);
            if (textSelector)
                return { engine: 'text', selector: textSelector };
            // De-prioritize id, but still use it as a last resort.
            const idAttr = element.getAttribute('id');
            if (idAttr && !isGuidLike(idAttr))
                return { engine: 'css', selector: `${nodeName}[id=${quoteString(idAttr)}]` };
            return null;
        }
        function parentElementOrShadowHost(element) {
            if (element.parentElement)
                return element.parentElement;
            if (!element.parentNode)
                return null;
            if (element.parentNode.nodeType === Node.DOCUMENT_FRAGMENT_NODE && element.parentNode.host)
                return element.parentNode.host;
            return null;
        }
        function cssSelectorForElement(injectedScript, targetElement) {
            const root = targetElement.ownerDocument;
            const tokens = [];
            function uniqueCSSSelector(prefix) {
                const path = tokens.slice();
                if (prefix)
                    path.unshift(prefix);
                const selector = path.join(' ');
                const parsedSelector = injectedScript.parseSelector(selector);
                const node = injectedScript.querySelector(parsedSelector, targetElement.ownerDocument);
                return node === targetElement ? selector : undefined;
            }
            for (let element = targetElement; element && element !== root; element = parentElementOrShadowHost(element)) {
                const nodeName = element.nodeName.toLowerCase();
                // Element ID is the strongest signal, use it.
                let bestTokenForLevel = '';
                if (element.id) {
                    const token = /^[a-zA-Z][a-zA-Z0-9\-\_]+$/.test(element.id) ? '#' + element.id : `[id="${element.id}"]`;
                    const selector = uniqueCSSSelector(token);
                    if (selector)
                        return selector;
                    bestTokenForLevel = token;
                }
                const parent = element.parentNode;
                // Combine class names until unique.
                const classes = Array.from(element.classList);
                for (let i = 0; i < classes.length; ++i) {
                    const token = '.' + classes.slice(0, i + 1).join('.');
                    const selector = uniqueCSSSelector(token);
                    if (selector)
                        return selector;
                    // Even if not unique, does this subset of classes uniquely identify node as a child?
                    if (!bestTokenForLevel && parent) {
                        const sameClassSiblings = parent.querySelectorAll(token);
                        if (sameClassSiblings.length === 1)
                            bestTokenForLevel = token;
                    }
                }
                // Ordinal is the weakest signal.
                if (parent) {
                    const siblings = Array.from(parent.children);
                    const sameTagSiblings = siblings.filter(sibling => (sibling).nodeName.toLowerCase() === nodeName);
                    const token = sameTagSiblings.indexOf(element) === 0 ? nodeName : `${nodeName}:nth-child(${1 + siblings.indexOf(element)})`;
                    const selector = uniqueCSSSelector(token);
                    if (selector)
                        return selector;
                    if (!bestTokenForLevel)
                        bestTokenForLevel = token;
                }
                else if (!bestTokenForLevel) {
                    bestTokenForLevel = nodeName;
                }
                tokens.unshift(bestTokenForLevel);
            }
            return uniqueCSSSelector();
        }
        function textSelectorForElement(node) {
            const maxLength = 30;
            let needsRegex = false;
            let trimmedText = null;
            for (const child of node.childNodes) {
                if (child.nodeType !== Node.TEXT_NODE)
                    continue;
                if (child.textContent && child.textContent.trim()) {
                    if (trimmedText)
                        return null;
                    trimmedText = child.textContent.trim().substr(0, maxLength);
                    needsRegex = child.textContent !== trimmedText;
                }
                else {
                    needsRegex = true;
                }
            }
            if (!trimmedText)
                return null;
            return needsRegex ? `/.*${escapeForRegex(trimmedText)}.*/` : `"${trimmedText}"`;
        }
        function escapeForRegex(text) {
            return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
        }
        function quoteString(text) {
            return `"${text.replaceAll(/"/g, '\\"')}"`;
        }
        function joinSelector(path) {
            const tokens = [];
            let lastEngine = '';
            for (const { engine, selector } of path) {
                if (tokens.length && (lastEngine !== 'css' || engine !== 'css'))
                    tokens.push('>>');
                lastEngine = engine;
                if (engine === 'css')
                    tokens.push(selector);
                else
                    tokens.push(`${engine}=${selector}`);
            }
            return tokens.join(' ');
        }
        function isGuidLike(id) {
            let lastCharacterType;
            let transitionCount = 0;
            for (let i = 0; i < id.length; ++i) {
                const c = id[i];
                let characterType;
                if (c === '-' || c === '_')
                    continue;
                if (c >= 'a' && c <= 'z')
                    characterType = 'lower';
                else if (c >= 'A' && c <= 'Z')
                    characterType = 'upper';
                else if (c >= '0' && c <= '9')
                    characterType = 'digit';
                else
                    characterType = 'other';
                if (characterType === 'lower' && lastCharacterType === 'upper') {
                    lastCharacterType = characterType;
                    continue;
                }
                if (lastCharacterType && lastCharacterType !== characterType)
                    ++transitionCount;
                lastCharacterType = characterType;
            }
            return transitionCount >= id.length / 4;
        }
        function createXPath(root, targetElement) {
            const maxTextLength = 80;
            const minMeaningfulSelectorLegth = 100;
            const maybeDocument = root instanceof Document ? root : root.ownerDocument;
            if (!maybeDocument)
                return;
            const document = maybeDocument;
            const xpathCache = new Map();
            const tokens = [];
            function evaluateXPath(expression) {
                let nodes = xpathCache.get(expression);
                if (!nodes) {
                    nodes = [];
                    try {
                        const result = document.evaluate(expression, root, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE);
                        for (let node = result.iterateNext(); node; node = result.iterateNext()) {
                            if (node.nodeType === Node.ELEMENT_NODE)
                                nodes.push(node);
                        }
                    }
                    catch (e) {
                    }
                    xpathCache.set(expression, nodes);
                }
                return nodes;
            }
            function uniqueXPathSelector(prefix) {
                const path = tokens.slice();
                if (prefix)
                    path.unshift(prefix);
                let selector = '//' + path.join('/');
                while (selector.includes('///'))
                    selector = selector.replace('///', '//');
                if (selector.endsWith('/'))
                    selector = selector.substring(0, selector.length - 1);
                const nodes = evaluateXPath(selector);
                if (nodes[0] === targetElement)
                    return selector;
                // If we are looking at a small set of elements with long selector, fall back to ordinal.
                if (nodes.length < 5 && selector.length > minMeaningfulSelectorLegth) {
                    const index = nodes.indexOf(targetElement);
                    if (index !== -1)
                        return `(${selector})[${index + 1}]`;
                }
                return undefined;
            }
            function escapeAndCap(text) {
                text = text.substring(0, maxTextLength);
                // XPath 1.0 does not support quote escaping.
                // 1. If there are no single quotes - use them.
                if (text.indexOf(`'`) === -1)
                    return `'${text}'`;
                // 2. If there are no double quotes - use them to enclose text.
                if (text.indexOf(`"`) === -1)
                    return `"${text}"`;
                // 3. Otherwise, use popular |concat| trick.
                const Q = `'`;
                return `concat(${text.split(Q).map(token => Q + token + Q).join(`, "'", `)})`;
            }
            const defaultAttributes = new Set(['title', 'aria-label', 'disabled', 'role']);
            const importantAttributes = new Map([
                ['form', ['action']],
                ['img', ['alt']],
                ['input', ['placeholder', 'type', 'name']],
                ['textarea', ['placeholder', 'type', 'name']],
            ]);
            let usedTextConditions = false;
            for (let element = targetElement; element && element !== root; element = element.parentElement) {
                const nodeName = element.nodeName.toLowerCase();
                const tag = nodeName === 'svg' ? '*' : nodeName;
                const tagConditions = [];
                if (nodeName === 'svg')
                    tagConditions.push('local-name()="svg"');
                const attrConditions = [];
                const importantAttrs = [...defaultAttributes, ...(importantAttributes.get(tag) || [])];
                for (const attr of importantAttrs) {
                    const value = element.getAttribute(attr);
                    if (value && value.length < maxTextLength)
                        attrConditions.push(`normalize-space(@${attr})=${escapeAndCap(value)}`);
                    else if (value)
                        attrConditions.push(`starts-with(normalize-space(@${attr}), ${escapeAndCap(value)})`);
                }
                const text = document.evaluate('normalize-space(.)', element).stringValue;
                const textConditions = [];
                if (tag !== 'select' && text.length && !usedTextConditions) {
                    if (text.length < maxTextLength)
                        textConditions.push(`normalize-space(.)=${escapeAndCap(text)}`);
                    else
                        textConditions.push(`starts-with(normalize-space(.), ${escapeAndCap(text)})`);
                    usedTextConditions = true;
                }
                // Always retain the last tag.
                const conditions = [...tagConditions, ...textConditions, ...attrConditions];
                const token = conditions.length ? `${tag}[${conditions.join(' and ')}]` : (tokens.length ? '' : tag);
                const selector = uniqueXPathSelector(token);
                if (selector)
                    return selector;
                const parent = element.parentElement;
                let ordinal = -1;
                if (parent) {
                    const siblings = Array.from(parent.children);
                    const sameTagSiblings = siblings.filter(sibling => (sibling).nodeName.toLowerCase() === nodeName);
                    if (sameTagSiblings.length > 1)
                        ordinal = sameTagSiblings.indexOf(element);
                }
                // Do not include text into this token, only tag / attributes.
                // Topmost node will get all the text.
                const conditionsString = conditions.length ? `[${conditions.join(' and ')}]` : '';
                const ordinalString = ordinal >= 0 ? `[${ordinal + 1}]` : '';
                tokens.unshift(`${tag}${ordinalString}${conditionsString}`);
            }
            return uniqueXPathSelector();
        }
        /***/ 
    })
    /******/ 
})["default"];
//# sourceMappingURL=recorderSource.js.map