UNPKG

@gamestdio/state-listener

Version:

Deeply compare JavaScript objects and listen to changes.

124 lines (123 loc) 4.51 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var compare_1 = require("./compare"); var StateContainer = /** @class */ (function () { function StateContainer(state) { this.listeners = []; this.matcherPlaceholders = { ":id": /^([a-zA-Z0-9\-_]+)$/, ":number": /^([0-9]+)$/, ":string": /^(\w+)$/, ":axis": /^([xyz])$/, ":*": /(.*)/, }; this.state = state; this.reset(); } StateContainer.prototype.set = function (newState) { var patches = compare_1.compare(this.state, newState); this.state = newState; this.checkPatches(patches, this.listeners, this.defaultListener); return patches; }; StateContainer.prototype.registerPlaceholder = function (placeholder, matcher) { this.matcherPlaceholders[placeholder] = matcher; }; StateContainer.prototype.listen = function (segments, callback, immediate) { var _this = this; var rules; if (typeof (segments) === "function") { rules = []; callback = segments; } else { rules = segments.split("/"); } if (callback.length > 1) { console.warn(".listen() accepts only one parameter."); } var listener = { callback: callback, rawRules: rules, rules: rules.map(function (segment) { if (typeof (segment) === "string") { // replace placeholder matchers return (segment.indexOf(":") === 0) ? _this.matcherPlaceholders[segment] || _this.matcherPlaceholders[":*"] : new RegExp("^" + segment + "$"); } else { return segment; } }) }; if (rules.length === 0) { this.defaultListener = listener; } else { this.listeners.push(listener); } // immediatelly try to trigger this listener. if (immediate) { this.checkPatches(compare_1.compare({}, this.state), [listener]); } return listener; }; StateContainer.prototype.removeListener = function (listener) { for (var i = this.listeners.length - 1; i >= 0; i--) { if (this.listeners[i] === listener) { this.listeners.splice(i, 1); } } }; StateContainer.prototype.removeAllListeners = function () { this.reset(); }; StateContainer.prototype.checkPatches = function (patches, listeners, defaultListener) { for (var j = 0, len = listeners.length; j < len; j++) { var listener = listeners[j]; for (var i = patches.length - 1; i >= 0; i--) { var pathVariables = listener && this.getPathVariables(patches[i], listener); if (pathVariables) { listener.callback({ path: pathVariables, rawPath: patches[i].path, operation: patches[i].operation, value: patches[i].value }); patches[i].matched = true; } } } // trigger default listener callback with each unmatched patch if (defaultListener) { for (var i = patches.length - 1; i >= 0; i--) { if (!patches[i].matched) { defaultListener.callback(patches[i]); } } } }; StateContainer.prototype.getPathVariables = function (patch, listener) { // skip if rules count differ from patch if (patch.path.length !== listener.rules.length) { return false; } var path = {}; for (var i = 0, len = listener.rules.length; i < len; i++) { var matches = patch.path[i].match(listener.rules[i]); if (!matches || matches.length === 0 || matches.length > 2) { return false; } else if (listener.rawRules[i].substr(0, 1) === ":") { path[listener.rawRules[i].substr(1)] = matches[1]; } } return path; }; StateContainer.prototype.reset = function () { this.listeners = []; }; return StateContainer; }()); exports.StateContainer = StateContainer;