"use strict";
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
var __values = (this && this.__values) || function(o) {
    var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
    if (m) return m.call(o);
    if (o && typeof o.length === "number") return {
        next: function () {
            if (o && i >= o.length) o = void 0;
            return { value: o && o[i++], done: !o };
        }
    };
    throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
var __read = (this && this.__read) || function (o, n) {
    var m = typeof Symbol === "function" && o[Symbol.iterator];
    if (!m) return o;
    var i = m.call(o), r, ar = [], e;
    try {
        while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
    }
    catch (error) { e = { error: error }; }
    finally {
        try {
            if (r && !r.done && (m = i["return"])) m.call(i);
        }
        finally { if (e) throw e.error; }
    }
    return ar;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
        if (ar || !(i in from)) {
            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
            ar[i] = from[i];
        }
    }
    return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DEFAULT_CONTENT_IGNORELIST_WITH_STEPPERS = exports.autocaptureCompatibleElements = void 0;
exports.splitClassString = splitClassString;
exports.getClassNames = getClassNames;
exports.makeSafeText = makeSafeText;
exports.getSafeText = getSafeText;
exports.getEventTarget = getEventTarget;
exports.getParentElement = getParentElement;
exports.shouldCaptureDeadClick = shouldCaptureDeadClick;
exports.isTextSelectionTarget = isTextSelectionTarget;
exports.shouldCaptureRageclick = shouldCaptureRageclick;
exports.shouldSkipDeadClick = shouldSkipDeadClick;
exports.shouldCaptureDomEvent = shouldCaptureDomEvent;
exports.shouldCaptureElement = shouldCaptureElement;
exports.isSensitiveElement = isSensitiveElement;
exports.shouldCaptureValue = shouldCaptureValue;
exports.isAngularStyleAttr = isAngularStyleAttr;
exports.getDirectAndNestedSpanText = getDirectAndNestedSpanText;
exports.getNestedSpanText = getNestedSpanText;
exports.getElementsChainString = getElementsChainString;
var utils_1 = require("./utils");
var core_1 = require("@posthog/core");
var logger_1 = require("./utils/logger");
var globals_1 = require("./utils/globals");
var url_targeting_utils_1 = require("./utils/url-targeting-utils");
var element_utils_1 = require("./utils/element-utils");
var core_2 = require("@posthog/core");
function splitClassString(s) {
    return s ? (0, core_2.trim)(s).split(/\s+/) : [];
}
function checkForURLMatches(urlsList, instance) {
    var url = (0, url_targeting_utils_1.getTargetingUrl)(instance);
    return !!(url && urlsList && urlsList.some(function (regex) { return url.match(regex); }));
}
/*
 * Get the className of an element, accounting for edge cases where element.className is an object
 *
 * Because this is a string it can contain unexpected characters
 * So, this method safely splits the className and returns that array.
 */
function getClassNames(el) {
    var className = '';
    switch (typeof el.className) {
        case 'string':
            className = el.className;
            break;
        // TODO: when is this ever used?
        case 'object': // handle cases where className might be SVGAnimatedString or some other type
            className =
                (el.className && 'baseVal' in el.className ? el.className.baseVal : null) ||
                    el.getAttribute('class') ||
                    '';
            break;
        default:
            className = '';
    }
    return splitClassString(className);
}
function makeSafeText(s) {
    if ((0, core_1.isNullish)(s)) {
        return null;
    }
    return ((0, core_2.trim)(s)
        // scrub potentially sensitive values
        .split(/(\s+)/)
        .filter(function (s) { return shouldCaptureValue(s); })
        .join('')
        // normalize whitespace
        .replace(/[\r\n]/g, ' ')
        .replace(/[ ]+/g, ' ')
        // truncate
        .substring(0, 255));
}
/*
 * Get the direct text content of an element, protecting against sensitive data collection.
 * Concats textContent of each of the element's text node children; this avoids potential
 * collection of sensitive data that could happen if we used element.textContent and the
 * element had sensitive child elements, since element.textContent includes child content.
 * Scrubs values that look like they could be sensitive (i.e. cc or ssn number).
 * @param {Element} el - element to get the text of
 * @returns {string} the element's direct text content
 */
function getSafeText(el) {
    var elText = '';
    if (shouldCaptureElement(el) && !isSensitiveElement(el) && el.childNodes && el.childNodes.length) {
        (0, utils_1.each)(el.childNodes, function (child) {
            var _a;
            if ((0, element_utils_1.isTextNode)(child) && child.textContent) {
                elText += (_a = makeSafeText(child.textContent)) !== null && _a !== void 0 ? _a : '';
            }
        });
    }
    return (0, core_2.trim)(elText);
}
function getEventTarget(e) {
    var _a;
    // https://developer.mozilla.org/en-US/docs/Web/API/Event/target#Compatibility_notes
    if ((0, core_1.isUndefined)(e.target)) {
        return e.srcElement || null;
    }
    else {
        if ((_a = e.target) === null || _a === void 0 ? void 0 : _a.shadowRoot) {
            return e.composedPath()[0] || null;
        }
        return e.target || null;
    }
}
exports.autocaptureCompatibleElements = ['a', 'button', 'form', 'input', 'select', 'textarea', 'label'];
/*
 if there is no config, then all elements are allowed
 if there is a config, and there is an allow list, then only elements in the allow list are allowed
 assumes that some other code is checking this element's parents
 */
function checkIfElementTreePassesElementAllowList(elements, autocaptureConfig) {
    var e_1, _a;
    var allowlist = autocaptureConfig === null || autocaptureConfig === void 0 ? void 0 : autocaptureConfig.element_allowlist;
    if ((0, core_1.isUndefined)(allowlist)) {
        // everything is allowed, when there is no allow list
        return true;
    }
    var _loop_1 = function (el) {
        if (allowlist.some(function (elementType) { return el.tagName.toLowerCase() === elementType; })) {
            return { value: true };
        }
    };
    try {
        // check each element in the tree
        // if any of the elements are in the allow list, then the tree is allowed
        for (var elements_1 = __values(elements), elements_1_1 = elements_1.next(); !elements_1_1.done; elements_1_1 = elements_1.next()) {
            var el = elements_1_1.value;
            var state_1 = _loop_1(el);
            if (typeof state_1 === "object")
                return state_1.value;
        }
    }
    catch (e_1_1) { e_1 = { error: e_1_1 }; }
    finally {
        try {
            if (elements_1_1 && !elements_1_1.done && (_a = elements_1.return)) _a.call(elements_1);
        }
        finally { if (e_1) throw e_1.error; }
    }
    // otherwise there is an allow list and this element tree didn't match it
    return false;
}
function elementMatchesCSSSelector(el, selector) {
    var matches = el.matches ||
        el.matchesSelector ||
        el.msMatchesSelector ||
        el.mozMatchesSelector ||
        el.webkitMatchesSelector ||
        el.oMatchesSelector;
    try {
        return matches ? matches.call(el, selector) : false;
    }
    catch (_a) {
        return false;
    }
}
/*
 if there is no selector list (i.e. it is undefined), then any elements matches
 if there is an empty list, then no elements match
 if there is a selector list, then check it against each element provided
 */
function checkIfElementsMatchCSSSelector(elements, selectorList) {
    var e_2, _a;
    if ((0, core_1.isUndefined)(selectorList)) {
        // everything is allowed, when there is no selector list
        return true;
    }
    var _loop_2 = function (el) {
        if (selectorList.some(function (selector) { return elementMatchesCSSSelector(el, selector); })) {
            return { value: true };
        }
    };
    try {
        for (var elements_2 = __values(elements), elements_2_1 = elements_2.next(); !elements_2_1.done; elements_2_1 = elements_2.next()) {
            var el = elements_2_1.value;
            var state_2 = _loop_2(el);
            if (typeof state_2 === "object")
                return state_2.value;
        }
    }
    catch (e_2_1) { e_2 = { error: e_2_1 }; }
    finally {
        try {
            if (elements_2_1 && !elements_2_1.done && (_a = elements_2.return)) _a.call(elements_2);
        }
        finally { if (e_2) throw e_2.error; }
    }
    return false;
}
function getParentElement(curEl) {
    var parentNode = curEl.parentNode;
    if (!parentNode || !(0, element_utils_1.isElementNode)(parentNode))
        return false;
    return parentNode;
}
var DEFAULT_AUTOCAPTURE_IGNORE_LIST = ['.ph-no-autocapture', '[data-ph-no-autocapture]'];
var DEFAULT_CONTENT_IGNORELIST = ['next', 'previous', 'prev', '>', '<'];
// +/- steppers are built to be clicked repeatedly; enabled from the 2026-05-30 config defaults
exports.DEFAULT_CONTENT_IGNORELIST_WITH_STEPPERS = __spreadArray(__spreadArray([], __read(DEFAULT_CONTENT_IGNORELIST), false), ['+', '-', '−', '–'], false);
var MAX_CONTENT_IGNORELIST_ENTRIES = 10;
// symbol keywords (e.g. +, -, >) match exactly so we don't suppress "sign-up", "5 > 3", "C++", etc.
var matchesContentKeyword = function (text, keyword) {
    return /[a-z0-9]/i.test(keyword) ? text.includes(keyword) : text === keyword;
};
function shouldIgnoreByContent(contentIgnorelist, elementsWithText) {
    if (contentIgnorelist === false || (0, core_1.isUndefined)(contentIgnorelist)) {
        return false;
    }
    var keywords;
    if (contentIgnorelist === true) {
        keywords = DEFAULT_CONTENT_IGNORELIST;
    }
    else if ((0, core_1.isArray)(contentIgnorelist)) {
        if (contentIgnorelist.length > MAX_CONTENT_IGNORELIST_ENTRIES) {
            logger_1.logger.error("[PostHog] content_ignorelist array cannot exceed ".concat(MAX_CONTENT_IGNORELIST_ENTRIES, " items. Use css_selector_ignorelist for more complex matching."));
            return false;
        }
        keywords = contentIgnorelist.map(function (k) { return k.toLowerCase(); });
    }
    else {
        return false;
    }
    return elementsWithText.some(function (_a) {
        var safeText = _a.safeText, ariaLabel = _a.ariaLabel;
        return keywords.some(function (keyword) { return matchesContentKeyword(safeText, keyword) || matchesContentKeyword(ariaLabel, keyword); });
    });
}
// dead click capture does not run through autocapture's ph-no-capture check,
// so we include it here so that ph-no-capture also suppresses dead click capture
var DEFAULT_DEAD_CLICK_IGNORE_LIST = ['.ph-no-deadclick', '.ph-no-capture'];
function shouldCaptureDeadClick(el, _config) {
    var _a;
    if (!globals_1.window || cannotCheckForAutocapture(el)) {
        return false;
    }
    var selectorIgnoreList = (0, core_1.isBoolean)(_config)
        ? DEFAULT_DEAD_CLICK_IGNORE_LIST
        : ((_a = _config === null || _config === void 0 ? void 0 : _config.css_selector_ignorelist) !== null && _a !== void 0 ? _a : DEFAULT_DEAD_CLICK_IGNORE_LIST);
    var targetElementList = getElementAndParentsForElement(el, false).targetElementList;
    // we don't capture if we match the ignore list
    return !checkIfElementsMatchCSSSelector(targetElementList, selectorIgnoreList);
}
// autocapture check will already filter for ph-no-capture,
// but we include it here to protect against future changes accidentally removing that check
var DEFAULT_RAGE_CLICK_IGNORE_LIST = ['.ph-no-rageclick', '.ph-no-capture'];
var TEXT_SELECTION_INPUT_TYPES = ['', 'text', 'search', 'email', 'password', 'url', 'tel', 'number'];
function isContentEditableTarget(el) {
    var _a;
    if (el.isContentEditable) {
        return true;
    }
    var contentEditable = (_a = el.getAttribute) === null || _a === void 0 ? void 0 : _a.call(el, 'contenteditable');
    return contentEditable === 'true' || contentEditable === '';
}
// repeated fast clicks on a text-editing surface are double/triple-click text selection, not rage
function isTextSelectionTarget(el) {
    if (!el || !(0, element_utils_1.isElementNode)(el)) {
        return false;
    }
    if ((0, element_utils_1.isTag)(el, 'textarea')) {
        return true;
    }
    if ((0, element_utils_1.isTag)(el, 'input')) {
        return (0, core_2.includes)(TEXT_SELECTION_INPUT_TYPES, (el.getAttribute('type') || '').toLowerCase());
    }
    return isContentEditableTarget(el);
}
function shouldCaptureRageclick(el, _config) {
    var _a, _b;
    if (!globals_1.window || cannotCheckForAutocapture(el)) {
        return false;
    }
    var selectorIgnoreList;
    var contentIgnorelist;
    var ignoreTextSelection;
    if ((0, core_1.isBoolean)(_config)) {
        selectorIgnoreList = _config ? DEFAULT_RAGE_CLICK_IGNORE_LIST : false;
        // For backward compatibility, don't enable content or text-selection filtering for rageclick: true
        contentIgnorelist = undefined;
        ignoreTextSelection = false;
    }
    else {
        selectorIgnoreList = (_a = _config === null || _config === void 0 ? void 0 : _config.css_selector_ignorelist) !== null && _a !== void 0 ? _a : DEFAULT_RAGE_CLICK_IGNORE_LIST;
        contentIgnorelist = _config === null || _config === void 0 ? void 0 : _config.content_ignorelist;
        ignoreTextSelection = (_b = _config === null || _config === void 0 ? void 0 : _config.ignore_text_selection) !== null && _b !== void 0 ? _b : false;
    }
    if (selectorIgnoreList === false) {
        return false;
    }
    if (ignoreTextSelection && isTextSelectionTarget(el)) {
        return false;
    }
    // Traverse DOM once and cache element data to avoid redundant calls to getSafeText
    var targetElementList = getElementAndParentsForElement(el, false).targetElementList;
    var elementsWithText = targetElementList.map(function (element) {
        var _a;
        return ({
            safeText: getSafeText(element).toLowerCase(),
            ariaLabel: ((_a = element.getAttribute('aria-label')) === null || _a === void 0 ? void 0 : _a.toLowerCase().trim()) || '',
        });
    });
    if (shouldIgnoreByContent(contentIgnorelist, elementsWithText)) {
        return false;
    }
    // we don't capture if we match the ignore list
    return !checkIfElementsMatchCSSSelector(targetElementList, selectorIgnoreList);
}
var cannotCheckForAutocapture = function (el) {
    return !el || (0, element_utils_1.isTag)(el, 'html') || !(0, element_utils_1.isElementNode)(el);
};
var getElementAndParentsForElement = function (el, captureOnAnyElement) {
    if (!globals_1.window || cannotCheckForAutocapture(el)) {
        return { parentIsUsefulElement: false, targetElementList: [] };
    }
    var parentIsUsefulElement = false;
    var targetElementList = [el];
    var curEl = el;
    while (curEl.parentNode && !(0, element_utils_1.isTag)(curEl, 'body')) {
        if ((0, element_utils_1.isShadowRoot)(curEl.parentNode)) {
            targetElementList.push(curEl.parentNode.host);
            curEl = curEl.parentNode.host;
            continue;
        }
        var parentNode = getParentElement(curEl);
        if (!parentNode)
            break;
        if (captureOnAnyElement || exports.autocaptureCompatibleElements.indexOf(parentNode.tagName.toLowerCase()) > -1) {
            parentIsUsefulElement = true;
        }
        else {
            var compStyles = globals_1.window.getComputedStyle(parentNode);
            if (compStyles && compStyles.getPropertyValue('cursor') === 'pointer') {
                parentIsUsefulElement = true;
            }
        }
        targetElementList.push(parentNode);
        curEl = parentNode;
    }
    return { parentIsUsefulElement: parentIsUsefulElement, targetElementList: targetElementList };
};
// dead-click skips a click only when the click target is — or is inside — an <a>.
// Anchors navigate / download / open a new window via the browser, and we have no
// observable signal for those actions (no DOM mutation, no scroll). For every other
// element (button, input, select, textarea, label, custom JS-handled divs, etc.) we
// rely on the existing mutation / scroll / selection / visibility observers — if the
// app's JS handler ran, those catch the effect; if it didn't, dead-click correctly
// surfaces the bug. A click on a broken <button> with no handler should still flag.
function shouldSkipDeadClick(el) {
    if (!globals_1.window || cannotCheckForAutocapture(el)) {
        return false;
    }
    var targetElementList = getElementAndParentsForElement(el, false).targetElementList;
    return targetElementList.some(function (node) { return (0, element_utils_1.isTag)(node, 'a'); });
}
/*
 * Check whether a DOM event should be "captured" or if it may contain sensitive data
 * using a variety of heuristics.
 * @param {Element} el - element to check
 * @param {Event} event - event to check
 * @param {Object} autocaptureConfig - autocapture config
 * @param {boolean} captureOnAnyElement - whether to capture on any element, clipboard autocapture doesn't restrict to "clickable" elements
 * @param {string[]} allowedEventTypes - event types to capture, normally just 'click', but some autocapture types react to different events, some elements have fixed events (e.g., form has "submit")
 * @returns {boolean} whether the event should be captured
 */
function shouldCaptureDomEvent(el, event, autocaptureConfig, captureOnAnyElement, allowedEventTypes, instance) {
    var _a;
    if (autocaptureConfig === void 0) { autocaptureConfig = undefined; }
    if (!globals_1.window || cannotCheckForAutocapture(el)) {
        return false;
    }
    if (autocaptureConfig === null || autocaptureConfig === void 0 ? void 0 : autocaptureConfig.url_allowlist) {
        // if the current URL is not in the allow list, don't capture
        if (!checkForURLMatches(autocaptureConfig.url_allowlist, instance)) {
            return false;
        }
    }
    if (autocaptureConfig === null || autocaptureConfig === void 0 ? void 0 : autocaptureConfig.url_ignorelist) {
        // if the current URL is in the ignore list, don't capture
        if (checkForURLMatches(autocaptureConfig.url_ignorelist, instance)) {
            return false;
        }
    }
    if (autocaptureConfig === null || autocaptureConfig === void 0 ? void 0 : autocaptureConfig.dom_event_allowlist) {
        var allowlist = autocaptureConfig.dom_event_allowlist;
        if (allowlist && !allowlist.some(function (eventType) { return event.type === eventType; })) {
            return false;
        }
    }
    var _b = getElementAndParentsForElement(el, captureOnAnyElement), parentIsUsefulElement = _b.parentIsUsefulElement, targetElementList = _b.targetElementList;
    if (!checkIfElementTreePassesElementAllowList(targetElementList, autocaptureConfig)) {
        return false;
    }
    if (!checkIfElementsMatchCSSSelector(targetElementList, autocaptureConfig === null || autocaptureConfig === void 0 ? void 0 : autocaptureConfig.css_selector_allowlist)) {
        return false;
    }
    var selectorIgnoreList = (_a = autocaptureConfig === null || autocaptureConfig === void 0 ? void 0 : autocaptureConfig.css_selector_ignorelist) !== null && _a !== void 0 ? _a : DEFAULT_AUTOCAPTURE_IGNORE_LIST;
    if (checkIfElementsMatchCSSSelector(targetElementList, selectorIgnoreList)) {
        return false;
    }
    var compStyles = globals_1.window.getComputedStyle(el);
    if (compStyles && compStyles.getPropertyValue('cursor') === 'pointer' && event.type === 'click') {
        return true;
    }
    var tag = el.tagName.toLowerCase();
    switch (tag) {
        case 'html':
            return false;
        case 'form':
            return (allowedEventTypes || ['submit']).indexOf(event.type) >= 0;
        case 'input':
        case 'select':
        case 'textarea':
            return (allowedEventTypes || ['change', 'click']).indexOf(event.type) >= 0;
        default:
            if (parentIsUsefulElement)
                return (allowedEventTypes || ['click']).indexOf(event.type) >= 0;
            return ((allowedEventTypes || ['click']).indexOf(event.type) >= 0 &&
                (exports.autocaptureCompatibleElements.indexOf(tag) > -1 || el.getAttribute('contenteditable') === 'true'));
    }
}
/*
 * Check whether a DOM element should be "captured" or if it may contain sensitive data
 * using a variety of heuristics.
 * @param {Element} el - element to check
 * @returns {boolean} whether the element should be captured
 */
function shouldCaptureElement(el) {
    for (var curEl = el; curEl.parentNode && !(0, element_utils_1.isTag)(curEl, 'body'); curEl = curEl.parentNode) {
        var classes = getClassNames(curEl);
        if ((0, core_2.includes)(classes, 'ph-sensitive') || (0, core_2.includes)(classes, 'ph-no-capture')) {
            return false;
        }
    }
    if ((0, core_2.includes)(getClassNames(el), 'ph-include')) {
        return true;
    }
    // don't include hidden or password fields
    var type = el.type || '';
    if ((0, core_1.isString)(type)) {
        // it's possible for el.type to be a DOM element if el is a form with a child input[name="type"]
        switch (type.toLowerCase()) {
            case 'hidden':
                return false;
            case 'password':
                return false;
        }
    }
    // filter out data from fields that look like sensitive fields
    var name = el.name || el.id || '';
    // See https://github.com/posthog/posthog-js/issues/165
    // Under specific circumstances a bug caused .replace to be called on a DOM element
    // instead of a string, removing the element from the page. Ensure this issue is mitigated.
    if ((0, core_1.isString)(name)) {
        // it's possible for el.name or el.id to be a DOM element if el is a form with a child input[name="name"]
        var sensitiveNameRegex = /^cc|cardnum|ccnum|creditcard|csc|cvc|cvv|exp|pass|pwd|routing|seccode|securitycode|securitynum|socialsec|socsec|ssn/i;
        if (sensitiveNameRegex.test(name.replace(/[^a-zA-Z0-9]/g, ''))) {
            return false;
        }
    }
    return true;
}
/*
 * Check whether a DOM element is 'sensitive' and we should only capture limited data
 * @param {Element} el - element to check
 * @returns {boolean} whether the element should be captured
 */
function isSensitiveElement(el) {
    // don't send data from inputs or similar elements since there will always be
    // a risk of clientside javascript placing sensitive data in attributes
    var allowedInputTypes = ['button', 'checkbox', 'submit', 'reset'];
    if (((0, element_utils_1.isTag)(el, 'input') && !allowedInputTypes.includes(el.type)) ||
        (0, element_utils_1.isTag)(el, 'select') ||
        (0, element_utils_1.isTag)(el, 'textarea') ||
        el.getAttribute('contenteditable') === 'true') {
        return true;
    }
    return false;
}
// Define the core pattern for matching credit card numbers
var coreCCPattern = "(4[0-9]{12}(?:[0-9]{3})?)|(5[1-5][0-9]{14})|(6(?:011|5[0-9]{2})[0-9]{12})|(3[47][0-9]{13})|(3(?:0[0-5]|[68][0-9])[0-9]{11})|((?:2131|1800|35[0-9]{3})[0-9]{11})";
// Create the Anchored version of the regex by adding '^' at the start and '$' at the end
var anchoredCCRegex = new RegExp("^(?:".concat(coreCCPattern, ")$"));
// The Unanchored version is essentially the core pattern, usable as is for partial matches
var unanchoredCCRegex = new RegExp(coreCCPattern);
// Define the core pattern for matching SSNs with optional dashes
var coreSSNPattern = "\\d{3}-?\\d{2}-?\\d{4}";
// Create the Anchored version of the regex by adding '^' at the start and '$' at the end
var anchoredSSNRegex = new RegExp("^(".concat(coreSSNPattern, ")$"));
// The Unanchored version is essentially the core pattern itself, usable for partial matches
var unanchoredSSNRegex = new RegExp("(".concat(coreSSNPattern, ")"));
/*
 * Check whether a string value should be "captured" or if it may contain sensitive data
 * using a variety of heuristics.
 * @param {string} value - string value to check
 * @param {boolean} anchorRegexes - whether to anchor the regexes to the start and end of the string
 * @returns {boolean} whether the element should be captured
 */
function shouldCaptureValue(value, anchorRegexes) {
    if (anchorRegexes === void 0) { anchorRegexes = true; }
    if ((0, core_1.isNullish)(value)) {
        return false;
    }
    if ((0, core_1.isString)(value)) {
        value = (0, core_2.trim)(value);
        // check to see if input value looks like a credit card number
        // see: https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9781449327453/ch04s20.html
        var ccRegex = anchorRegexes ? anchoredCCRegex : unanchoredCCRegex;
        if (ccRegex.test((value || '').replace(/[- ]/g, ''))) {
            return false;
        }
        // check to see if input value looks like a social security number
        var ssnRegex = anchorRegexes ? anchoredSSNRegex : unanchoredSSNRegex;
        if (ssnRegex.test(value)) {
            return false;
        }
    }
    return true;
}
/*
 * Check whether an attribute name is an Angular style attr (either _ngcontent or _nghost)
 * These update on each build and lead to noise in the element chain
 * More details on the attributes here: https://angular.io/guide/view-encapsulation
 * @param {string} attributeName - string value to check
 * @returns {boolean} whether the element is an angular tag
 */
function isAngularStyleAttr(attributeName) {
    if ((0, core_1.isString)(attributeName)) {
        return attributeName.substring(0, 10) === '_ngcontent' || attributeName.substring(0, 7) === '_nghost';
    }
    return false;
}
/*
 * Iterate through children of a target element looking for span tags
 * and return the text content of the span tags, separated by spaces,
 * along with the direct text content of the target element
 * @param {Element} target - element to check
 * @returns {string} text content of the target element and its child span tags
 */
function getDirectAndNestedSpanText(target) {
    var text = getSafeText(target);
    text = "".concat(text, " ").concat(getNestedSpanText(target)).trim();
    return shouldCaptureValue(text) ? text : '';
}
/*
 * Iterate through children of a target element looking for span tags
 * and return the text content of the span tags, separated by spaces
 * @param {Element} target - element to check
 * @returns {string} text content of span tags
 */
function getNestedSpanText(target) {
    var text = '';
    if (target && target.childNodes && target.childNodes.length) {
        (0, utils_1.each)(target.childNodes, function (child) {
            var _a;
            if (child && ((_a = child.tagName) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'span') {
                try {
                    var spanText = getSafeText(child);
                    text = "".concat(text, " ").concat(spanText).trim();
                    if (child.childNodes && child.childNodes.length) {
                        text = "".concat(text, " ").concat(getNestedSpanText(child)).trim();
                    }
                }
                catch (e) {
                    logger_1.logger.error('[AutoCapture]', e);
                }
            }
        });
    }
    return text;
}
/*
Back in the day storing events in Postgres we use Elements for autocapture events.
Now we're using elements_chain. We used to do this parsing/processing during ingestion.
This code is just copied over from ingestion, but we should optimize it
to create elements_chain string directly.
*/
function getElementsChainString(elements) {
    return elementsToString(extractElements(elements));
}
function escapeQuotes(input) {
    return input.replace(/"|\\"/g, '\\"');
}
function elementsToString(elements) {
    var ret = elements.map(function (element) {
        var e_3, _a;
        var _b, _c;
        var el_string = '';
        if (element.tag_name) {
            el_string += element.tag_name;
        }
        if (element.attr_class) {
            element.attr_class.sort();
            try {
                for (var _d = __values(element.attr_class), _e = _d.next(); !_e.done; _e = _d.next()) {
                    var single_class = _e.value;
                    el_string += ".".concat(single_class.replace(/"/g, ''));
                }
            }
            catch (e_3_1) { e_3 = { error: e_3_1 }; }
            finally {
                try {
                    if (_e && !_e.done && (_a = _d.return)) _a.call(_d);
                }
                finally { if (e_3) throw e_3.error; }
            }
        }
        var attributes = __assign(__assign(__assign(__assign(__assign({}, (element.text ? { text: element.text } : {})), { 'nth-child': (_b = element.nth_child) !== null && _b !== void 0 ? _b : 0, 'nth-of-type': (_c = element.nth_of_type) !== null && _c !== void 0 ? _c : 0 }), (element.href ? { href: element.href } : {})), (element.attr_id ? { attr_id: element.attr_id } : {})), element.attributes);
        var sortedAttributes = {};
        (0, utils_1.entries)(attributes)
            .sort(function (_a, _b) {
            var _c = __read(_a, 1), a = _c[0];
            var _d = __read(_b, 1), b = _d[0];
            return a.localeCompare(b);
        })
            .forEach(function (_a) {
            var _b = __read(_a, 2), key = _b[0], value = _b[1];
            return (sortedAttributes[escapeQuotes(key.toString())] = escapeQuotes(value.toString()));
        });
        el_string += ':';
        el_string += (0, utils_1.entries)(sortedAttributes)
            .map(function (_a) {
            var _b = __read(_a, 2), key = _b[0], value = _b[1];
            return "".concat(key, "=\"").concat(value, "\"");
        })
            .join('');
        return el_string;
    });
    return ret.join(';');
}
function extractElements(elements) {
    return elements.map(function (el) {
        var _a, _b;
        var response = {
            text: (_a = el['$el_text']) === null || _a === void 0 ? void 0 : _a.slice(0, 400),
            tag_name: el['tag_name'],
            href: (_b = el['attr__href']) === null || _b === void 0 ? void 0 : _b.slice(0, 2048),
            attr_class: extractAttrClass(el),
            attr_id: el['attr__id'],
            nth_child: el['nth_child'],
            nth_of_type: el['nth_of_type'],
            attributes: {},
        };
        (0, utils_1.entries)(el)
            .filter(function (_a) {
            var _b = __read(_a, 1), key = _b[0];
            return key.indexOf('attr__') === 0;
        })
            .forEach(function (_a) {
            var _b = __read(_a, 2), key = _b[0], value = _b[1];
            return (response.attributes[key] = value);
        });
        return response;
    });
}
function extractAttrClass(el) {
    var attr_class = el['attr__class'];
    if (!attr_class) {
        return undefined;
    }
    else if ((0, core_1.isArray)(attr_class)) {
        return attr_class;
    }
    else {
        return splitClassString(attr_class);
    }
}
//# sourceMappingURL=autocapture-utils.js.map