feat(News): refactor news service and add sentiment tracking
This commit is contained in:
@@ -0,0 +1,367 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.WorkerDispatcher = exports.PageDispatcher = exports.BindingCallDispatcher = void 0;
|
||||
var _page = require("../page");
|
||||
var _dispatcher = require("./dispatcher");
|
||||
var _errors = require("../errors");
|
||||
var _frameDispatcher = require("./frameDispatcher");
|
||||
var _networkDispatchers = require("./networkDispatchers");
|
||||
var _jsHandleDispatcher = require("./jsHandleDispatcher");
|
||||
var _elementHandlerDispatcher = require("./elementHandlerDispatcher");
|
||||
var _artifactDispatcher = require("./artifactDispatcher");
|
||||
var _utils = require("../../utils");
|
||||
var _webSocketRouteDispatcher = require("./webSocketRouteDispatcher");
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class PageDispatcher extends _dispatcher.Dispatcher {
|
||||
static from(parentScope, page) {
|
||||
return PageDispatcher.fromNullable(parentScope, page);
|
||||
}
|
||||
static fromNullable(parentScope, page) {
|
||||
if (!page) return undefined;
|
||||
const result = (0, _dispatcher.existingDispatcher)(page);
|
||||
return result || new PageDispatcher(parentScope, page);
|
||||
}
|
||||
constructor(parentScope, page) {
|
||||
// TODO: theoretically, there could be more than one frame already.
|
||||
// If we split pageCreated and pageReady, there should be no main frame during pageCreated.
|
||||
|
||||
// We will reparent it to the page below using adopt.
|
||||
const mainFrame = _frameDispatcher.FrameDispatcher.from(parentScope, page.mainFrame());
|
||||
super(parentScope, page, 'Page', {
|
||||
mainFrame,
|
||||
viewportSize: page.viewportSize() || undefined,
|
||||
isClosed: page.isClosed(),
|
||||
opener: PageDispatcher.fromNullable(parentScope, page.opener())
|
||||
});
|
||||
this._type_EventTarget = true;
|
||||
this._type_Page = true;
|
||||
this._page = void 0;
|
||||
this._subscriptions = new Set();
|
||||
this._webSocketInterceptionPatterns = [];
|
||||
this.adopt(mainFrame);
|
||||
this._page = page;
|
||||
this.addObjectListener(_page.Page.Events.Close, () => {
|
||||
this._dispatchEvent('close');
|
||||
this._dispose();
|
||||
});
|
||||
this.addObjectListener(_page.Page.Events.Crash, () => this._dispatchEvent('crash'));
|
||||
this.addObjectListener(_page.Page.Events.Download, download => {
|
||||
// Artifact can outlive the page, so bind to the context scope.
|
||||
this._dispatchEvent('download', {
|
||||
url: download.url,
|
||||
suggestedFilename: download.suggestedFilename(),
|
||||
artifact: _artifactDispatcher.ArtifactDispatcher.from(parentScope, download.artifact)
|
||||
});
|
||||
});
|
||||
this.addObjectListener(_page.Page.Events.FileChooser, fileChooser => this._dispatchEvent('fileChooser', {
|
||||
element: _elementHandlerDispatcher.ElementHandleDispatcher.from(mainFrame, fileChooser.element()),
|
||||
isMultiple: fileChooser.isMultiple()
|
||||
}));
|
||||
this.addObjectListener(_page.Page.Events.FrameAttached, frame => this._onFrameAttached(frame));
|
||||
this.addObjectListener(_page.Page.Events.FrameDetached, frame => this._onFrameDetached(frame));
|
||||
this.addObjectListener(_page.Page.Events.LocatorHandlerTriggered, uid => this._dispatchEvent('locatorHandlerTriggered', {
|
||||
uid
|
||||
}));
|
||||
this.addObjectListener(_page.Page.Events.WebSocket, webSocket => this._dispatchEvent('webSocket', {
|
||||
webSocket: new _networkDispatchers.WebSocketDispatcher(this, webSocket)
|
||||
}));
|
||||
this.addObjectListener(_page.Page.Events.Worker, worker => this._dispatchEvent('worker', {
|
||||
worker: new WorkerDispatcher(this, worker)
|
||||
}));
|
||||
this.addObjectListener(_page.Page.Events.Video, artifact => this._dispatchEvent('video', {
|
||||
artifact: _artifactDispatcher.ArtifactDispatcher.from(parentScope, artifact)
|
||||
}));
|
||||
if (page._video) this._dispatchEvent('video', {
|
||||
artifact: _artifactDispatcher.ArtifactDispatcher.from(this.parentScope(), page._video)
|
||||
});
|
||||
// Ensure client knows about all frames.
|
||||
const frames = page._frameManager.frames();
|
||||
for (let i = 1; i < frames.length; i++) this._onFrameAttached(frames[i]);
|
||||
}
|
||||
page() {
|
||||
return this._page;
|
||||
}
|
||||
async setDefaultNavigationTimeoutNoReply(params, metadata) {
|
||||
this._page.setDefaultNavigationTimeout(params.timeout);
|
||||
}
|
||||
async setDefaultTimeoutNoReply(params, metadata) {
|
||||
this._page.setDefaultTimeout(params.timeout);
|
||||
}
|
||||
async exposeBinding(params, metadata) {
|
||||
await this._page.exposeBinding(params.name, !!params.needsHandle, (source, ...args) => {
|
||||
// When reusing the context, we might have some bindings called late enough,
|
||||
// after context and page dispatchers have been disposed.
|
||||
if (this._disposed) return;
|
||||
const binding = new BindingCallDispatcher(this, params.name, !!params.needsHandle, source, args);
|
||||
this._dispatchEvent('bindingCall', {
|
||||
binding
|
||||
});
|
||||
return binding.promise();
|
||||
});
|
||||
}
|
||||
async setExtraHTTPHeaders(params, metadata) {
|
||||
await this._page.setExtraHTTPHeaders(params.headers);
|
||||
}
|
||||
async reload(params, metadata) {
|
||||
return {
|
||||
response: _networkDispatchers.ResponseDispatcher.fromNullable(this.parentScope(), await this._page.reload(metadata, params))
|
||||
};
|
||||
}
|
||||
async goBack(params, metadata) {
|
||||
return {
|
||||
response: _networkDispatchers.ResponseDispatcher.fromNullable(this.parentScope(), await this._page.goBack(metadata, params))
|
||||
};
|
||||
}
|
||||
async goForward(params, metadata) {
|
||||
return {
|
||||
response: _networkDispatchers.ResponseDispatcher.fromNullable(this.parentScope(), await this._page.goForward(metadata, params))
|
||||
};
|
||||
}
|
||||
async requestGC(params, metadata) {
|
||||
await this._page.requestGC();
|
||||
}
|
||||
async registerLocatorHandler(params, metadata) {
|
||||
const uid = this._page.registerLocatorHandler(params.selector, params.noWaitAfter);
|
||||
return {
|
||||
uid
|
||||
};
|
||||
}
|
||||
async resolveLocatorHandlerNoReply(params, metadata) {
|
||||
this._page.resolveLocatorHandler(params.uid, params.remove);
|
||||
}
|
||||
async unregisterLocatorHandler(params, metadata) {
|
||||
this._page.unregisterLocatorHandler(params.uid);
|
||||
}
|
||||
async emulateMedia(params, metadata) {
|
||||
await this._page.emulateMedia({
|
||||
media: params.media,
|
||||
colorScheme: params.colorScheme,
|
||||
reducedMotion: params.reducedMotion,
|
||||
forcedColors: params.forcedColors
|
||||
});
|
||||
}
|
||||
async setViewportSize(params, metadata) {
|
||||
await this._page.setViewportSize(params.viewportSize);
|
||||
}
|
||||
async addInitScript(params, metadata) {
|
||||
await this._page.addInitScript(params.source);
|
||||
}
|
||||
async setNetworkInterceptionPatterns(params, metadata) {
|
||||
if (!params.patterns.length) {
|
||||
await this._page.setClientRequestInterceptor(undefined);
|
||||
return;
|
||||
}
|
||||
const urlMatchers = params.patterns.map(pattern => pattern.regexSource ? new RegExp(pattern.regexSource, pattern.regexFlags) : pattern.glob);
|
||||
await this._page.setClientRequestInterceptor((route, request) => {
|
||||
const matchesSome = urlMatchers.some(urlMatch => (0, _utils.urlMatches)(this._page._browserContext._options.baseURL, request.url(), urlMatch));
|
||||
if (!matchesSome) return false;
|
||||
this._dispatchEvent('route', {
|
||||
route: _networkDispatchers.RouteDispatcher.from(_networkDispatchers.RequestDispatcher.from(this.parentScope(), request), route)
|
||||
});
|
||||
return true;
|
||||
});
|
||||
}
|
||||
async setWebSocketInterceptionPatterns(params, metadata) {
|
||||
this._webSocketInterceptionPatterns = params.patterns;
|
||||
if (params.patterns.length) await _webSocketRouteDispatcher.WebSocketRouteDispatcher.installIfNeeded(this.parentScope(), this._page);
|
||||
}
|
||||
async expectScreenshot(params, metadata) {
|
||||
const mask = (params.mask || []).map(({
|
||||
frame,
|
||||
selector
|
||||
}) => ({
|
||||
frame: frame._object,
|
||||
selector
|
||||
}));
|
||||
const locator = params.locator ? {
|
||||
frame: params.locator.frame._object,
|
||||
selector: params.locator.selector
|
||||
} : undefined;
|
||||
return await this._page.expectScreenshot(metadata, {
|
||||
...params,
|
||||
locator,
|
||||
mask
|
||||
});
|
||||
}
|
||||
async screenshot(params, metadata) {
|
||||
const mask = (params.mask || []).map(({
|
||||
frame,
|
||||
selector
|
||||
}) => ({
|
||||
frame: frame._object,
|
||||
selector
|
||||
}));
|
||||
return {
|
||||
binary: await this._page.screenshot(metadata, {
|
||||
...params,
|
||||
mask
|
||||
})
|
||||
};
|
||||
}
|
||||
async close(params, metadata) {
|
||||
if (!params.runBeforeUnload) metadata.potentiallyClosesScope = true;
|
||||
await this._page.close(metadata, params);
|
||||
}
|
||||
async updateSubscription(params) {
|
||||
if (params.event === 'fileChooser') await this._page.setFileChooserIntercepted(params.enabled);
|
||||
if (params.enabled) this._subscriptions.add(params.event);else this._subscriptions.delete(params.event);
|
||||
}
|
||||
async keyboardDown(params, metadata) {
|
||||
await this._page.keyboard.down(params.key);
|
||||
}
|
||||
async keyboardUp(params, metadata) {
|
||||
await this._page.keyboard.up(params.key);
|
||||
}
|
||||
async keyboardInsertText(params, metadata) {
|
||||
await this._page.keyboard.insertText(params.text);
|
||||
}
|
||||
async keyboardType(params, metadata) {
|
||||
await this._page.keyboard.type(params.text, params);
|
||||
}
|
||||
async keyboardPress(params, metadata) {
|
||||
await this._page.keyboard.press(params.key, params);
|
||||
}
|
||||
async mouseMove(params, metadata) {
|
||||
await this._page.mouse.move(params.x, params.y, params, metadata);
|
||||
}
|
||||
async mouseDown(params, metadata) {
|
||||
await this._page.mouse.down(params, metadata);
|
||||
}
|
||||
async mouseUp(params, metadata) {
|
||||
await this._page.mouse.up(params, metadata);
|
||||
}
|
||||
async mouseClick(params, metadata) {
|
||||
await this._page.mouse.click(params.x, params.y, params, metadata);
|
||||
}
|
||||
async mouseWheel(params, metadata) {
|
||||
await this._page.mouse.wheel(params.deltaX, params.deltaY);
|
||||
}
|
||||
async touchscreenTap(params, metadata) {
|
||||
await this._page.touchscreen.tap(params.x, params.y, metadata);
|
||||
}
|
||||
async accessibilitySnapshot(params, metadata) {
|
||||
const rootAXNode = await this._page.accessibility.snapshot({
|
||||
interestingOnly: params.interestingOnly,
|
||||
root: params.root ? params.root._elementHandle : undefined
|
||||
});
|
||||
return {
|
||||
rootAXNode: rootAXNode || undefined
|
||||
};
|
||||
}
|
||||
async pdf(params, metadata) {
|
||||
if (!this._page.pdf) throw new Error('PDF generation is only supported for Headless Chromium');
|
||||
const buffer = await this._page.pdf(params);
|
||||
return {
|
||||
pdf: buffer
|
||||
};
|
||||
}
|
||||
async bringToFront(params, metadata) {
|
||||
await this._page.bringToFront();
|
||||
}
|
||||
async startJSCoverage(params, metadata) {
|
||||
const coverage = this._page.coverage;
|
||||
await coverage.startJSCoverage(params);
|
||||
}
|
||||
async stopJSCoverage(params, metadata) {
|
||||
const coverage = this._page.coverage;
|
||||
return await coverage.stopJSCoverage();
|
||||
}
|
||||
async startCSSCoverage(params, metadata) {
|
||||
const coverage = this._page.coverage;
|
||||
await coverage.startCSSCoverage(params);
|
||||
}
|
||||
async stopCSSCoverage(params, metadata) {
|
||||
const coverage = this._page.coverage;
|
||||
return await coverage.stopCSSCoverage();
|
||||
}
|
||||
_onFrameAttached(frame) {
|
||||
this._dispatchEvent('frameAttached', {
|
||||
frame: _frameDispatcher.FrameDispatcher.from(this.parentScope(), frame)
|
||||
});
|
||||
}
|
||||
_onFrameDetached(frame) {
|
||||
this._dispatchEvent('frameDetached', {
|
||||
frame: _frameDispatcher.FrameDispatcher.from(this.parentScope(), frame)
|
||||
});
|
||||
}
|
||||
_onDispose() {
|
||||
// Avoid protocol calls for the closed page.
|
||||
if (!this._page.isClosedOrClosingOrCrashed()) this._page.setClientRequestInterceptor(undefined).catch(() => {});
|
||||
}
|
||||
}
|
||||
exports.PageDispatcher = PageDispatcher;
|
||||
class WorkerDispatcher extends _dispatcher.Dispatcher {
|
||||
static fromNullable(scope, worker) {
|
||||
if (!worker) return undefined;
|
||||
const result = (0, _dispatcher.existingDispatcher)(worker);
|
||||
return result || new WorkerDispatcher(scope, worker);
|
||||
}
|
||||
constructor(scope, worker) {
|
||||
super(scope, worker, 'Worker', {
|
||||
url: worker.url()
|
||||
});
|
||||
this._type_Worker = true;
|
||||
this.addObjectListener(_page.Worker.Events.Close, () => this._dispatchEvent('close'));
|
||||
}
|
||||
async evaluateExpression(params, metadata) {
|
||||
return {
|
||||
value: (0, _jsHandleDispatcher.serializeResult)(await this._object.evaluateExpression(params.expression, params.isFunction, (0, _jsHandleDispatcher.parseArgument)(params.arg)))
|
||||
};
|
||||
}
|
||||
async evaluateExpressionHandle(params, metadata) {
|
||||
return {
|
||||
handle: _elementHandlerDispatcher.ElementHandleDispatcher.fromJSHandle(this, await this._object.evaluateExpressionHandle(params.expression, params.isFunction, (0, _jsHandleDispatcher.parseArgument)(params.arg)))
|
||||
};
|
||||
}
|
||||
}
|
||||
exports.WorkerDispatcher = WorkerDispatcher;
|
||||
class BindingCallDispatcher extends _dispatcher.Dispatcher {
|
||||
constructor(scope, name, needsHandle, source, args) {
|
||||
super(scope, {
|
||||
guid: 'bindingCall@' + (0, _utils.createGuid)()
|
||||
}, 'BindingCall', {
|
||||
frame: _frameDispatcher.FrameDispatcher.from(scope.parentScope(), source.frame),
|
||||
name,
|
||||
args: needsHandle ? undefined : args.map(_jsHandleDispatcher.serializeResult),
|
||||
handle: needsHandle ? _elementHandlerDispatcher.ElementHandleDispatcher.fromJSHandle(scope, args[0]) : undefined
|
||||
});
|
||||
this._type_BindingCall = true;
|
||||
this._resolve = void 0;
|
||||
this._reject = void 0;
|
||||
this._promise = void 0;
|
||||
this._promise = new Promise((resolve, reject) => {
|
||||
this._resolve = resolve;
|
||||
this._reject = reject;
|
||||
});
|
||||
}
|
||||
promise() {
|
||||
return this._promise;
|
||||
}
|
||||
async resolve(params, metadata) {
|
||||
this._resolve((0, _jsHandleDispatcher.parseArgument)(params.result));
|
||||
this._dispose();
|
||||
}
|
||||
async reject(params, metadata) {
|
||||
this._reject((0, _errors.parseError)(params.error));
|
||||
this._dispose();
|
||||
}
|
||||
}
|
||||
exports.BindingCallDispatcher = BindingCallDispatcher;
|
||||
Reference in New Issue
Block a user