"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.gatherIdentifiers = exports.isInReactiveStatement = exports.isReactiveStatement = void 0;
exports.getStartOfNode = getStartOfNode;
exports.findNodeAtOffsetRange = findNodeAtOffsetRange;
exports.gatherDescendants = gatherDescendants;
const svelte2tsx_1 = require("svelte2tsx");
/**
 * https://github.com/microsoft/typescript-go/blob/2a5e1cf9fe2261f2ad56871a6d2ed12d6ac34083/internal/scanner/scanner.go#L2473
 * TODO: check if it's added to the ast package
 */
function getStartOfNode(tsAstModule, node, sourceFile) {
    if (nodeIsMissing(tsAstModule, node)) {
        return node.pos;
    }
    if (tsAstModule.isJSDoc(node) || node.kind === tsAstModule.SyntaxKind.JSDocText) {
        return tsAstModule.skipTrivia(sourceFile.text, node.pos, 
        /*stopAfterLineBreak*/ false, 
        /*stopAtComments*/ true);
    }
    return tsAstModule.skipTrivia(sourceFile.text, node.pos, 
    /*stopAfterLineBreak*/ false, 
    /*stopAtComments*/ false, 
    /*inJSDoc*/ (node.flags & tsAstModule.NodeFlags.JSDoc) !== 0);
}
function nodeIsMissing(tsAstModule, node) {
    return (!node ||
        (node.pos === node.end && node.pos >= 0 && node.kind !== tsAstModule.SyntaxKind.EndOfFile));
}
function findNodeAtOffsetRange(tsAstModule, sourceFile, start, end) {
    const nearest = tsAstModule.getTouchingToken(sourceFile, start);
    if (nearest.end != end) {
        let current = nearest;
        while (current) {
            if (current.end === end) {
                return current;
            }
            current = current.parent;
        }
    }
}
/**
 * Tests a node then its parent and successive ancestors for some respective predicates.
 */
function nodeAndParentsSatisfyRespectivePredicates(selfPredicate, ...predicates) {
    return (tsAstModule, node) => {
        let next = node;
        return [selfPredicate, ...predicates].every((predicate) => {
            if (!next) {
                return false;
            }
            const current = next;
            next = next.parent;
            return predicate(tsAstModule, current);
        });
    };
}
const isRenderFunction = nodeAndParentsSatisfyRespectivePredicates((tsAstModule, node) => tsAstModule.isFunctionDeclaration(node) && node?.name?.text === svelte2tsx_1.internalHelpers.renderName, (tsAstModule, node) => node.kind === tsAstModule.SyntaxKind.SourceFile);
const isRenderFunctionBody = nodeAndParentsSatisfyRespectivePredicates((tsAstModule, node) => tsAstModule.isBlock(node), isRenderFunction);
exports.isReactiveStatement = nodeAndParentsSatisfyRespectivePredicates((tsAstModule, node) => tsAstModule.isLabeledStatement(node) && node.label.text === '$', or(
// function $$render() {
//     $: x2 = __sveltets_2_invalidate(() => x * x)
// }
isRenderFunctionBody, 
// function $$render() {
//     ;() => {$: x, update();
// }
nodeAndParentsSatisfyRespectivePredicates((tsAstModule, node) => tsAstModule.isBlock(node), (tsAstModule, node) => tsAstModule.isArrowFunction(node), (tsAstModule, node) => tsAstModule.isExpressionStatement(node), isRenderFunctionBody)));
function or(...predicates) {
    return (tsAstModule, node) => predicates.some((predicate) => predicate(tsAstModule, node));
}
function isSomeAncestor(tsAstModule, node, predicate) {
    for (let parent = node.parent; parent; parent = parent.parent) {
        if (predicate(tsAstModule, parent)) {
            return true;
        }
    }
    return false;
}
const isInReactiveStatement = (tsAstModule, node) => isSomeAncestor(tsAstModule, node, exports.isReactiveStatement);
exports.isInReactiveStatement = isInReactiveStatement;
function gatherDescendants(tsAstModule, node, predicate, dest = []) {
    if (predicate(tsAstModule, node)) {
        dest.push(node);
    }
    else {
        node.forEachChild((child) => {
            gatherDescendants(tsAstModule, child, predicate, dest);
        });
    }
    return dest;
}
const gatherIdentifiers = (tsAstModule, node) => gatherDescendants(tsAstModule, node, (tsAstModule, node) => tsAstModule.isIdentifier(node));
exports.gatherIdentifiers = gatherIdentifiers;
//# sourceMappingURL=utils.js.map