"use strict";
/*
 * Copyright OpenSearch Contributors
 * SPDX-License-Identifier: Apache-2.0
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.replaceWildcardAsymmetryDetector = void 0;
exports.countUnescapedWildcards = countUnescapedWildcards;
const rule_index_1 = require("../rule_index");
const range_utils_1 = require("../range_utils");
// Engine ground truth: replace throws IllegalArgumentException (wildcard
// symmetry validation) when the replacement wildcard count differs from the
// pattern count and is non-zero. Not caught by the Calcite-to-v2 fallback
// (default plugins.calcite.fallback.allowed=false). `replace` is Calcite-only
// and runtime-only.
/** Count unescaped `*` occurrences in a string, excluding `\*`. Exported for unit tests. */
function countUnescapedWildcards(text) {
    let count = 0;
    for (let i = 0; i < text.length; i++) {
        if (text[i] === '*') {
            // An odd number of preceding backslashes means the `*` is escaped.
            let backslashes = 0;
            let j = i - 1;
            while (j >= 0 && text[j] === '\\') {
                backslashes++;
                j--;
            }
            if (backslashes % 2 === 0) {
                count++;
            }
        }
    }
    return count;
}
const replaceWildcardAsymmetryDetector = (tree, config, context, ruleNameToIndex) => {
    // Runtime-only + Calcite-gated. `replacePair` is absent on the compiled
    // surface → findAllDescendantsByRule returns [] → clean no-op.
    if (context.isCalcite !== true) {
        return [];
    }
    const diagnostics = [];
    const pairs = (0, rule_index_1.findAllDescendantsByRule)(tree, ruleNameToIndex, 'replacePair');
    for (const pair of pairs) {
        const literals = (0, rule_index_1.findAllChildrenByRule)(pair, ruleNameToIndex, 'stringLiteral');
        if (literals.length < 2) {
            continue;
        }
        // getText() returns the raw literal, so countUnescapedWildcards sees escapes
        // exactly as written in the query (e.g. `\*` stays escaped, `\\*` is a real
        // wildcard) — the same view the user sees in the editor, which is what we
        // want to lint against.
        const patternText = (0, range_utils_1.unquote)(literals[0].getText());
        const replacementText = (0, range_utils_1.unquote)(literals[1].getText());
        const patternCount = countUnescapedWildcards(patternText);
        const replacementCount = countUnescapedWildcards(replacementText);
        if (replacementCount !== 0 && replacementCount !== patternCount) {
            diagnostics.push({
                ruleId: config.id,
                severity: config.severity,
                message: config.message,
                range: (0, range_utils_1.rangeFromContext)(pair),
                docUrl: config.docUrl,
                hoverFacts: { patternWildcards: patternCount, replacementWildcards: replacementCount },
            });
        }
    }
    return diagnostics;
};
exports.replaceWildcardAsymmetryDetector = replaceWildcardAsymmetryDetector;
//# sourceMappingURL=replace_wildcard_asymmetry.js.map