class Task { _data = {}; _data_keys = []; /** * Create a task. * constructor(itemsSelector:string, fieldSelectors:string[]) * constructor(itemsSelector:string, fieldSelectors:string[], url:string, from:number, to:number, interval:number) * constructor(itemsSelector:string, fieldSelectors:string[], url:string, pages:number[]) * constructor(itemsSelector:string, fieldSelectors:string[], urls:string[]) * @param {...any} args */ constructor(options, ...args) { if (!testArgs(...args)) throw new Error(`Invalid call arguments.\n\n${signitures}\n\n`); this._options = options; this._itemsSelector = args.shift(); this._fieldSelectors = args.shift(); this._urls = parseUrls(...args); } get urls() { return this._urls; } get data() { return this._data; } get results() { return this._data_keys.reduce((p, c) => { return p.concat(this._data[c]); }, []); } get fieldSelectors() { return this._fieldSelectors; } clean() { this._data = {}; } async execute(tab, upstreamData) { if (!tab) return Promise.reject("No tab to execute the task."); let urls = this._urls if (!urls.length) { if (upstreamData) { urls = parseUrls(upstreamData); } else { urls = [await queryUrl(tab)]; } } let saveResult = (results, key) => { this._data[key] = results; this._data_keys.push(key); } return urls.reduce((p, url, i) => p.then( results => { if (i > 0) { if (!MSG_URL_SKIPPED.isEqual(results)) { let lastURL = urls[i - 1]; saveResult(results, lastURL); } } if (this._data[url]) return MSG_URL_SKIPPED; let pms = redirectTab(tab, url); if (this._options["scrollToBottom"]) { pms = pms.then(() => scrollToBottom(tab)); } return pms.then( () => extractTabData(tab, this._itemsSelector, this._fieldSelectors) ); } ), Promise.resolve(null)).then( results => { if (!MSG_URL_SKIPPED.isEqual(results)) { let lastURL = urls[urls.length - 1]; saveResult(results, lastURL); return; } } ); } }