syphonx-core
Version:
SyphonX is a template-driven solution for extracting data from HTML in a highly efficient way. It combines the power of jQuery, Regular Expressions, and Javascript into a declarative template-driven format that extracts and reshapes HTML data into JSON.
992 lines • 116 kB
JavaScript
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
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 __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Controller = void 0;
var defaultTimeoutSeconds = 30;
var errors_js_1 = require("./errors.js");
var index_js_1 = require("./lib/index.js");
var Controller = (function () {
function Controller(state) {
var _a, _b;
this.lastLogLine = "";
this.lastLogLength = 0;
this.lastLogTimestamp = 0;
this.lastStep = [];
this.step = [];
this.jquery = state.root || $;
this.online = typeof this.jquery.noConflict === "function";
if (this.online)
state.url = window.location.href;
var _c = (0, index_js_1.parseUrl)(state.url), domain = _c.domain, origin = _c.origin;
if (state.__locator) {
state.data = (0, index_js_1.merge)(state.data, state.__locator);
state.__locator = undefined;
}
var version = "1.2.80";
this.state = __assign(__assign({ params: {}, errors: [], log: "" }, state), { yield: undefined, vars: __assign(__assign({ __instance: 0, __context: [], __metrics: {}, __repeat: {}, __t0: Date.now(), __timeout: state.timeout || defaultTimeoutSeconds }, state.vars), { __step: [], __yield: (_a = state.yield) === null || _a === void 0 ? void 0 : _a.step }), domain: domain, origin: origin, version: version });
this.state.vars.__metrics = __assign({ actions: 0, clicks: 0, elapsed: 0, errors: 0, navigate: 0, queries: 0, renavigations: 0, retries: 0, skipped: 0, snooze: 0, steps: 0, timeouts: 0, waitfor: 0, yields: 0 }, (_b = state.vars) === null || _b === void 0 ? void 0 : _b.__metrics);
if (this.state.context) {
var $_1 = this.jquery;
var nodes = $_1(this.state.context);
var value = this.text(nodes);
this.state.vars.__context = [{ name: "context", nodes: nodes, value: value }];
}
}
Controller.prototype.appendError = function (code, message, level, stack) {
var key = this.contextKey();
this.state.errors.push({ code: code, message: message, key: key, level: level, stack: stack });
var text = "ERROR ".concat(key ? "".concat(key, ": ") : "").concat(message, " code=").concat(code, " level=").concat(level).concat(stack ? "\n".concat(stack) : "");
this.log(text);
};
Controller.prototype.break = function (_a) {
var _b = _a.name, name = _b === void 0 ? "" : _b, query = _a.query, _c = _a.on, on = _c === void 0 ? "any" : _c, pattern = _a.pattern, when = _a.when;
if (name)
name = " " + name;
if (this.online) {
if (this.when(when, "BREAK")) {
this.state.vars.__metrics.steps += 1;
if (query) {
this.log("BREAK".concat(name, " WAITFOR QUERY ").concat((0, index_js_1.trunc)($), " on=").concat(on, ", pattern=").concat(pattern));
var _d = this.queryCheck(query, on, pattern), pass = _d[0], result = _d[1];
this.log("BREAK".concat(name, " QUERY ").concat((0, index_js_1.selectorStatements)(query), " -> ").concat((0, index_js_1.trunc)(result === null || result === void 0 ? void 0 : result.value)).concat(pattern ? " (valid=".concat(result === null || result === void 0 ? void 0 : result.valid, ")") : "", " -> on=").concat(on, " -> ").concat(pass));
if (pass) {
this.log("BREAK".concat(name, " ").concat(when || ""));
return true;
}
}
else {
this.log("BREAK".concat(name, " ").concat(when || ""));
return true;
}
}
else {
this.state.vars.__metrics.skipped += 1;
this.log("BREAK".concat(name, " SKIPPED ").concat(when));
}
}
else {
this.log("BREAK".concat(name ? " ".concat(name) : "", " BYPASSED ").concat(when));
}
return false;
};
Controller.prototype.click = function (_a) {
var name = _a.name, query = _a.query, waitfor = _a.waitfor, snooze = _a.snooze, required = _a.required, retry = _a.retry, when = _a.when, options = __rest(_a, ["name", "query", "waitfor", "snooze", "required", "retry", "when"]);
return __awaiter(this, void 0, void 0, function () {
var mode, duration, result, code, duration;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
if (!this.online) return [3, 15];
if (!this.when(when, "CLICK".concat(name ? " ".concat(name) : ""))) return [3, 13];
mode = snooze ? snooze[2] || "before" : undefined;
if (!(snooze && (mode === "before" || mode === "before-and-after"))) return [3, 2];
duration = this.maxTimeout(snooze[0]);
this.log("CLICK".concat(name ? " ".concat(name) : "", " SNOOZE BEFORE (").concat(duration.toFixed(1), "s) ").concat((0, index_js_1.selectorStatements)(query)));
return [4, (0, index_js_1.sleep)(duration)];
case 1:
_b.sent();
this.state.vars.__metrics.snooze += duration;
_b.label = 2;
case 2:
result = this.query({ query: query });
if (!(result && result.nodes.length > 0)) return [3, 11];
if (!this.clickElement(result.nodes[0], (0, index_js_1.selectorStatements)(query))) return [3, 10];
if (!waitfor) return [3, 8];
return [4, this.waitfor(waitfor, "CLICK")];
case 3:
code = _b.sent();
if (!!code) return [3, 6];
if (!(snooze && (mode === "after" || mode === "before-and-after"))) return [3, 5];
duration = this.maxTimeout(snooze[0]);
this.log("CLICK".concat(name ? " ".concat(name) : "", " SNOOZE AFTER (").concat(duration.toFixed(1), "s) ").concat((0, index_js_1.selectorStatements)(query)));
return [4, (0, index_js_1.sleep)(duration)];
case 4:
_b.sent();
this.state.vars.__metrics.snooze += duration;
_b.label = 5;
case 5: return [3, 7];
case 6:
if (code === "timeout") {
this.appendError("click-timeout", "Timeout waiting for CLICK".concat(name ? " ".concat(name) : "", " result. ").concat((0, index_js_1.trunc)(waitfor.query)).concat(waitfor.pattern ? ", pattern=".concat(waitfor.pattern) : ""), 1);
return [2, "timeout"];
}
else if (code === "invalid") {
}
_b.label = 7;
case 7: return [3, 9];
case 8:
if (options.yield) {
this.yield({
name: "CLICK ".concat(name ? " ".concat(name) : ""),
params: {
click: {},
waitUntil: options.waitUntil
}
});
}
_b.label = 9;
case 9:
this.state.vars.__metrics.clicks += 1;
this.state.vars.__metrics.steps += 1;
_b.label = 10;
case 10: return [3, 12];
case 11:
if (required) {
this.appendError("click-required", "Required click target not found. ".concat((0, index_js_1.trunc)(query)), 1);
}
return [2, "not-found"];
case 12: return [3, 14];
case 13:
this.state.vars.__metrics.skipped += 1;
this.log("CLICK".concat(name ? " ".concat(name) : "", " SKIPPED ").concat((0, index_js_1.selectorStatements)(query)));
_b.label = 14;
case 14: return [3, 16];
case 15:
this.log("CLICK".concat(name ? " ".concat(name) : "", " IGNORED ").concat((0, index_js_1.selectorStatements)(query)));
_b.label = 16;
case 16: return [2, null];
}
});
});
};
Controller.prototype.clickElement = function (element, context) {
if (element instanceof HTMLElement) {
if (element instanceof HTMLOptionElement && element.parentElement instanceof HTMLSelectElement) {
this.log("CLICK ".concat(context, " <select> \"").concat(element.parentElement.value, "\" -> \"").concat(element.value, "\""));
element.parentElement.value = element.value;
element.parentElement.dispatchEvent(new Event("change", { bubbles: true, cancelable: false }));
element.parentElement.dispatchEvent(new Event("input", { bubbles: true, cancelable: false }));
}
else {
this.log("CLICK ".concat(context));
element.click();
}
return true;
}
else {
this.log("CLICK ".concat(context, " not insanceof HTMLElement"));
return false;
}
};
Controller.prototype.context = function () {
var stack = this.state.vars.__context;
var j = stack.length - 1;
var context = __assign({}, stack[j]);
var subcontext = context;
while (--j >= 0) {
subcontext.parent = __assign({}, stack[j]);
subcontext = subcontext.parent;
}
return context;
};
Controller.prototype.contextKey = function () {
var stack = this.state.vars.__context;
var key = "";
for (var _i = 0, stack_1 = stack; _i < stack_1.length; _i++) {
var _a = stack_1[_i], name_1 = _a.name, index = _a.index;
if (name_1) {
if (key) {
key += ".";
}
key += name_1;
if (index !== undefined) {
key += "[".concat(index, "]");
}
}
}
return key;
};
Controller.prototype.contextKeyInfo = function () {
var key = this.contextKey();
var stack = this.state.vars.__context;
var info = "";
if (stack.length > 0) {
var top_1 = stack.slice(-1)[0];
if (top_1.pivot !== undefined) {
info = "PIVOT(".concat(top_1.pivot, ")");
}
else if (top_1.union !== undefined) {
info = "UNION(".concat(top_1.union, ")");
}
else if (top_1.action !== undefined) {
info = "".concat(top_1.action.toUpperCase());
}
}
return info ? "".concat(key, " ").concat(info) : key;
};
Controller.prototype.dispatch = function (action) {
return __awaiter(this, void 0, void 0, function () {
var select, code, data, required, code, required, code;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!action.hasOwnProperty("select")) return [3, 2];
select = action.select;
return [4, this.selectWaitfor(select)];
case 1:
code = _a.sent();
if (code === "timeout")
return [2, "timeout"];
data = this.select(select);
this.state.data = (0, index_js_1.merge)(this.state.data, data);
return [3, 32];
case 2:
if (!action.hasOwnProperty("break")) return [3, 3];
if (this.break(action.break)) {
return [2, "break"];
}
return [3, 32];
case 3:
if (!action.hasOwnProperty("click")) return [3, 5];
required = action.click.required;
return [4, this.click(action.click)];
case 4:
code = _a.sent();
if (code === "timeout" && required) {
return [2, "timeout"];
}
else if (code === "not-found" && required) {
return [2, "required"];
}
return [3, 32];
case 5:
if (!action.hasOwnProperty("each")) return [3, 7];
return [4, this.each(action.each)];
case 6:
_a.sent();
return [3, 32];
case 7:
if (!action.hasOwnProperty("error")) return [3, 8];
this.error(action.error);
return [3, 32];
case 8:
if (!action.hasOwnProperty("goback")) return [3, 10];
return [4, this.goback(action.goback)];
case 9:
_a.sent();
return [3, 32];
case 10:
if (!action.hasOwnProperty("keypress")) return [3, 11];
this.keypress(action.keypress);
return [3, 32];
case 11:
if (!action.hasOwnProperty("locator")) return [3, 13];
return [4, this.locator(action.locator)];
case 12:
_a.sent();
return [3, 32];
case 13:
if (!action.hasOwnProperty("navigate")) return [3, 15];
return [4, this.navigate(action.navigate)];
case 14:
_a.sent();
return [3, 32];
case 15:
if (!action.hasOwnProperty("reload")) return [3, 17];
return [4, this.reload(action.reload)];
case 16:
_a.sent();
return [3, 32];
case 17:
if (!action.hasOwnProperty("repeat")) return [3, 19];
return [4, this.repeat(action.repeat)];
case 18:
_a.sent();
return [3, 32];
case 19:
if (!action.hasOwnProperty("screenshot")) return [3, 21];
return [4, this.screenshot(action.screenshot)];
case 20:
_a.sent();
return [3, 32];
case 21:
if (!action.hasOwnProperty("scroll")) return [3, 23];
return [4, this.scroll(action.scroll)];
case 22:
_a.sent();
return [3, 32];
case 23:
if (!action.hasOwnProperty("snooze")) return [3, 25];
return [4, this.snooze(action.snooze)];
case 24:
_a.sent();
return [3, 32];
case 25:
if (!action.hasOwnProperty("switch")) return [3, 27];
return [4, this.switch(action.switch)];
case 26:
_a.sent();
return [3, 32];
case 27:
if (!action.hasOwnProperty("transform")) return [3, 29];
return [4, this.transform(action.transform)];
case 28:
_a.sent();
return [3, 32];
case 29:
if (!action.hasOwnProperty("waitfor")) return [3, 31];
required = action.waitfor.required;
return [4, this.waitfor(action.waitfor)];
case 30:
code = _a.sent();
if (code === "timeout" && required) {
return [2, "timeout"];
}
return [3, 32];
case 31:
if (action.hasOwnProperty("yield")) {
this.yield(action.yield || {});
}
_a.label = 32;
case 32: return [2, null];
}
});
});
};
Controller.prototype.each = function (_a) {
var name = _a.name, query = _a.query, actions = _a.actions, context = _a.context, when = _a.when;
return __awaiter(this, void 0, void 0, function () {
var $, label, result, elements, _i, elements_1, element, nodes, code;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
$ = this.jquery;
label = "EACH".concat(name ? " ".concat(name) : "");
if (!this.when(when, label)) return [3, 5];
result = this.query({ query: query, repeated: true });
if (!(result && result.nodes.length > 0)) return [3, 4];
elements = result.nodes.toArray();
_i = 0, elements_1 = elements;
_b.label = 1;
case 1:
if (!(_i < elements_1.length)) return [3, 4];
element = elements_1[_i];
nodes = $(element);
this.pushContext({
nodes: nodes,
value: this.text(nodes),
action: "each",
index: elements.indexOf(element)
}, context);
return [4, this.run(actions, label, true)];
case 2:
code = _b.sent();
this.popContext();
if (code === "break") {
return [3, 4];
}
_b.label = 3;
case 3:
_i++;
return [3, 1];
case 4:
this.state.vars.__metrics.steps += 1;
return [3, 6];
case 5:
this.state.vars.__metrics.skipped += 1;
_b.label = 6;
case 6: return [2];
}
});
});
};
Controller.prototype.eachNode = function (_a, callback) {
var nodes = _a.nodes, value = _a.value;
var $ = this.jquery;
if (nodes) {
var elements = nodes.toArray();
for (var i = 0; i < elements.length; ++i) {
var node = $(elements[i]);
var subvalue = value instanceof Array ? value[i] : value;
callback(node, subvalue);
}
}
};
Controller.prototype.elapsed = function () {
return Date.now() - this.state.vars.__t0;
};
Controller.prototype.error = function (_a) {
var query = _a.query, _b = _a.code, code = _b === void 0 ? "app-error" : _b, message = _a.message, _c = _a.level, level = _c === void 0 ? 1 : _c, negate = _a.negate, stop = _a.stop, when = _a.when;
if (!message)
message = errors_js_1.errorCodeMessageMap[code] || "Unknown error.";
if (query) {
var result = this.query({ query: query, type: "boolean", repeated: false });
var hit = !negate ? (result === null || result === void 0 ? void 0 : result.value) === false : (result === null || result === void 0 ? void 0 : result.value) === true;
if (hit) {
this.appendError(code, String(this.evaluate(message)), level);
this.state.vars.__metrics.steps += 1;
if (stop === true || (stop === undefined && level === 0))
throw "STOP";
}
}
else if (this.when(when, "ERROR")) {
this.appendError(code, String(this.evaluate(message)), level);
this.state.vars.__metrics.steps += 1;
if (stop === true || (stop === undefined && level === 0))
throw "STOP";
}
else {
this.state.vars.__metrics.skipped += 1;
this.log("ERROR ".concat(code, " SKIPPED ").concat(when));
}
};
Controller.prototype.evaluate = function (input, params) {
if (params === void 0) { params = {}; }
if ((0, index_js_1.isFormula)(input)) {
var data = params.data, extra = __rest(params, ["data"]);
var context_1 = this.context();
var args = __assign(__assign(__assign(__assign(__assign({}, this.state.vars), this.state), context_1), { data: (0, index_js_1.unwrap)((0, index_js_1.merge)(this.state.data, data)) }), extra);
try {
var result = (0, index_js_1.evaluateFormula)(input.slice(1, -1).trim(), args);
return result;
}
catch (err) {
this.appendError("eval-error", "Error evaluating formula \"".concat(input, "\": ").concat(err instanceof Error ? err.message : JSON.stringify(err)), 0);
}
}
else if ((0, index_js_1.isRegexp)(input)) {
var result = (0, index_js_1.regexpExtract)(params.value, input);
return result;
}
else {
return input;
}
};
Controller.prototype.evaluateBoolean = function (input, params) {
if (params === void 0) { params = {}; }
if (input !== undefined && input !== null) {
if ((0, index_js_1.isRegexp)(input)) {
var result = (0, index_js_1.regexpTest)(params.value, input);
return result !== null ? result : undefined;
}
else {
var result = this.evaluate(input, params);
if (typeof result === "boolean")
return result;
}
}
return undefined;
};
Controller.prototype.evaluateNumber = function (input, params) {
if (params === void 0) { params = {}; }
if (input !== undefined && input !== null) {
var result = this.evaluate(input, params);
if (typeof result === "number")
return result;
}
return undefined;
};
Controller.prototype.evaluateString = function (input, params) {
if (params === void 0) { params = {}; }
if (input !== undefined && input !== null) {
var result = this.evaluate(input, params);
if (typeof result === "string")
return result;
}
return undefined;
};
Controller.prototype.formatResult = function (result, type, all, limit, format, pattern, distinct, negate, removeNulls) {
var _this = this;
if (format === void 0) { format = "multiline"; }
var $ = this.jquery;
var regexp = (0, index_js_1.createRegExp)(pattern);
if (result.raw)
return result;
if (!type) {
var defaultType = result.value instanceof Array ? typeof result.value[0] : typeof result.value;
type = ["string", "number", "boolean"].includes(defaultType) ? defaultType : "string";
}
if (limit !== undefined && limit !== null && result.value instanceof Array) {
result.nodes = $(result.nodes.toArray().slice(0, limit));
result.value = result.value.slice(0, limit);
}
if (type === "string" && result.value instanceof Array) {
if (!result.formatted) {
result.value = result.value.map(function (value) { return (0, index_js_1.formatStringValue)((0, index_js_1.coerceSelectValue)(value, "string"), format, _this.state.origin); });
}
if (regexp && !(0, index_js_1.isEmpty)(result.value)) {
result.valid = result.value.every(function (value) { return regexp.test(value); });
}
}
else if (type === "string") {
if (!result.formatted) {
result.value = (0, index_js_1.formatStringValue)((0, index_js_1.coerceSelectValue)(result.value, "string"), format, this.state.origin);
}
if (regexp && !(0, index_js_1.isEmpty)(result.value)) {
result.valid = regexp.test(result.value);
}
}
else if (type === "boolean" && result.value instanceof Array && result.value.length === 0) {
result.value = false;
}
else if (type === "boolean" && result.value instanceof Array && all) {
result.value = result.value.every(function (value) { return (0, index_js_1.coerceSelectValue)(value, "boolean") === true; });
}
else if (type === "boolean" && result.value instanceof Array && !all) {
result.value = result.value.some(function (value) { return (0, index_js_1.coerceSelectValue)(value, "boolean") === true; });
}
else if (type === "boolean") {
result.value = (0, index_js_1.coerceSelectValue)(result.value, "boolean");
}
else if (type === "number" && result.value instanceof Array) {
result.value = result.value.map(function (value) { return (0, index_js_1.coerceSelectValue)(value, "number"); });
}
else if (type === "number") {
result.value = (0, index_js_1.coerceSelectValue)(result.value, "number");
}
if (negate) {
if (typeof result.value === "boolean")
result.value = !result.value;
else if (result.value instanceof Array && result.value.every(function (value) { return typeof value === "boolean"; }))
result.value = result.value.map(function (value) { return !value; });
}
if (removeNulls && result.value instanceof Array) {
(0, index_js_1.filterQueryResult)($, result, function (value) { return value !== null; });
}
if (distinct && result.value instanceof Array) {
(0, index_js_1.filterQueryResult)($, result, function (value, index, array) { return array.indexOf(value) === index; });
}
return result;
};
Controller.prototype.goback = function (_a) {
var name = _a.name, when = _a.when;
this.yield({
name: "GOBACK ".concat(name ? " ".concat(name) : ""),
params: {
goback: {},
action: "goBack"
},
when: when
});
};
Controller.prototype.keypress = function (_a) {
var _b = _a.name, name = _b === void 0 ? "" : _b, key = _a.key, shift = _a.shift, control = _a.control, alt = _a.alt, when = _a.when;
if (name)
name = " " + name;
if (this.online) {
if (this.when(when, "KEYPRESS")) {
var event_1 = new KeyboardEvent("keydown", {
key: key,
code: 'Key' + key.toUpperCase(),
keyCode: key.charCodeAt(0),
which: key.charCodeAt(0),
shiftKey: shift,
ctrlKey: control,
altKey: alt
});
document.dispatchEvent(event_1);
}
else {
this.state.vars.__metrics.skipped += 1;
this.log("KEYPRESS".concat(name, " SKIPPED ").concat(when));
}
}
else {
this.log("KEYPRESS".concat(name ? " ".concat(name) : "", " BYPASSED ").concat(when));
}
};
Controller.prototype.log = function (text) {
if (this.state.debug) {
if (this.lastLogLine === text) {
var elapsed = (Date.now() - this.lastLogTimestamp) / 1000;
this.state.log = "".concat(this.state.log.slice(0, this.lastLogLength)).concat(text, " (").concat(elapsed.toFixed(1), "s)\n");
}
else {
this.lastLogLine = text;
this.lastLogLength = this.state.log.length;
this.lastLogTimestamp = Date.now();
this.state.log += "".concat(String(this.elapsed()).padStart(8, "0"), " ").concat(text, "\n");
}
}
};
Controller.prototype.maxTimeout = function (seconds) {
if (seconds === void 0) { seconds = defaultTimeoutSeconds; }
var elapsed = this.elapsed() / 1000;
var remaining = Math.max(this.state.vars.__timeout - elapsed, 0);
return Math.min(seconds, remaining);
};
Controller.prototype.mergeQueryResult = function (source, target) {
var _a, _b;
var $ = this.jquery;
if (source && target) {
var nodes = source.nodes && target.nodes ? $(__spreadArray(__spreadArray([], source.nodes.toArray(), true), target.nodes.toArray(), true)) : target.nodes || source.nodes;
var value = undefined;
if (source.value instanceof Array && target.value instanceof Array) {
value = __spreadArray(__spreadArray([], source.value, true), target.value, true);
}
else if (source.value instanceof Array && !(0, index_js_1.isNullOrUndefined)(target.value)) {
value = __spreadArray(__spreadArray([], source.value, true), [target.value], false);
}
else if (target.value instanceof Array && !(0, index_js_1.isNullOrUndefined)(source.value)) {
value = __spreadArray([source.value], target.value, true);
}
else if (!(0, index_js_1.isNullOrUndefined)(source.value) && !(0, index_js_1.isNullOrUndefined)(target.value)) {
value = [source.value, target.value];
}
else {
value = (_a = target.value) !== null && _a !== void 0 ? _a : source.value;
}
return { nodes: nodes, key: this.contextKey(), value: value, valid: (_b = target.valid) !== null && _b !== void 0 ? _b : source.valid };
}
else if (target) {
return target;
}
else {
return source;
}
};
Controller.prototype.nodeKey = function (node) {
var _a, _b;
var $ = this.jquery;
var path = [];
var elements = $(node && node.length > 1 ? node[0] : node).parents().addBack().not("html").toArray().reverse();
for (var _i = 0, elements_2 = elements; _i < elements_2.length; _i++) {
var element = elements_2[_i];
var $parent = $(element).parent();
var tag = (_a = element.tagName) === null || _a === void 0 ? void 0 : _a.toLowerCase();
var id = $(element).attr('id') || "";
var className = ((_b = $(element).attr('class')) === null || _b === void 0 ? void 0 : _b.split(' ')[0]) || "";
var n = $(element).index() + 1;
var uniqueId = /^[A-Za-z0-9_-]+$/.test(id) ? $("#".concat(id)).length === 1 : false;
var uniqueClassName = tag && /^[A-Za-z0-9_-]+$/.test(className) ? $("".concat(tag, ".").concat(className)).length === 1 : false;
var onlyTag = $parent.children(tag).length === 1;
var onlyClassName = tag && /^[A-Za-z0-9_-]+$/.test(className) ? $parent.children("".concat(tag, ".").concat(className)).length === 1 : false;
if (uniqueId)
path.push("#".concat(id));
else if (uniqueClassName)
path.push("".concat(tag, ".").concat(className));
else if (onlyTag)
path.push(tag);
else if (onlyClassName)
path.push("".concat(tag, ".").concat(className));
else
path.push("".concat(tag, ":nth-child(").concat(n, ")"));
if (uniqueId || uniqueClassName)
break;
}
return path.reverse().join(" > ");
};
Controller.prototype.nodeKeys = function (nodes) {
var _this = this;
if (typeof nodes === "object" && typeof nodes.toArray === "function") {
return nodes.toArray().map(function (node) { return _this.nodeKey(node); });
}
else {
return [];
}
};
Controller.prototype.pokeContext = function (context) {
var stack = this.state.vars.__context;
var i = stack.length - 1;
if (i >= 0) {
stack[i] = __assign(__assign({}, stack[i]), context);
}
if (context.nodes) {
this.log("--> ".concat(this.contextKeyInfo(), " [").concat(this.nodeKey(stack[stack.length - 1].nodes), "] ").concat((0, index_js_1.trunc)(stack[stack.length - 1].value)));
}
};
Controller.prototype.popContext = function () {
var stack = this.state.vars.__context;
var top = stack.slice(-1)[0];
this.log("<<< ".concat(this.contextKeyInfo(), " [").concat(this.nodeKey(top === null || top === void 0 ? void 0 : top.nodes), "] ").concat(stack.length - 1));
stack.pop();
};
Controller.prototype.pushContext = function (context, inherit) {
var stack = this.state.vars.__context;
if (inherit === undefined) {
var parent_1 = stack.slice(-1)[0];
stack.push(__assign({ nodes: parent_1 === null || parent_1 === void 0 ? void 0 : parent_1.nodes, value: parent_1 === null || parent_1 === void 0 ? void 0 : parent_1.value }, context));
}
else if (inherit === null) {
stack.push(__assign(__assign({}, context), { nodes: undefined }));
}
else if (inherit > 0 && inherit <= stack.length) {
var parent_2 = stack.slice(-1 * inherit)[0];
stack.push(__assign(__assign({}, context), { nodes: parent_2 === null || parent_2 === void 0 ? void 0 : parent_2.nodes, value: parent_2 === null || parent_2 === void 0 ? void 0 : parent_2.value }));
}
else {
stack.push(context);
this.appendError("eval-error", "Undefined context #".concat(inherit), 1);
}
this.log(">>> ".concat(this.contextKeyInfo(), " [").concat(this.nodeKey(stack[stack.length - 1].nodes), "] ").concat((0, index_js_1.trunc)(stack[stack.length - 1].value), " ").concat(stack.length));
};
Controller.prototype.query = function (_a) {
var query = _a.query, type = _a.type, _b = _a.repeated, repeated = _b === void 0 ? false : _b, _c = _a.all, all = _c === void 0 ? false : _c, format = _a.format, pattern = _a.pattern, limit = _a.limit, hits = _a.hits, distinct = _a.distinct, negate = _a.negate, removeNulls = _a.removeNulls;
if (query instanceof Array && query.every(function (stage) { return stage instanceof Array; }) && query[0].length > 0 && !!query[0][0]) {
if (limit === undefined && type === "string" && !repeated && !all) {
limit = 1;
}
if (hits === null || hits === undefined) {
hits = query.length;
}
var hit = 0;
var result = undefined;
for (var _i = 0, query_1 = query; _i < query_1.length; _i++) {
var stage = query_1[_i];
var subresult = this.resolveQuery({ query: stage, type: type, repeated: repeated, all: all, limit: limit, format: format, pattern: pattern, distinct: distinct, negate: negate, removeNulls: removeNulls, result: result });
if (subresult) {
result = this.mergeQueryResult(result, subresult);
if (subresult.nodes.length > 0) {
if (!all) {
this.log("[".concat(query.indexOf(stage) + 1, "/").concat(query.length, "] STOP (first hit)"));
break;
}
if (++hit === hits) {
this.log("[".concat(query.indexOf(stage) + 1, "/").concat(query.length, "] STOP (").concat(hits, " hits)"));
break;
}
}
}
else {
}
}
if (result && !result.raw) {
if (repeated && !Array.isArray(result.value))
result.value = [result.value];
else if (!repeated && Array.isArray(result.value) && result.value.every(function (value) { return typeof value === "string"; }))
result.value = result.value.length > 0 ? result.value.join(format === "singleline" ? " " : "\n") : null;
else if (!repeated && type === "boolean" && !negate && Array.isArray(result.value) && result.value.every(function (value) { return typeof value === "boolean"; }))
result.value = result.value.some(function (value) { return value === true; });
else if (!repeated && type === "boolean" && negate && Array.isArray(result.value) && result.value.every(function (value) { return typeof value === "boolean"; }))
result.value = !(result.value.some(function (value) { return value === false; }));
else if (!repeated && Array.isArray(result.value))
result.value = result.value[0];
}
return result;
}
};
Controller.prototype.queryCheck = function (query, on, pattern) {
var type = pattern ? "string" : "boolean";
var all = on === "all";
var result = this.query({ query: query, type: type, pattern: pattern, all: all, repeated: all });
var pass = false;
if (result) {
if (type === "boolean") {
if (on === "any") {
pass = result.value === true;
}
else if (on === "all") {
pass = result.value.every(function (value) { return value === true; });
}
else if (on === "none") {
pass = result.value === false;
}
}
else if (type === "string") {
if (on === "any") {
pass = !(0, index_js_1.isEmpty)((0, index_js_1.trim)(result.value)) && result.valid !== false;
}
else if (on === "all") {
pass = result.value.every(function (value) { return !(0, index_js_1.isEmpty)((0, index_js_1.trim)(value)); }) && result.valid !== false;
}
else if (on === "none") {
pass = !(!(0, index_js_1.isEmpty)((0, index_js_1.trim)(result.value)) && result.valid !== false);
}
}
}
return [pass, result];
};
Controller.prototype.reload = function (_a) {
var name = _a.name, waitUntil = _a.waitUntil, when = _a.when;
this.yield({
name: "RELOAD ".concat(name ? " ".concat(name) : ""),
params: {
reload: {},
action: "reload",
waitUntil: waitUntil
},
when: when
});
};
Controller.prototype.repeat = function (_a) {
var _b = _a.name, name = _b === void 0 ? "" : _b, actions = _a.actions, limit = _a.limit, _c = _a.errors, errors = _c === void 0 ? 1 : _c, when = _a.when;
return __awaiter(this, void 0, void 0, function () {
var state, errorOffset, label, code;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
if (name)
name = " " + name;
limit = this.evaluateNumber(limit);
if (limit === undefined)
limit = 1;
if (!this.when(when, "REPEAT".concat(name))) return [3, 4];
state = this.acquireRepeatState();
errorOffset = 0;
_d.label = 1;
case 1:
if (!(state.index < limit)) return [3, 3];
label = "REPEAT".concat(name, " #").concat(++state.index);
this.log("".concat(label, " (limit=").concat(limit, ")"));
return [4, this.run(actions, label, true)];
case 2:
code = _d.sent();
if (!code) {
this.log("".concat(label, " -> ").concat(actions.length, " steps completed"));
errorOffset = this.state.errors.length - state.errors;
if (errorOffset >= errors) {
this.appendError("error-limit", "".concat(errorOffset, " errors in repeat (error limit of ").concat(errors, " exceeded)"), 1);
return [3, 3];
}
}
else {
return [3, 3];
}
return [3, 1];
case 3:
this.clearRepeatState();
this.state.vars.__metrics.steps += 1;
this.log("REPEAT".concat(name, " ").concat(state.index, " iterations completed (limit=").concat(limit, ", errors=").concat(errorOffset, "/").concat(errors, ")"));
return [3, 5];
case 4:
this.state.vars.__metrics.skipped += 1;
this.log("REPEAT".concat(name, " SKIPPED ").concat(when));
_d.label = 5;
case 5: return [2];
}
});
});
};
Controller.prototype.acquireRepeatState = function () {
var depth = this.state.vars.__step.length;
if (!this.state.vars.__repeat[depth])
this.state.vars.__repeat[depth] = {
index: 0,
errors: this.state.errors.length
};
return this.state.vars.__repeat[depth];
};
Controller.prototype.clearRepeatState = function () {
var depth = this.state.vars.__step.length;
this.state.vars.__repeat[depth] = undefined;
};
Controller.prototype.locator = function (locators) {
var _this = this;
var activeLocators = locators.filter(function (locator) {
return _this.when(locator.when, "LOCATOR".concat(locator.name ? " ".concat(locator.name) : ""));
});
if (activeLocators.length > 0) {
var locator = activeLocators[0];
this.yield({
name: "LOCATOR ".concat(locator.name ? " ".concat(locator.name) : "").concat(activeLocators.length > 1 ? " (+".concat(activeLocators.length - 1, " more)") : ""),
params: {
locators: activeLocators.map(function (locator) {
var _a;
return ({
name: _this.evaluateString(locator.name) || "_value",
selector: _this.evaluateString(locator.selector),
method: _this.evaluateString(locator.method),
params: (_a = locator.params) === null || _a === void 0 ? void 0 : _a.map(function (param) { return _this.evaluate(param); }),
frame: _this.evaluateString(locator.frame),
promote: locator.promote,
chain: locator.chain
});
}),
action: "locator",
name: locator.name,
frame: locator.frame,
selector: locator.selector,
promote: locator.promote,
method: locator.method,
arg0: locator.params ? locator.params[0] : undefined
}
});
}
};
Controller.prototype.navigate = function (_a) {
var name = _a.name, url = _a.url, waitUntil = _a.waitUntil, when = _a.when;
this.yield({
name: "NAVIGATE ".concat(name ? " ".concat(name) : "", " ").concat(url),
params: {
navigate: { url: this.evaluateString(url) },
action: "navigate",
url: url,
waitUntil: waitUntil
},
when: when
});
};
Controller.prototype.resolveOperands = function (operands, result) {
var _this = this;
var _loop_1 = function (i) {
if ((0, index_js_1.isFormula)(operands[i]) || (0, index_js_1.isRegexp)(operands[i])) {
this_1.eachNode(result, function (node, value) {
var resolvedValue = String(_this.evaluate(operands[i], { value: value }));
if (resolvedValue !== operands[i]) {
operands[i] = resolvedValue;
}
});
}
};
var this_1 = this;
for (var i = 0; i < operands.length; ++i) {
_loop_1(i);
}
};
Controller.prototype.resolveQuery