"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.IfAllCondition = exports.IfOnlyExistCondition = exports.UnlessExistCondition = exports.IfExistCondition = void 0;
const typy_1 = require("typy");
const node_query_1 = __importDefault(require("@synvert-hq/node-query"));
const utils_1 = require("./utils");
/**
* Condition is used to check if the node matches, condition won’t change the node scope.
*/
class Condition {
/**
* Create a Condition
* @param {Instance} instance
* @param {string|Object} nqlOrRules - nql or rules to find nodes
* @param {ConditionOptions} options - to do find in specific child node, e.g. `{ in: 'callee' }`
* @param {Function} func - a function to be called if nql or rules are matched.
* @param {Function} elseFunc - a function to be called if nql or rules are not matched.
*/
constructor(instance, nqlOrRules, options, func, elseFunc) {
this.instance = instance;
this.nodeQuery = new node_query_1.default(nqlOrRules, { adapter: instance.parser });
this.options = options;
this.func = func;
this.elseFunc = elseFunc;
}
/**
* If condition matches, run the func.
*/
processSync() {
if (this.match()) {
this.func.call(this.instance, this.instance);
}
else if (this.elseFunc) {
this.elseFunc.call(this.instance, this.instance);
}
}
process() {
return __awaiter(this, void 0, void 0, function* () {
if (this.match()) {
yield this.func.call(this.instance, this.instance);
}
else if (this.elseFunc) {
yield this.elseFunc.call(this.instance, this.instance);
}
});
}
/**
* Get the target node to process.
* If `option.in` exists, the target node depends on `options.in`,
* otherwise the target node is the current node.
* e.g. source code of the node is `$.ajax({})` and `options` is `{ in: 'callee' }`
* the target node is `$.ajax`.
* @private
* @returns {T}
*/
targetNode() {
if (this.options.in) {
return (0, typy_1.t)(this.instance.currentNode, this.options.in).safeObject;
}
return this.instance.currentNode;
}
}
/**
* IfExistCondition checks if matching node exists in the node children.
* @extends Condition
*/
class IfExistCondition extends Condition {
/**
* Check if any child node matches.
*/
match() {
const targetNode = this.targetNode();
if (!targetNode)
return false;
const matchingNodes = this.nodeQuery.queryNodes(targetNode, {
includingSelf: false,
stopAtFirstMatch: true,
});
return matchingNodes.length > 0;
}
}
exports.IfExistCondition = IfExistCondition;
/**
* UnlessExistCondition checks if matching node doesn't exist in the node children.
* @extends Condition
*/
class UnlessExistCondition extends Condition {
/**
* Check if none of child node matches.
*/
match() {
const targetNode = this.targetNode();
if (!targetNode)
return true;
const matchingNodes = this.nodeQuery.queryNodes(targetNode, {
includingSelf: false,
stopAtFirstMatch: true,
});
return matchingNodes.length === 0;
}
}
exports.UnlessExistCondition = UnlessExistCondition;
/**
* IfOnlyExistCondition checks if node has only one child node and the child node matches.
* @extends Condition
*/
class IfOnlyExistCondition extends Condition {
/**
* Check if only have one child node and the child node matches.
*/
match() {
const targetNode = this.targetNode();
if (!targetNode)
return false;
const body = (0, utils_1.arrayBody)(targetNode, this.nodeQuery.adapter);
return body.length === 1 && this.nodeQuery.matchNode(body[0]);
}
}
exports.IfOnlyExistCondition = IfOnlyExistCondition;
/**
* IfAllCondition checks if all matching nodes match options.match.
* @extends Condition
*/
class IfAllCondition extends Condition {
/**
* Find all matching nodes, if all match options.match, run the func, else run the elseFunc.
*/
match() {
const targetNode = this.targetNode();
if (!targetNode)
return false;
const nodes = this.nodeQuery.queryNodes(targetNode, {
includingSelf: false,
});
if (nodes.length === 0) {
return false;
}
return nodes.every(this._matchFunc.bind(this));
}
/**
* Function to match node.
* @private
* @param {T} node
* @returns {boolean} true if node matches
*/
_matchFunc(node) {
if (typeof this.options.match === "function") {
return this.options.match(node);
}
else {
return new node_query_1.default(this.options.match, {
adapter: this.instance.parser,
}).matchNode(node);
}
}
}
exports.IfAllCondition = IfAllCondition;