UNPKG

page-parser-tree

Version:

Library to find elements in a dynamic web page

347 lines (286 loc) 11.2 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _liveSet = _interopRequireDefault(require("live-set")); var _merge = _interopRequireDefault(require("live-set/merge")); var _flatMapR = _interopRequireDefault(require("live-set/flatMapR")); var _Scheduler = _interopRequireDefault(require("live-set/Scheduler")); var _tagTree = require("tag-tree"); var _watcherFinderMerger = _interopRequireDefault(require("./watcherFinderMerger")); var _createTransformer = _interopRequireDefault(require("./createTransformer")); function makeTagOptions(options) { var map = new Map(); var list = []; Object.keys(options.tags).forEach(function (tag) { var tagOptions = options.tags[tag]; var ownedBy = tagOptions.ownedBy; list.push({ tag: tag, ownedBy: ownedBy }); map.set(tag, tagOptions); }); Object.keys(options.finders).concat(options.watchers.map(function (w) { return w.tag; })).forEach(function (tag) { if (!map.has(tag)) { map.set(tag, { ownedBy: [] }); list.push({ tag: tag }); } }); return { map: map, list: list }; } var PageParserTree = /*#__PURE__*/ function () { function PageParserTree(root, options) { var _this = this; (0, _classCallCheck2["default"])(this, PageParserTree); (0, _defineProperty2["default"])(this, "tree", void 0); (0, _defineProperty2["default"])(this, "_scheduler", new _Scheduler["default"]()); (0, _defineProperty2["default"])(this, "_treeController", void 0); (0, _defineProperty2["default"])(this, "_rootMatchedSet", void 0); (0, _defineProperty2["default"])(this, "_ecSources", void 0); (0, _defineProperty2["default"])(this, "_logError", void 0); (0, _defineProperty2["default"])(this, "_options", void 0); (0, _defineProperty2["default"])(this, "_tagOptions", void 0); (0, _defineProperty2["default"])(this, "_tagsList", void 0); (0, _defineProperty2["default"])(this, "_subscriptions", []); var rootEl; if (root.nodeType === Node.DOCUMENT_NODE) { rootEl = root.documentElement; if (!rootEl) throw new Error('missing documentElement'); } else { rootEl = root; } this._options = options; this._logError = options.logError || function (err) { setTimeout(function () { throw err; }, 0); }; var _makeTagOptions = makeTagOptions(this._options), tagOptionsMap = _makeTagOptions.map, tags = _makeTagOptions.list; this._tagOptions = tagOptionsMap; this._tagsList = tags; this.tree = new _tagTree.TagTree({ root: rootEl, tags: tags, executor: function executor(controller) { _this._treeController = controller; } }); this._rootMatchedSet = _liveSet["default"].constant(new Set([{ el: this.tree.getValue(), parents: [{ tag: null, node: this.tree }] }]), { scheduler: this._scheduler }); this._setupWatchersAndFinders(); } (0, _createClass2["default"])(PageParserTree, [{ key: "_setupWatchersAndFinders", value: function _setupWatchersAndFinders() { var _this2 = this; var tagsWithWatchers = new Set(); this._options.watchers.forEach(function (watcher) { tagsWithWatchers.add(watcher.tag); }); this._ecSources = new Map(this._tagsList.map(function (_ref) { var tag = _ref.tag; var tagOptions = _this2._tagOptions.get(tag); if (!tagOptions) throw new Error(); var ownedBy = new Set(tagOptions.ownedBy || []); var _LiveSet$active = _liveSet["default"].active(null, { scheduler: _this2._scheduler }), liveSet = _LiveSet$active.liveSet, controller = _LiveSet$active.controller; var combinedWatcherSet = tagsWithWatchers.has(tag) ? (0, _flatMapR["default"])(liveSet, function (s) { return s; }) : null; var finder = _this2._options.finders[tag]; var ecsToTag = finder ? (0, _watcherFinderMerger["default"])(_this2._scheduler, _this2.tree, tag, tagOptions, combinedWatcherSet, finder, _this2._logError) : combinedWatcherSet || _liveSet["default"].constant(new Set(), { scheduler: _this2._scheduler }); var elementsToNodes = new Map(); function findParentNode(taggedParents) { var parentNode; for (var i = taggedParents.length - 1; i >= 0; i--) { if (taggedParents[i].tag == null || ownedBy.has(taggedParents[i].tag)) { parentNode = taggedParents[i].node; break; } } if (!parentNode) throw new Error(); return parentNode; } var ecSet = new _liveSet["default"]({ scheduler: _this2._scheduler, read: function read() { throw new Error(); }, listen: function listen(setValues, controller) { var m = new Map(); var cb = function cb(ec) { var el = ec.el, parents = ec.parents; var parentNode = findParentNode(parents); var node = _this2._treeController.addTaggedValue(parentNode, tag, el); if (elementsToNodes.has(el)) { _this2._logError(new Error("PageParserTree(".concat(tag, ") watcher received element twice")), el); } elementsToNodes.set(el, node); var newParents = ec.parents.concat([{ tag: tag, node: node }]); return { el: el, parents: newParents }; }; return ecsToTag.subscribe({ start: function start() { var s = new Set(); ecsToTag.values().forEach(function (value) { var newValue = cb(value); m.set(value, newValue); s.add(newValue); }); setValues(s); }, next: function next(changes) { var ecsRemovedInNotification = new Set(); if (changes.length > 1) { changes.forEach(function (change) { if (change.type === 'remove') { ecsRemovedInNotification.add(change.value); } }); } changes.forEach(function (change) { if (change.type === 'add') { // Don't process adds of elements that are removed by a later // change in this notification. if (ecsRemovedInNotification.has(change.value)) return; var newValue = cb(change.value); m.set(change.value, newValue); controller.add(newValue); } else if (change.type === 'remove') { var _newValue = m.get(change.value); if (!_newValue) return; m["delete"](change.value); controller.remove(_newValue); var node = elementsToNodes.get(_newValue.el); if (!node) throw new Error('Should not happen: received removal of unseen element'); elementsToNodes["delete"](_newValue.el); var nodeParent = node.getParent(); // The node might have already been removed from the tree if it // is owned by a node that was just removed. if (nodeParent && nodeParent.ownsNode(node)) { _this2._treeController.removeTaggedNode(nodeParent, tag, node); } } }); }, error: function error(err) { controller.error(err); }, complete: function complete() { controller.end(); } }); } }); _this2._subscriptions.push(ecSet.subscribe({})); return [tag, { liveSet: liveSet, controller: controller, ecSet: ecSet }]; })); this._options.watchers.forEach(function (_ref2) { var sources = _ref2.sources, selectors = _ref2.selectors, tag = _ref2.tag; var sourceSets = sources.map(function (tag) { if (!tag) return _this2._rootMatchedSet; var entry = _this2._ecSources.get(tag); if (!entry) throw new Error('Unknown source: ' + tag); return entry.ecSet; }); var sourceSet = sourceSets.length === 1 ? sourceSets[0] : (0, _merge["default"])(sourceSets); var transformer = (0, _createTransformer["default"])(_this2._scheduler, selectors); var ecEntry = _this2._ecSources.get(tag); if (!ecEntry) throw new Error(); ecEntry.controller.add(transformer(sourceSet)); }); this._scheduler.flush(); } }, { key: "_dumpWithoutEnd", value: function _dumpWithoutEnd() { var _this3 = this; this._subscriptions.forEach(function (sub) { sub.unsubscribe(); }); this._subscriptions.length = 0; this.tree.getOwned().forEach(function (liveSet, tag) { liveSet.values().forEach(function (node) { _this3._treeController.removeTaggedNode(_this3.tree, tag, node); }); }); } }, { key: "dump", value: function dump() { this._dumpWithoutEnd(); this._treeController.end(); } // Intended for use with hot module replacement. }, { key: "replaceOptions", value: function replaceOptions(options) { var tagErrStr = 'replaceOptions does not support tag changes'; var _makeTagOptions2 = makeTagOptions(options), tagOptionsMap = _makeTagOptions2.map; if (this._tagOptions.size !== tagOptionsMap.size) { throw new Error(tagErrStr); } this._tagOptions.forEach(function (oldOptions, tag) { var newOptions = tagOptionsMap.get(tag); if (!newOptions) throw new Error(tagErrStr); var oldOwnedBy = oldOptions.ownedBy || []; var newOwnedBy = new Set(newOptions.ownedBy || []); if (oldOwnedBy.length !== newOwnedBy.size) throw new Error(tagErrStr); oldOwnedBy.forEach(function (tag) { if (!newOwnedBy.has(tag)) throw new Error(tagErrStr); }); }); this._dumpWithoutEnd(); this._options = options; this._setupWatchersAndFinders(); } }]); return PageParserTree; }(); exports["default"] = PageParserTree; module.exports = exports.default; module.exports.default = exports.default; //# sourceMappingURL=index.js.map