"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/consoleApi.ts");
    /******/ 
})({
    /***/ "./src/server/supplements/injected/consoleApi.ts": 
    /*!*******************************************************!*\
      !*** ./src/server/supplements/injected/consoleApi.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.ConsoleAPI = void 0;
        const selectorGenerator_1 = __webpack_require__(/*! ./selectorGenerator */ "./src/server/supplements/injected/selectorGenerator.ts");
        class ConsoleAPI {
            constructor(injectedScript) {
                this._injectedScript = injectedScript;
                if (window.playwright)
                    return;
                window.playwright = {
                    $: (selector) => this._querySelector(selector),
                    $$: (selector) => this._querySelectorAll(selector),
                    inspect: (selector) => this._inspect(selector),
                    selector: (element) => this._selector(element),
                };
            }
            _querySelector(selector) {
                if (typeof selector !== 'string')
                    throw new Error(`Usage: playwright.query('Playwright >> selector').`);
                const parsed = this._injectedScript.parseSelector(selector);
                return this._injectedScript.querySelector(parsed, document);
            }
            _querySelectorAll(selector) {
                if (typeof selector !== 'string')
                    throw new Error(`Usage: playwright.$$('Playwright >> selector').`);
                const parsed = this._injectedScript.parseSelector(selector);
                return this._injectedScript.querySelectorAll(parsed, document);
            }
            _inspect(selector) {
                if (typeof window.inspect !== 'function')
                    return;
                if (typeof selector !== 'string')
                    throw new Error(`Usage: playwright.inspect('Playwright >> selector').`);
                window.inspect(this._querySelector(selector));
            }
            _selector(element) {
                if (!(element instanceof Element))
                    throw new Error(`Usage: playwright.selector(element).`);
                return selectorGenerator_1.generateSelector(this._injectedScript, element).selector;
            }
        }
        exports.ConsoleAPI = ConsoleAPI;
        exports.default = ConsoleAPI;
        /***/ 
    }),
    /***/ "./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=consoleApiSource.js.map