scope.js

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.GotoScope = exports.WithinScope = void 0;
const node_query_1 = __importDefault(require("@synvert-hq/node-query"));
/**
 * Scope just likes its name, different scope points to different current node.
 * One scope defines some rules, it finds nodes and changes current node to the matching node.
 */
class Scope {
    /**
     * Create a Scope
     * @param {Instance} instance
     */
    constructor(instance) {
        this.instance = instance;
    }
}
/**
 * WithinScope finds out nodes which match rules, then changes its scope to matching node.
 * @extends Scope
 */
class WithinScope extends Scope {
    /**
     * Create a WithinScope
     * @param {Instance} instance
     * @param {string|Object} nqlOrRules - nql or rules to find nodes.
     * @param {QueryOptions} options
     * @param {Function} func - a function to be called if rules are matched.
     */
    constructor(instance, nqlOrRules, options, func) {
        super(instance);
        this.func = func;
        this.nodeQuery = new node_query_1.default(nqlOrRules, { adapter: instance.parser });
        this.options = Object.assign({ includingSelf: true, stopAtFirstMatch: false, recursive: true }, options);
    }
    /**
     * Find out the matching nodes.
     * It checks the current node and iterates all child nodes,
     * then run the function code on each matching node.
     */
    processSync() {
        const instance = this.instance;
        const currentNode = instance.currentNode;
        if (!currentNode) {
            return;
        }
        instance.processWithNodeSync(currentNode, () => {
            this.nodeQuery
                .queryNodes(currentNode, this.options)
                .forEach((matchingNode) => {
                instance.processWithNodeSync(matchingNode, () => {
                    this.func.call(this.instance, this.instance);
                });
            });
        });
    }
    async process() {
        const instance = this.instance;
        const currentNode = instance.currentNode;
        if (!currentNode) {
            return;
        }
        await instance.processWithNode(currentNode, async () => {
            const matchingNodes = this.nodeQuery.queryNodes(currentNode, this.options);
            for (const matchingNode of matchingNodes) {
                await instance.processWithNode(matchingNode, async () => {
                    await this.func.call(this.instance, this.instance);
                });
            }
        });
    }
}
exports.WithinScope = WithinScope;
/**
 * Go to and change its scope to a child node.
 * @extends Scope
 */
class GotoScope extends Scope {
    /**
     * Create a GotoScope
     * @param {Instance} instance
     * @param {string} childNodeName
     * @param {Function} func
     */
    constructor(instance, childNodeName, func) {
        super(instance);
        this.childNodeName = childNodeName;
        this.func = func;
    }
    /**
     * Go to a child now, then run the func with the the child node.
     */
    processSync() {
        const currentNode = this.instance.currentNode;
        if (!currentNode)
            return;
        let childNode = currentNode;
        this.childNodeName.split(".").forEach((childNodeName) => {
            childNode =
                Array.isArray(childNode) && /-?d+/.test(childNodeName)
                    ? childNode[Number.parseInt(childNodeName)]
                    : childNode[childNodeName];
        });
        if (!childNode)
            return;
        this.instance.processWithOtherNodeSync(childNode, () => {
            this.func.call(this.instance, this.instance);
        });
    }
    async process() {
        const currentNode = this.instance.currentNode;
        if (!currentNode)
            return;
        let childNode = currentNode;
        this.childNodeName.split(".").forEach((childNodeName) => {
            childNode =
                Array.isArray(childNode) && /-?d+/.test(childNodeName)
                    ? childNode[Number.parseInt(childNodeName)]
                    : childNode[childNodeName];
        });
        if (!childNode)
            return;
        await this.instance.processWithOtherNode(childNode, async () => {
            await this.func.call(this.instance, this.instance);
        });
    }
}
exports.GotoScope = GotoScope;