scope.js

"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
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);
                });
            });
        });
    }
    process() {
        return __awaiter(this, void 0, void 0, function* () {
            const instance = this.instance;
            const currentNode = instance.currentNode;
            if (!currentNode) {
                return;
            }
            yield instance.processWithNode(currentNode, () => __awaiter(this, void 0, void 0, function* () {
                const matchingNodes = this.nodeQuery.queryNodes(currentNode, this.options);
                for (const matchingNode of matchingNodes) {
                    yield instance.processWithNode(matchingNode, () => __awaiter(this, void 0, void 0, function* () {
                        yield 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);
        });
    }
    process() {
        return __awaiter(this, void 0, void 0, function* () {
            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;
            yield this.instance.processWithOtherNode(childNode, () => __awaiter(this, void 0, void 0, function* () {
                yield this.func.call(this.instance, this.instance);
            }));
        });
    }
}
exports.GotoScope = GotoScope;