UNPKG

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.

991 lines 112 kB
"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.78"; 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, 31]; case 2: if (!action.hasOwnProperty("break")) return [3, 3]; if (this.break(action.break)) { return [2, "break"]; } return [3, 31]; 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, 31]; case 5: if (!action.hasOwnProperty("each")) return [3, 7]; return [4, this.each(action.each)]; case 6: _a.sent(); return [3, 31]; case 7: if (!action.hasOwnProperty("error")) return [3, 8]; this.error(action.error); return [3, 31]; case 8: if (!action.hasOwnProperty("goback")) return [3, 10]; return [4, this.goback(action.goback)]; case 9: _a.sent(); return [3, 31]; case 10: if (!action.hasOwnProperty("keypress")) return [3, 11]; this.keypress(action.keypress); return [3, 31]; case 11: if (!action.hasOwnProperty("locator")) return [3, 13]; return [4, this.locator(action.locator)]; case 12: _a.sent(); return [3, 31]; case 13: if (!action.hasOwnProperty("navigate")) return [3, 15]; return [4, this.navigate(action.navigate)]; case 14: _a.sent(); return [3, 31]; case 15: if (!action.hasOwnProperty("reload")) return [3, 17]; return [4, this.reload(action.reload)]; case 16: _a.sent(); return [3, 31]; case 17: if (!action.hasOwnProperty("repeat")) return [3, 19]; return [4, this.repeat(action.repeat)]; case 18: _a.sent(); return [3, 31]; case 19: if (!action.hasOwnProperty("screenshot")) return [3, 21]; return [4, this.screenshot(action.screenshot)]; case 20: _a.sent(); return [3, 31]; case 21: if (!action.hasOwnProperty("scroll")) return [3, 23]; return [4, this.scroll(action.scroll)]; case 22: _a.sent(); return [3, 31]; case 23: if (!action.hasOwnProperty("snooze")) return [3, 25]; return [4, this.snooze(action.snooze)]; case 24: _a.sent(); return [3, 31]; case 25: if (!action.hasOwnProperty("switch")) return [3, 27]; return [4, this.switch(action.switch)]; case 26: _a.sent(); return [3, 31]; case 27: if (!action.hasOwnProperty("transform")) return [3, 28]; this.transform(action.transform); return [3, 31]; case 28: if (!action.hasOwnProperty("waitfor")) return [3, 30]; required = action.waitfor.required; return [4, this.waitfor(action.waitfor)]; case 29: code = _a.sent(); if (code === "timeout" && required) { return [2, "timeout"]; } return [3, 31]; case 30: if (action.hasOwnProperty("yield")) { this.yield(action.yield || {}); } _a.label = 31; case 31: 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 = function (_a) { var query = _a.query, type = _a.type, repeated = _