"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isInTag = isInTag;
exports.isAttributeName = isAttributeName;
exports.isAttributeShorthand = isAttributeShorthand;
exports.isEventHandler = isEventHandler;
exports.isElseBlockWithElseIf = isElseBlockWithElseIf;
exports.hasElseBlock = hasElseBlock;
exports.findElseBlockTagStart = findElseBlockTagStart;
exports.findIfBlockEndTagStart = findIfBlockEndTagStart;
exports.walkSvelteAst = walkSvelteAst;
exports.isAwaitBlock = isAwaitBlock;
exports.isEachBlock = isEachBlock;
const estree_walker_1 = require("estree-walker");
function matchesOnly(type, only) {
    return (!only ||
        // We hide the detail that body/window are also like elements in the context of this usage
        (only === 'Element' && ['Element', 'Body', 'Window'].includes(type)) ||
        (only === 'InlineComponent' && type === 'InlineComponent'));
}
/**
 * Returns true if given node is a component or html element, or if the offset is at the end of the node
 * and its parent is a component or html element.
 */
function isInTag(node, offset) {
    return (node?.type === 'InlineComponent' ||
        node?.type === 'Element' ||
        (node?.end === offset &&
            (node?.parent?.type === 'InlineComponent' || node?.parent?.type === 'Element')));
}
/**
 * Returns when given node represents an HTML Attribute.
 * Example: The `class` in `<div class=".."`.
 * Note: This method returns `false` for shorthands like `<div {foo}`.
 */
function isAttributeName(node, only) {
    return !!node && node.type === 'Attribute' && matchesOnly(node.parent?.type, only);
}
/**
 * Returns when given node represents an HTML Attribute shorthand or is inside one.
 * Example: The `{foo}` in `<div {foo}`
 */
function isAttributeShorthand(node, only) {
    if (!node) {
        return false;
    }
    do {
        // We could get the expression, or the shorthand, or the attribute
        // Be pragmatic and just go upwards until we can't anymore
        if (isAttributeName(node, only)) {
            return true;
        }
        node = node.parent;
    } while (node);
    return false;
}
/**
 * Returns when given node represents an HTML Attribute shorthand or is inside one.
 * Example: The `on:click={foo}` in `<div on:click={foo}`
 */
function isEventHandler(node, only) {
    return !!node && node.type === 'EventHandler' && matchesOnly(node.parent?.type, only);
}
function isElseBlockWithElseIf(node) {
    return (!!node &&
        node.type === 'ElseBlock' &&
        'children' in node &&
        Array.isArray(node.children) &&
        node.children.length === 1 &&
        node.children[0].type === 'IfBlock');
}
function hasElseBlock(node) {
    return 'else' in node && !!node.else;
}
function findElseBlockTagStart(documentText, elseBlock) {
    return documentText.lastIndexOf('{', documentText.lastIndexOf(':else', elseBlock.start));
}
function findIfBlockEndTagStart(documentText, ifBlock) {
    return documentText.lastIndexOf('{', documentText.lastIndexOf('/if', ifBlock.end));
}
// wrap the estree-walker to make it svelte specific
// the type casting is necessary because estree-walker is not designed for this
// especially in v3 which svelte 4 uses
function walkSvelteAst(htmlAst, walker) {
    (0, estree_walker_1.walk)(htmlAst, {
        enter(node, parent, key, index) {
            walker.enter?.call(this, node, parent, key, index);
        },
        leave(node, parent, key, index) {
            walker.leave?.call(this, node, parent, key, index);
        }
    });
}
function isAwaitBlock(node) {
    return node.type === 'AwaitBlock';
}
function isEachBlock(node) {
    return node.type === 'EachBlock';
}
//# sourceMappingURL=svelte-ast-utils.js.map