UNPKG

mobx-location

Version:

minimal observable wrapper around browser location utilizing popstate event of HTML5 history api

1,355 lines (1,300 loc) 178 kB
// modules are defined as an array // [ module function, map of requires ] // // map of requires is short require name -> numeric require // // anything defined in a previous bundle is accessed via the // orig method which is the require for previous bundles // eslint-disable-next-line no-global-assign parcelRequire = (function (modules, cache, entry, globalName) { // Save the require from previous bundle to this closure if any var previousRequire = typeof parcelRequire === 'function' && parcelRequire; var nodeRequire = typeof require === 'function' && require; function newRequire(name, jumped) { if (!cache[name]) { if (!modules[name]) { // if we cannot find the module within our internal map or // cache jump to the current global require ie. the last bundle // that was added to the page. var currentRequire = typeof parcelRequire === 'function' && parcelRequire; if (!jumped && currentRequire) { return currentRequire(name, true); } // If there are other bundles on this page the require from the // previous one is saved to 'previousRequire'. Repeat this as // many times as there are bundles until the module is found or // we exhaust the require chain. if (previousRequire) { return previousRequire(name, true); } // Try the node require function if it exists. if (nodeRequire && typeof name === 'string') { return nodeRequire(name); } var err = new Error('Cannot find module \'' + name + '\''); err.code = 'MODULE_NOT_FOUND'; throw err; } localRequire.resolve = resolve; var module = cache[name] = new newRequire.Module(name); modules[name][0].call(module.exports, localRequire, module, module.exports, this); } return cache[name].exports; function localRequire(x){ return newRequire(localRequire.resolve(x)); } function resolve(x){ return modules[name][1][x] || x; } } function Module(moduleName) { this.id = moduleName; this.bundle = newRequire; this.exports = {}; } newRequire.isParcelRequire = true; newRequire.Module = Module; newRequire.modules = modules; newRequire.cache = cache; newRequire.parent = previousRequire; for (var i = 0; i < entry.length; i++) { newRequire(entry[i]); } if (entry.length) { // Expose entry point to Node, AMD or browser globals // Based on https://github.com/ForbesLindesay/umd/blob/master/template.js var mainExports = newRequire(entry[entry.length - 1]); // CommonJS if (typeof exports === "object" && typeof module !== "undefined") { module.exports = mainExports; // RequireJS } else if (typeof define === "function" && define.amd) { define(function () { return mainExports; }); // <script> } else if (globalName) { this[globalName] = mainExports; } } // Override the current require with this new one return newRequire; })({9:[function(require,module,exports) { // shim for using process in browser var process = module.exports = {}; // cached from whatever global is present so that test runners that stub it // don't break things. But we need to wrap it in a try catch in case it is // wrapped in strict mode code which doesn't define any globals. It's inside a // function because try/catches deoptimize in certain engines. var cachedSetTimeout; var cachedClearTimeout; function defaultSetTimout() { throw new Error('setTimeout has not been defined'); } function defaultClearTimeout() { throw new Error('clearTimeout has not been defined'); } (function () { try { if (typeof setTimeout === 'function') { cachedSetTimeout = setTimeout; } else { cachedSetTimeout = defaultSetTimout; } } catch (e) { cachedSetTimeout = defaultSetTimout; } try { if (typeof clearTimeout === 'function') { cachedClearTimeout = clearTimeout; } else { cachedClearTimeout = defaultClearTimeout; } } catch (e) { cachedClearTimeout = defaultClearTimeout; } })(); function runTimeout(fun) { if (cachedSetTimeout === setTimeout) { //normal enviroments in sane situations return setTimeout(fun, 0); } // if setTimeout wasn't available but was latter defined if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { cachedSetTimeout = setTimeout; return setTimeout(fun, 0); } try { // when when somebody has screwed with setTimeout but no I.E. maddness return cachedSetTimeout(fun, 0); } catch (e) { try { // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally return cachedSetTimeout.call(null, fun, 0); } catch (e) { // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error return cachedSetTimeout.call(this, fun, 0); } } } function runClearTimeout(marker) { if (cachedClearTimeout === clearTimeout) { //normal enviroments in sane situations return clearTimeout(marker); } // if clearTimeout wasn't available but was latter defined if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { cachedClearTimeout = clearTimeout; return clearTimeout(marker); } try { // when when somebody has screwed with setTimeout but no I.E. maddness return cachedClearTimeout(marker); } catch (e) { try { // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally return cachedClearTimeout.call(null, marker); } catch (e) { // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. // Some versions of I.E. have different rules for clearTimeout vs setTimeout return cachedClearTimeout.call(this, marker); } } } var queue = []; var draining = false; var currentQueue; var queueIndex = -1; function cleanUpNextTick() { if (!draining || !currentQueue) { return; } draining = false; if (currentQueue.length) { queue = currentQueue.concat(queue); } else { queueIndex = -1; } if (queue.length) { drainQueue(); } } function drainQueue() { if (draining) { return; } var timeout = runTimeout(cleanUpNextTick); draining = true; var len = queue.length; while (len) { currentQueue = queue; queue = []; while (++queueIndex < len) { if (currentQueue) { currentQueue[queueIndex].run(); } } queueIndex = -1; len = queue.length; } currentQueue = null; draining = false; runClearTimeout(timeout); } process.nextTick = function (fun) { var args = new Array(arguments.length - 1); if (arguments.length > 1) { for (var i = 1; i < arguments.length; i++) { args[i - 1] = arguments[i]; } } queue.push(new Item(fun, args)); if (queue.length === 1 && !draining) { runTimeout(drainQueue); } }; // v8 likes predictible objects function Item(fun, array) { this.fun = fun; this.array = array; } Item.prototype.run = function () { this.fun.apply(null, this.array); }; process.title = 'browser'; process.browser = true; process.env = {}; process.argv = []; process.version = ''; // empty string to avoid regexp issues process.versions = {}; function noop() {} process.on = noop; process.addListener = noop; process.once = noop; process.off = noop; process.removeListener = noop; process.removeAllListeners = noop; process.emit = noop; process.prependListener = noop; process.prependOnceListener = noop; process.listeners = function (name) { return []; }; process.binding = function (name) { throw new Error('process.binding is not supported'); }; process.cwd = function () { return '/'; }; process.chdir = function (dir) { throw new Error('process.chdir is not supported'); }; process.umask = function () { return 0; }; },{}],5:[function(require,module,exports) { var process = require("process"); var global = arguments[3]; "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /** MobX - (c) Michel Weststrate 2015, 2016 - MIT Licensed */ /*! ***************************************************************************** Copyright (c) Microsoft Corporation. All rights reserved. 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 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. ***************************************************************************** */ /* global Reflect, Promise */ var extendStatics = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; } || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; function __extends(d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var __assign = Object.assign || function __assign(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; }; function __read(o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; } function __spread() { for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); return ar; } var enumerableDescriptorCache = {}; var nonEnumerableDescriptorCache = {}; function createPropertyInitializerDescriptor(prop, enumerable) { var cache = enumerable ? enumerableDescriptorCache : nonEnumerableDescriptorCache; return cache[prop] || (cache[prop] = { configurable: true, enumerable: enumerable, get: function () { initializeInstance(this); return this[prop]; }, set: function (value) { initializeInstance(this); this[prop] = value; } }); } function initializeInstance(target) { if (target.__mobxDidRunLazyInitializers === true) return; var decorators = target.__mobxDecorators; if (decorators) { addHiddenProp(target, "__mobxDidRunLazyInitializers", true); for (var key in decorators) { var d = decorators[key]; d.propertyCreator(target, d.prop, d.descriptor, d.decoratorTarget, d.decoratorArguments); } } } function createPropDecorator(propertyInitiallyEnumerable, propertyCreator) { return function decoratorFactory() { var decoratorArguments; var decorator = function decorate(target, prop, descriptor, applyImmediately // This is a special parameter to signal the direct application of a decorator, allow extendObservable to skip the entire type decoration part, // as the instance to apply the decorator to equals the target ) { if (applyImmediately === true) { propertyCreator(target, prop, descriptor, target, decoratorArguments); return null; } if (undefined !== "production" && !quacksLikeADecorator(arguments)) fail$1("This function is a decorator, but it wasn't invoked like a decorator"); if (!Object.prototype.hasOwnProperty.call(target, "__mobxDecorators")) { var inheritedDecorators = target.__mobxDecorators; addHiddenProp(target, "__mobxDecorators", __assign({}, inheritedDecorators)); } target.__mobxDecorators[prop] = { prop: prop, propertyCreator: propertyCreator, descriptor: descriptor, decoratorTarget: target, decoratorArguments: decoratorArguments }; return createPropertyInitializerDescriptor(prop, propertyInitiallyEnumerable); }; if (quacksLikeADecorator(arguments)) { // @decorator decoratorArguments = EMPTY_ARRAY; return decorator.apply(null, arguments); } else { // @decorator(args) decoratorArguments = Array.prototype.slice.call(arguments); return decorator; } }; } function quacksLikeADecorator(args) { return (args.length === 2 || args.length === 3) && typeof args[1] === "string" || args.length === 4 && args[3] === true; } function isSpyEnabled() { return !!globalState.spyListeners.length; } function spyReport(event) { if (!globalState.spyListeners.length) return; var listeners = globalState.spyListeners; for (var i = 0, l = listeners.length; i < l; i++) listeners[i](event); } function spyReportStart(event) { var change = __assign({}, event, { spyReportStart: true }); spyReport(change); } var END_EVENT = { spyReportEnd: true }; function spyReportEnd(change) { if (change) spyReport(__assign({}, change, { spyReportEnd: true }));else spyReport(END_EVENT); } function spy(listener) { globalState.spyListeners.push(listener); return once(function () { globalState.spyListeners = globalState.spyListeners.filter(function (l) { return l !== listener; }); }); } function createAction(actionName, fn) { if (undefined !== "production") { invariant(typeof fn === "function", "`action` can only be invoked on functions"); if (typeof actionName !== "string" || !actionName) fail$1("actions should have valid names, got: '" + actionName + "'"); } var res = function () { return executeAction(actionName, fn, this, arguments); }; res.isMobxAction = true; return res; } function executeAction(actionName, fn, scope, args) { var runInfo = startAction(actionName, fn, scope, args); try { return fn.apply(scope, args); } finally { endAction(runInfo); } } function startAction(actionName, fn, scope, args) { var notifySpy = isSpyEnabled() && !!actionName; var startTime = 0; if (notifySpy) { startTime = Date.now(); var l = args && args.length || 0; var flattendArgs = new Array(l); if (l > 0) for (var i = 0; i < l; i++) flattendArgs[i] = args[i]; spyReportStart({ type: "action", name: actionName, object: scope, arguments: flattendArgs }); } var prevDerivation = untrackedStart(); startBatch(); var prevAllowStateChanges = allowStateChangesStart(true); return { prevDerivation: prevDerivation, prevAllowStateChanges: prevAllowStateChanges, notifySpy: notifySpy, startTime: startTime }; } function endAction(runInfo) { allowStateChangesEnd(runInfo.prevAllowStateChanges); endBatch(); untrackedEnd(runInfo.prevDerivation); if (runInfo.notifySpy) spyReportEnd({ time: Date.now() - runInfo.startTime }); } function allowStateChanges(allowStateChanges, func) { var prev = allowStateChangesStart(allowStateChanges); var res; try { res = func(); } finally { allowStateChangesEnd(prev); } return res; } function allowStateChangesStart(allowStateChanges) { var prev = globalState.allowStateChanges; globalState.allowStateChanges = allowStateChanges; return prev; } function allowStateChangesEnd(prev) { globalState.allowStateChanges = prev; } function dontReassignFields() { fail$1(undefined !== "production" && "@action fields are not reassignable"); } function namedActionDecorator(name) { return function (target, prop, descriptor) { if (descriptor) { if (undefined !== "production" && descriptor.get !== undefined) { return fail$1("@action cannot be used with getters"); } // babel / typescript // @action method() { } if (descriptor.value) { // typescript return { value: createAction(name, descriptor.value), enumerable: false, configurable: true, writable: true // for typescript, this must be writable, otherwise it cannot inherit :/ (see inheritable actions test) }; } // babel only: @action method = () => {} var initializer_1 = descriptor.initializer; return { enumerable: false, configurable: true, writable: true, initializer: function () { // N.B: we can't immediately invoke initializer; this would be wrong return createAction(name, initializer_1.call(this)); } }; } // bound instance methods return actionFieldDecorator(name).apply(this, arguments); }; } function actionFieldDecorator(name) { // Simple property that writes on first invocation to the current instance return function (target, prop, descriptor) { Object.defineProperty(target, prop, { configurable: true, enumerable: false, get: function () { return undefined; }, set: function (value) { addHiddenFinalProp(this, prop, action(name, value)); } }); }; } function boundActionDecorator(target, propertyName, descriptor, applyToInstance) { if (applyToInstance === true) { defineBoundAction(target, propertyName, descriptor.value); return null; } if (descriptor) { // if (descriptor.value) // Typescript / Babel: @action.bound method() { } // also: babel @action.bound method = () => {} return { configurable: true, enumerable: false, get: function () { defineBoundAction(this, propertyName, descriptor.value || descriptor.initializer.call(this)); return this[propertyName]; }, set: dontReassignFields }; } // field decorator Typescript @action.bound method = () => {} return { enumerable: false, configurable: true, set: function (v) { defineBoundAction(this, propertyName, v); }, get: function () { return undefined; } }; } var action = function action(arg1, arg2, arg3, arg4) { // action(fn() {}) if (arguments.length === 1 && typeof arg1 === "function") return createAction(arg1.name || "<unnamed action>", arg1); // action("name", fn() {}) if (arguments.length === 2 && typeof arg2 === "function") return createAction(arg1, arg2); // @action("name") fn() {} if (arguments.length === 1 && typeof arg1 === "string") return namedActionDecorator(arg1); // @action fn() {} if (arg4 === true) { // apply to instance immediately arg1[arg2] = createAction(arg1.name || arg2, arg3.value); } else { return namedActionDecorator(arg2).apply(null, arguments); } }; action.bound = boundActionDecorator; function runInAction(arg1, arg2) { // TODO: deprecate? var actionName = typeof arg1 === "string" ? arg1 : arg1.name || "<unnamed action>"; var fn = typeof arg1 === "function" ? arg1 : arg2; if (undefined !== "production") { invariant(typeof fn === "function" && fn.length === 0, "`runInAction` expects a function without arguments"); if (typeof actionName !== "string" || !actionName) fail$1("actions should have valid names, got: '" + actionName + "'"); } return executeAction(actionName, fn, this, undefined); } function isAction(thing) { return typeof thing === "function" && thing.isMobxAction === true; } function defineBoundAction(target, propertyName, fn) { addHiddenProp(target, propertyName, createAction(propertyName, fn.bind(target))); } var toString = Object.prototype.toString; function deepEqual(a, b) { return eq(a, b); } // Copied from https://github.com/jashkenas/underscore/blob/5c237a7c682fb68fd5378203f0bf22dce1624854/underscore.js#L1186-L1289 // Internal recursive comparison function for `isEqual`. function eq(a, b, aStack, bStack) { // Identical objects are equal. `0 === -0`, but they aren't identical. // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). if (a === b) return a !== 0 || 1 / a === 1 / b; // `null` or `undefined` only equal to itself (strict comparison). if (a == null || b == null) return false; // `NaN`s are equivalent, but non-reflexive. if (a !== a) return b !== b; // Exhaust primitive checks var type = typeof a; if (type !== "function" && type !== "object" && typeof b != "object") return false; return deepEq(a, b, aStack, bStack); } // Internal recursive comparison function for `isEqual`. function deepEq(a, b, aStack, bStack) { // Unwrap any wrapped objects. a = unwrap(a); b = unwrap(b); // Compare `[[Class]]` names. var className = toString.call(a); if (className !== toString.call(b)) return false; switch (className) { // Strings, numbers, regular expressions, dates, and booleans are compared by value. case "[object RegExp]": // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') case "[object String]": // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is // equivalent to `new String("5")`. return "" + a === "" + b; case "[object Number]": // `NaN`s are equivalent, but non-reflexive. // Object(NaN) is equivalent to NaN. if (+a !== +a) return +b !== +b; // An `egal` comparison is performed for other numeric values. return +a === 0 ? 1 / +a === 1 / b : +a === +b; case "[object Date]": case "[object Boolean]": // Coerce dates and booleans to numeric primitive values. Dates are compared by their // millisecond representations. Note that invalid dates with millisecond representations // of `NaN` are not equivalent. return +a === +b; case "[object Symbol]": return typeof Symbol !== "undefined" && Symbol.valueOf.call(a) === Symbol.valueOf.call(b); } var areArrays = className === "[object Array]"; if (!areArrays) { if (typeof a != "object" || typeof b != "object") return false; // Objects with different constructors are not equivalent, but `Object`s or `Array`s // from different frames are. var aCtor = a.constructor, bCtor = b.constructor; if (aCtor !== bCtor && !(typeof aCtor === "function" && aCtor instanceof aCtor && typeof bCtor === "function" && bCtor instanceof bCtor) && "constructor" in a && "constructor" in b) { return false; } } // Assume equality for cyclic structures. The algorithm for detecting cyclic // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. // Initializing stack of traversed objects. // It's done here since we only need them for objects and arrays comparison. aStack = aStack || []; bStack = bStack || []; var length = aStack.length; while (length--) { // Linear search. Performance is inversely proportional to the number of // unique nested structures. if (aStack[length] === a) return bStack[length] === b; } // Add the first object to the stack of traversed objects. aStack.push(a); bStack.push(b); // Recursively compare objects and arrays. if (areArrays) { // Compare array lengths to determine if a deep comparison is necessary. length = a.length; if (length !== b.length) return false; // Deep compare the contents, ignoring non-numeric properties. while (length--) { if (!eq(a[length], b[length], aStack, bStack)) return false; } } else { // Deep compare objects. var keys$$1 = Object.keys(a), key; length = keys$$1.length; // Ensure that both objects contain the same number of properties before comparing deep equality. if (Object.keys(b).length !== length) return false; while (length--) { // Deep compare each member key = keys$$1[length]; if (!(has$$1(b, key) && eq(a[key], b[key], aStack, bStack))) return false; } } // Remove the first object from the stack of traversed objects. aStack.pop(); bStack.pop(); return true; } function unwrap(a) { if (isObservableArray(a)) return a.peek(); if (isES6Map(a) || isObservableMap(a)) return iteratorToArray(a.entries()); return a; } function has$$1(a, key) { return Object.prototype.hasOwnProperty.call(a, key); } function identityComparer(a, b) { return a === b; } function structuralComparer(a, b) { return deepEqual(a, b); } function defaultComparer(a, b) { return areBothNaN(a, b) || identityComparer(a, b); } var comparer = { identity: identityComparer, structural: structuralComparer, default: defaultComparer }; /** * Creates a named reactive view and keeps it alive, so that the view is always * updated if one of the dependencies changes, even when the view is not further used by something else. * @param view The reactive view * @returns disposer function, which can be used to stop the view from being updated in the future. */ function autorun(view, opts) { if (opts === void 0) { opts = EMPTY_OBJECT; } if (undefined !== "production") { invariant(typeof view === "function", "Autorun expects a function as first argument"); invariant(isAction(view) === false, "Autorun does not accept actions since actions are untrackable"); } var name = opts && opts.name || view.name || "Autorun@" + getNextId(); var runSync = !opts.scheduler && !opts.delay; var reaction; if (runSync) { // normal autorun reaction = new Reaction(name, function () { this.track(reactionRunner); }, opts.onError); } else { var scheduler_1 = createSchedulerFromOptions(opts); // debounced autorun var isScheduled_1 = false; reaction = new Reaction(name, function () { if (!isScheduled_1) { isScheduled_1 = true; scheduler_1(function () { isScheduled_1 = false; if (!reaction.isDisposed) reaction.track(reactionRunner); }); } }, opts.onError); } function reactionRunner() { view(reaction); } reaction.schedule(); return reaction.getDisposer(); } var run = function (f) { return f(); }; function createSchedulerFromOptions(opts) { return opts.scheduler ? opts.scheduler : opts.delay ? function (f) { return setTimeout(f, opts.delay); } : run; } function reaction(expression, effect, opts) { if (opts === void 0) { opts = EMPTY_OBJECT; } if (typeof opts === "boolean") { opts = { fireImmediately: opts }; deprecated("Using fireImmediately as argument is deprecated. Use '{ fireImmediately: true }' instead"); } if (undefined !== "production") { invariant(typeof expression === "function", "First argument to reaction should be a function"); invariant(typeof opts === "object", "Third argument of reactions should be an object"); } var name = opts.name || "Reaction@" + getNextId(); var effectAction = action(name, opts.onError ? wrapErrorHandler(opts.onError, effect) : effect); var runSync = !opts.scheduler && !opts.delay; var scheduler = createSchedulerFromOptions(opts); var firstTime = true; var isScheduled = false; var value; var equals = opts.compareStructural ? comparer.structural : opts.equals || comparer.default; var r = new Reaction(name, function () { if (firstTime || runSync) { reactionRunner(); } else if (!isScheduled) { isScheduled = true; scheduler(reactionRunner); } }, opts.onError); function reactionRunner() { isScheduled = false; // Q: move into reaction runner? if (r.isDisposed) return; var changed = false; r.track(function () { var nextValue = expression(r); changed = firstTime || !equals(value, nextValue); value = nextValue; }); if (firstTime && opts.fireImmediately) effectAction(value, r); if (!firstTime && changed === true) effectAction(value, r); if (firstTime) firstTime = false; } r.schedule(); return r.getDisposer(); } function wrapErrorHandler(errorHandler, baseFn) { return function () { try { return baseFn.apply(this, arguments); } catch (e) { errorHandler.call(this, e); } }; } /** * A node in the state dependency root that observes other nodes, and can be observed itself. * * ComputedValue will remember the result of the computation for the duration of the batch, or * while being observed. * * During this time it will recompute only when one of its direct dependencies changed, * but only when it is being accessed with `ComputedValue.get()`. * * Implementation description: * 1. First time it's being accessed it will compute and remember result * give back remembered result until 2. happens * 2. First time any deep dependency change, propagate POSSIBLY_STALE to all observers, wait for 3. * 3. When it's being accessed, recompute if any shallow dependency changed. * if result changed: propagate STALE to all observers, that were POSSIBLY_STALE from the last step. * go to step 2. either way * * If at any point it's outside batch and it isn't observed: reset everything and go to 1. */ var ComputedValue = /** @class */function () { /** * Create a new computed value based on a function expression. * * The `name` property is for debug purposes only. * * The `equals` property specifies the comparer function to use to determine if a newly produced * value differs from the previous value. Two comparers are provided in the library; `defaultComparer` * compares based on identity comparison (===), and `structualComparer` deeply compares the structure. * Structural comparison can be convenient if you always produce an new aggregated object and * don't want to notify observers if it is structurally the same. * This is useful for working with vectors, mouse coordinates etc. */ function ComputedValue(options) { var _this = this; this.dependenciesState = IDerivationState.NOT_TRACKING; this.observing = []; // nodes we are looking at. Our value depends on these nodes this.newObserving = null; // during tracking it's an array with new observed observers this.isBeingObserved = false; this.isPendingUnobservation = false; this.observers = []; this.observersIndexes = {}; this.diffValue = 0; this.runId = 0; this.lastAccessedBy = 0; this.lowestObserverState = IDerivationState.UP_TO_DATE; this.unboundDepsCount = 0; this.__mapid = "#" + getNextId(); this.value = new CaughtException(null); this.isComputing = false; // to check for cycles this.isRunningSetter = false; this.isTracing = TraceMode.NONE; if (undefined !== "production" && !options.get) return fail$1("missing option for computed: get"); this.derivation = options.get; this.name = options.name || "ComputedValue@" + getNextId(); if (options.set) this.setter = createAction(this.name + "-setter", options.set); this.equals = options.equals || (options.compareStructural || options.struct ? comparer.structural : comparer.default); this.scope = options.context; this.requiresReaction = !!options.requiresReaction; if (options.keepAlive === true) { // dangerous: never exposed, so this cmputed value should not depend on observables // that live globally, or it will never get disposed! (nor anything attached to it) autorun(function () { return _this.get(); }); } } ComputedValue.prototype.onBecomeStale = function () { propagateMaybeChanged(this); }; ComputedValue.prototype.onBecomeUnobserved = function () {}; ComputedValue.prototype.onBecomeObserved = function () {}; /** * Returns the current value of this computed value. * Will evaluate its computation first if needed. */ ComputedValue.prototype.get = function () { if (this.isComputing) fail$1("Cycle detected in computation " + this.name + ": " + this.derivation); if (globalState.inBatch === 0) { if (shouldCompute(this)) { this.warnAboutUntrackedRead(); startBatch(); // See perf test 'computed memoization' this.value = this.computeValue(false); endBatch(); } } else { reportObserved(this); if (shouldCompute(this)) if (this.trackAndCompute()) propagateChangeConfirmed(this); } var result = this.value; if (isCaughtException(result)) throw result.cause; return result; }; ComputedValue.prototype.peek = function () { var res = this.computeValue(false); if (isCaughtException(res)) throw res.cause; return res; }; ComputedValue.prototype.set = function (value) { if (this.setter) { invariant(!this.isRunningSetter, "The setter of computed value '" + this.name + "' is trying to update itself. Did you intend to update an _observable_ value, instead of the computed property?"); this.isRunningSetter = true; try { this.setter.call(this.scope, value); } finally { this.isRunningSetter = false; } } else invariant(false, undefined !== "production" && "[ComputedValue '" + this.name + "'] It is not possible to assign a new value to a computed value."); }; ComputedValue.prototype.trackAndCompute = function () { if (isSpyEnabled()) { spyReport({ object: this.scope, type: "compute", name: this.name }); } var oldValue = this.value; var wasSuspended = /* see #1208 */this.dependenciesState === IDerivationState.NOT_TRACKING; var newValue = this.computeValue(true); var changed = wasSuspended || isCaughtException(oldValue) || isCaughtException(newValue) || !this.equals(oldValue, newValue); if (changed) { this.value = newValue; } return changed; }; ComputedValue.prototype.computeValue = function (track) { this.isComputing = true; globalState.computationDepth++; var res; if (track) { res = trackDerivedFunction(this, this.derivation, this.scope); } else { if (globalState.disableErrorBoundaries === true) { res = this.derivation.call(this.scope); } else { try { res = this.derivation.call(this.scope); } catch (e) { res = new CaughtException(e); } } } globalState.computationDepth--; this.isComputing = false; return res; }; ComputedValue.prototype.suspend = function () { clearObserving(this); this.value = undefined; // don't hold on to computed value! }; ComputedValue.prototype.observe = function (listener, fireImmediately) { var _this = this; var firstTime = true; var prevValue = undefined; return autorun(function () { var newValue = _this.get(); if (!firstTime || fireImmediately) { var prevU = untrackedStart(); listener({ type: "update", object: _this, newValue: newValue, oldValue: prevValue }); untrackedEnd(prevU); } firstTime = false; prevValue = newValue; }); }; ComputedValue.prototype.warnAboutUntrackedRead = function () { if (undefined === "production") return; if (this.requiresReaction === true) { fail$1("[mobx] Computed value " + this.name + " is read outside a reactive context"); } if (this.isTracing !== TraceMode.NONE) { console.log("[mobx.trace] '" + this.name + "' is being read outside a reactive context. Doing a full recompute"); } if (globalState.computedRequiresReaction) { console.warn("[mobx] Computed value " + this.name + " is being read outside a reactive context. Doing a full recompute"); } }; ComputedValue.prototype.toJSON = function () { return this.get(); }; ComputedValue.prototype.toString = function () { return this.name + "[" + this.derivation.toString() + "]"; }; ComputedValue.prototype.valueOf = function () { return toPrimitive(this.get()); }; return ComputedValue; }(); ComputedValue.prototype[primitiveSymbol()] = ComputedValue.prototype.valueOf; var isComputedValue = createInstanceofPredicate("ComputedValue", ComputedValue); function hasInterceptors(interceptable) { return interceptable.interceptors !== undefined && interceptable.interceptors.length > 0; } function registerInterceptor(interceptable, handler) { var interceptors = interceptable.interceptors || (interceptable.interceptors = []); interceptors.push(handler); return once(function () { var idx = interceptors.indexOf(handler); if (idx !== -1) interceptors.splice(idx, 1); }); } function interceptChange(interceptable, change) { var prevU = untrackedStart(); try { var interceptors = interceptable.interceptors; if (interceptors) for (var i = 0, l = interceptors.length; i < l; i++) { change = interceptors[i](change); invariant(!change || change.type, "Intercept handlers should return nothing or a change object"); if (!change) break; } return change; } finally { untrackedEnd(prevU); } } function hasListeners(listenable) { return listenable.changeListeners !== undefined && listenable.changeListeners.length > 0; } function registerListener(listenable, handler) { var listeners = listenable.changeListeners || (listenable.changeListeners = []); listeners.push(handler); return once(function () { var idx = listeners.indexOf(handler); if (idx !== -1) listeners.splice(idx, 1); }); } function notifyListeners(listenable, change) { var prevU = untrackedStart(); var listeners = listenable.changeListeners; if (!listeners) return; listeners = listeners.slice(); for (var i = 0, l = listeners.length; i < l; i++) { listeners[i](change); } untrackedEnd(prevU); } var UNCHANGED = {}; declareAtom(); var ObservableValue = /** @class */function (_super) { __extends(ObservableValue, _super); function ObservableValue(value, enhancer, name, notifySpy) { if (name === void 0) { name = "ObservableValue@" + getNextId(); } if (notifySpy === void 0) { notifySpy = true; } var _this = _super.call(this, name) || this; _this.enhancer = enhancer; _this.hasUnreportedChange = false; _this.value = enhancer(value, undefined, name); if (notifySpy && isSpyEnabled()) { // only notify spy if this is a stand-alone observable spyReport({ type: "create", name: _this.name, newValue: "" + _this.value }); } return _this; } ObservableValue.prototype.dehanceValue = function (value) { if (this.dehancer !== undefined) return this.dehancer(value); return value; }; ObservableValue.prototype.set = function (newValue) { var oldValue = this.value; newValue = this.prepareNewValue(newValue); if (newValue !== UNCHANGED) { var notifySpy = isSpyEnabled(); if (notifySpy) { spyReportStart({ type: "update", name: this.name, newValue: newValue, oldValue: oldValue }); } this.setNewValue(newValue); if (notifySpy) spyReportEnd(); } }; ObservableValue.prototype.prepareNewValue = function (newValue) { checkIfStateModificationsAreAllowed(this); if (hasInterceptors(this)) { var change = interceptChange(this, { object: this, type: "update", newValue: newValue }); if (!change) return UNCHANGED; newValue = change.newValue; } // apply modifier newValue = this.enhancer(newValue, this.value, this.name); return this.value !== newValue ? newValue : UNCHANGED; }; ObservableValue.prototype.setNewValue = function (newValue) { var oldValue = this.value; this.value = newValue; this.reportChanged(); if (hasListeners(this)) { notifyListeners(this, { type: "update", object: this, newValue: newValue, oldValue: oldValue }); } }; ObservableValue.prototype.get = function () { this.reportObserved(); return this.dehanceValue(this.value); }; ObservableValue.prototype.intercept = function (handler) { return registerInterceptor(this, handler); }; ObservableValue.prototype.observe = function (listener, fireImmediately) { if (fireImmediately) listener({ object: this, type: "update", newValue: this.value, oldValue: undefined }); return registerListener(this, listener); }; ObservableValue.prototype.toJSON = function () { return this.get(); }; ObservableValue.prototype.toString = function () { return this.name + "[" + this.value + "]"; }; ObservableValue.prototype.valueOf = function () { return toPrimitive(this.get()); }; return ObservableValue; }(Atom); ObservableValue.prototype[primitiveSymbol()] = ObservableValue.prototype.valueOf; var isObservableValue = createInstanceofPredicate("ObservableValue", ObservableValue); var ObservableObjectAdministration = /** @class */function () { function ObservableObjectAdministration(target, name, defaultEnhancer) { this.target = target; this.name = name; this.defaultEnhancer = defaultEnhancer; this.values = {}; } ObservableObjectAdministration.prototype.read = function (owner, key) { if (this.target !== owner) { this.illegalAccess(owner, key); return; } return this.values[key].get(); }; ObservableObjectAdministration.prototype.write = function (owner, key, newValue) { var instance = this.target; if (instance !== owner) { this.illegalAccess(owner, key); return; } var observable = this.values[key]; if (observable instanceof ComputedValue) { observable.set(newValue); return; } // intercept if (hasInterceptors(this)) { var change = interceptChange(this, { type: "update", object: instance, name: key, newValue: newValue }); if (!change) return; newValue = change.newValue; } newValue = observable.prepareNewValue(newValue); // notify spy & observers if (newValue !== UNCHANGED) { var notify = hasListeners(this); var notifySpy = isSpyEnabled(); var change = notify || notifySpy ? { type: "update", object: instance, oldValue: observable.value, name: key, newValue: newValue } : null; if (notifySpy) spyReportStart(__assign({}, change, { name: this.name, key: key })); observable.setNewValue(newValue); if (notify) notifyListeners(this, change); if (notifySpy) spyReportEnd(); } }; ObservableObjectAdministration.prototype.remove = function (key) { if (!this.values[key]) return; var target = this.target; if (hasInterceptors(this)) { var change = interceptChange(this, { object: target, name: key, type: "remove" }); if (!change) return; } try { startBatch(); var notify = hasListeners(this); var notifySpy = isSpyEnabled(); var oldValue = this.values[key].get(); if (this.keys) this.keys.remove(key); delete this.values[key]; delete this.target[key]; var change = notify || notifySpy ? { type: "remove", object: target, oldValue: oldValue, name: key } : null; if (notifySpy) spyReportStart(__assign({}, change, { name: this.name, key: key })); if (notify) notifyListeners(this, change); if (notifySpy) spyReportEnd(); } finally { endBatch(); } }; ObservableObjectAdministration.prototype.illegalAccess = function (owner, propName) { /** * This happens if a property is accessed through the prototype chain, but the property was * declared directly as own property on the prototype. * * E.g.: * class A { * } * extendObservable(A.prototype, { x: 1 }) * * classB extens A { * } * console.log(new B().x) * * It is unclear whether the property should be considered 'static' or inherited. * Either use `console.log(A.x)` * or: decorate(A, { x: observable }) * * When using decorate, the property will always be redeclared as own property on the actual instance */ return fail$1("Property '" + propName + "' of '" + owner + "' was accessed through the prototype chain. Use 'decorate' instead to declare the prop or access it statically through it's owner"); }; /** * Observes this object. Triggers for the events 'add', 'update' and 'delete'. * See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/observe * for callback details */ ObservableObjectAdministration.prototype.observe = function (callback, fireImmediately) { undefined !== "production" && invariant(fireImmediately !== true, "`observe` doesn't support the fire immediately property for observable objects."); return registerListener(this, callback); }; ObservableObjectAdministration.prototype.intercept = function (handler) { return registerInterceptor(this, handler); }; ObservableObjectAdministration.prototype.getKeys = function () { var _this = this; if (this.keys === undefined) { this.keys = new ObservableArray(Object.keys(this.values).filter(function (key) { return _this.values[key] instanceof ObservableValue; }), referenceEnhancer, "keys(" + this.name + ")", true); } return this.keys.slice(); }; return ObservableObjectAdministration; }(); function asObservableObject(target, name, defaultEnhancer) { if (name === void 0) { name = ""; } if (defaultEnhancer === void 0) { defaultEnhancer = deepEnhancer; } var adm = target.$mobx; if (adm) return adm;