UNPKG

rxjs-autorun

Version:

Autorun expressions with RxJS Observables

146 lines (133 loc) 20.4 kB
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(require("rxjs"), require("rxjs/operators")); else if(typeof define === 'function' && define.amd) define("rxjs-autorun", ["rxjs", "rxjs/operators"], factory); else if(typeof exports === 'object') exports["rxjs-autorun"] = factory(require("rxjs"), require("rxjs/operators")); else root["rxjs-autorun"] = factory(root["rxjs"], root["rxjs"]["operators"]); })(window, function(__WEBPACK_EXTERNAL_MODULE_rxjs__, __WEBPACK_EXTERNAL_MODULE_rxjs_operators__) { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ /******/ // create a fake namespace object /******/ // mode & 1: value is a module id, require it /******/ // mode & 2: merge all properties of value into the ns /******/ // mode & 4: return value when already ns object /******/ // mode & 8|1: behave like require /******/ __webpack_require__.t = function(value, mode) { /******/ if(mode & 1) value = __webpack_require__(value); /******/ if(mode & 8) return value; /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; /******/ var ns = Object.create(null); /******/ __webpack_require__.r(ns); /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); /******/ return ns; /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = "/dist/"; /******/ /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = "./src/index.ts"); /******/ }) /************************************************************************/ /******/ ({ /***/ "./src/core.ts": /*!*********************!*\ !*** ./src/core.ts ***! \*********************/ /*! exports provided: TrackerError, forwardTracker, runner */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"TrackerError\", function() { return TrackerError; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"forwardTracker\", function() { return forwardTracker; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"runner\", function() { return runner; });\n/* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! rxjs */ \"rxjs\");\n/* harmony import */ var rxjs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(rxjs__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var rxjs_operators__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! rxjs/operators */ \"rxjs/operators\");\n/* harmony import */ var rxjs_operators__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__);\nvar __values = (undefined && undefined.__values) || function(o) {\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\n if (m) return m.call(o);\n if (o && typeof o.length === \"number\") return {\n next: function () {\n if (o && i >= o.length) o = void 0;\n return { value: o && o[i++], done: !o };\n }\n };\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\n};\n\n\n// an error to make mid-flight interruptions\n// when a value is still not available\nvar HALT_ERROR = Object.create(null);\n// error if tracker is used out of autorun/computed context\nvar TrackerError = new Error('$ or _ can only be called within computed or autorun context');\nvar errorTracker = function () { throw TrackerError; };\nerrorTracker.weak = errorTracker;\nerrorTracker.normal = errorTracker;\nerrorTracker.strong = errorTracker;\nvar context = {\n _: errorTracker,\n $: errorTracker\n};\nvar forwardTracker = function (tracker) {\n var r = (function (o) { return context[tracker](o); });\n r.weak = function (o) { return context[tracker].weak(o); };\n r.normal = function (o) { return context[tracker].normal(o); };\n r.strong = function (o) { return context[tracker].strong(o); };\n return r;\n};\nvar runner = function (fn, distinct) {\n if (distinct === void 0) { distinct = false; }\n return new rxjs__WEBPACK_IMPORTED_MODULE_0__[\"Observable\"](function (observer) {\n var deps = new Map();\n // context to be used for running expression\n var newCtx = {\n $: createTrackers(true),\n _: createTrackers(false)\n };\n // on unsubscribe/complete we destroy all subscriptions\n var sub = new rxjs__WEBPACK_IMPORTED_MODULE_0__[\"Subscription\"](function () {\n deps.forEach(function (dep) {\n dep.subscription.unsubscribe();\n });\n });\n // flag that indicates that current run might've affected completion status\n // we'll check completion after the first run\n var shouldCheckCompletion = true;\n // initial run\n runFn();\n return sub;\n function runFn() {\n // Mark all deps as untracked and unused, lowering normal to weak\n var loweredStrengthDeps = [];\n deps.forEach(function (dep) {\n dep.track = false;\n dep.used = false;\n // setting normal strength to weak, so that if previously `a` was\n // tracked as normal and in the latest run we only see `weak(a)` -\n // we can mark it as weak. this is restored if halted\n if (dep.strength === 1 /* Normal */) {\n dep.strength = 0 /* Weak */;\n loweredStrengthDeps.push(dep);\n }\n });\n var prevCtxt = context;\n context = newCtx;\n try {\n var result = fn();\n removeUnusedDeps(1 /* Normal */);\n observer.next(result);\n }\n catch (e) {\n // handling mid-flight interruption error\n // NOTE: check requires === strict equality\n if (e === HALT_ERROR) {\n // restore lowered strength\n loweredStrengthDeps.forEach(function (dep) {\n dep.strength = 1 /* Normal */;\n });\n // clean-up weak subscriptions\n removeUnusedDeps(0 /* Weak */);\n }\n else {\n // rethrow original errors\n observer.error(e);\n // we're errored, no need to check completion\n shouldCheckCompletion = false;\n }\n }\n finally {\n context = prevCtxt;\n // if this run was flagged as potentially completing\n if (shouldCheckCompletion) {\n checkCompletion();\n }\n }\n }\n function checkCompletion() {\n var e_1, _a;\n // reset the flag\n shouldCheckCompletion = false;\n try {\n // any dep is still running\n for (var _b = __values(deps.values()), _c = _b.next(); !_c.done; _c = _b.next()) {\n var dep = _c.value;\n if (dep.track && !dep.completed) {\n // one of the $-tracked deps is still running\n return;\n }\n }\n }\n catch (e_1_1) { e_1 = { error: e_1_1 }; }\n finally {\n try {\n if (_c && !_c.done && (_a = _b.return)) _a.call(_b);\n }\n finally { if (e_1) throw e_1.error; }\n }\n // All $-tracked deps completed\n observer.complete();\n }\n function removeUnusedDeps(ofStrength) {\n deps.forEach(function (dep, key) {\n if (dep.used || dep.strength > ofStrength) {\n return;\n }\n dep.subscription.unsubscribe();\n deps.delete(key);\n });\n }\n function createTrackers(track) {\n var r = createTracker(track, 1 /* Normal */);\n r.weak = createTracker(track, 0 /* Weak */);\n r.normal = createTracker(track, 1 /* Normal */);\n r.strong = createTracker(track, 2 /* Strong */);\n return r;\n }\n function createTracker(track, strength) {\n return function tracker(o) {\n if (deps.has(o)) {\n var v_1 = deps.get(o);\n v_1.used = true;\n if (track && !v_1.track) {\n // Previously tracked with _, but now also with $.\n // So completed state becomes relevant now.\n // Happens in case of e.g. computed(() => _(o) + $(o))\n v_1.track = true;\n }\n if (strength > v_1.strength) {\n // Previous tracking strength was weaker than it currently\n // is. So temporarily use the stronger version.\n v_1.strength = strength;\n }\n if (v_1.hasValue) {\n return v_1.value;\n }\n else {\n throw HALT_ERROR;\n }\n }\n var v = {\n hasValue: false,\n value: void 0,\n // Eagerly create subscription that can be destroyed.\n subscription: new rxjs__WEBPACK_IMPORTED_MODULE_0__[\"Subscription\"](),\n strength: strength,\n track: true,\n used: true,\n completed: false\n };\n deps.set(o, v);\n // Sync Code Section {{{\n // NOTE: we will synchronously (immediately) evaluate observables\n // that can synchronously emit a value. Such observables as:\n // - of(…)\n // - o.pipe( startWith(…) )\n // - BehaviorSubject\n // - ReplaySubject\n // - etc\n var isAsync = false;\n var hasSyncError = false;\n var syncError = void 0;\n v.subscription.add((distinct\n ? o.pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_1__[\"distinctUntilChanged\"])())\n : o)\n .subscribe({\n next: function (value) {\n var hadValue = v.hasValue;\n v.hasValue = true;\n v.value = value;\n var isUntrackFirstValue = !hadValue && !track;\n // It could be that all tracked deps already completed.\n // So signal that completion state might have changed.\n if (isUntrackFirstValue) {\n shouldCheckCompletion = true;\n }\n if (isAsync && v.track) {\n runFn();\n }\n if (isUntrackFirstValue) {\n // Untracked dep now has it's first value. So really untrack it.\n v.track = false;\n }\n },\n error: function (err) {\n if (isAsync) {\n observer.error(err);\n }\n else {\n syncError = err;\n hasSyncError = true;\n }\n },\n complete: function () {\n v.completed = true;\n // if we don't have a value — we interrupt evaluation\n // and complete output. See issue #22\n if (!v.hasValue) {\n observer.complete();\n // immediately halt the computation\n if (!isAsync) {\n hasSyncError = true;\n syncError = HALT_ERROR;\n }\n }\n if (isAsync && v.track) {\n checkCompletion();\n }\n }\n }));\n if (hasSyncError) {\n throw syncError;\n }\n isAsync = true;\n // }}} End Of Sync Section\n if (v.hasValue) {\n // Must have value because v.hasValue is true\n return v.value;\n }\n else {\n throw HALT_ERROR;\n }\n };\n }\n });\n};\n\n\n//# sourceURL=webpack://rxjs-autorun/./src/core.ts?"); /***/ }), /***/ "./src/index.ts": /*!**********************!*\ !*** ./src/index.ts ***! \**********************/ /*! exports provided: $, _, autorun, combined, computed */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"$\", function() { return $; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"_\", function() { return _; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"autorun\", function() { return autorun; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"combined\", function() { return combined; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"computed\", function() { return computed; });\n/* harmony import */ var rxjs_operators__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! rxjs/operators */ \"rxjs/operators\");\n/* harmony import */ var rxjs_operators__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(rxjs_operators__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./core */ \"./src/core.ts\");\n\n\n/**\n * Function to track Observable inside rxjs-autorun expressions\n *\n * Also provides `.weak`, `.normal` (default), and `.strong` types of tracking\n */\nvar $ = Object(_core__WEBPACK_IMPORTED_MODULE_1__[\"forwardTracker\"])('$');\n/**\n * Function to read latest Observable value (w/o tracking it) inside rxjs-autorun expressions\n *\n * Also provides `.weak`, `.normal` (default), and `.strong` types of tracking\n */\nvar _ = Object(_core__WEBPACK_IMPORTED_MODULE_1__[\"forwardTracker\"])('_');\n/**\n * Automatically run `fn` when tracked inner Observables emit\n *\n * ```js\n * autorun(() => _(a) + $(b))\n * ```\n *\n * @param fn Function that uses tracked (`$`) or untracked (`_`) Observables\n * @returns RxJS Subscription of distinct execution results\n */\nfunction autorun(fn) {\n return combined(fn).subscribe();\n}\n/**\n * Automatically run `fn` when tracked inner Observables emit\n *\n * ```js\n * combined(() => _(a) + $(b))\n * ```\n *\n * @param fn Function that uses tracked (`$`) or untracked (`_`) Observables\n * @returns Observable of execution results\n */\nfunction combined(fn) {\n return Object(_core__WEBPACK_IMPORTED_MODULE_1__[\"runner\"])(fn);\n}\n/**\n * Automatically run `fn` when tracked inner Observables emit a **distinct value**\n *\n * ```js\n * computed(() => _(a) + $(b))\n * ```\n *\n * @param fn Function that uses tracked (`$`) or untracked (`_`) Observables\n * @returns Observable of distinct execution results\n */\nfunction computed(fn) {\n return Object(_core__WEBPACK_IMPORTED_MODULE_1__[\"runner\"])(fn, true).pipe(Object(rxjs_operators__WEBPACK_IMPORTED_MODULE_0__[\"distinctUntilChanged\"])());\n}\n\n\n//# sourceURL=webpack://rxjs-autorun/./src/index.ts?"); /***/ }), /***/ "rxjs": /*!************************************************************************************!*\ !*** external {"root":["rxjs"],"commonjs":"rxjs","commonjs2":"rxjs","amd":"rxjs"} ***! \************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { eval("module.exports = __WEBPACK_EXTERNAL_MODULE_rxjs__;\n\n//# sourceURL=webpack://rxjs-autorun/external_%7B%22root%22:%5B%22rxjs%22%5D,%22commonjs%22:%22rxjs%22,%22commonjs2%22:%22rxjs%22,%22amd%22:%22rxjs%22%7D?"); /***/ }), /***/ "rxjs/operators": /*!******************************************************************************************************************************!*\ !*** external {"root":["rxjs","operators"],"commonjs":"rxjs/operators","commonjs2":"rxjs/operators","amd":"rxjs/operators"} ***! \******************************************************************************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { eval("module.exports = __WEBPACK_EXTERNAL_MODULE_rxjs_operators__;\n\n//# sourceURL=webpack://rxjs-autorun/external_%7B%22root%22:%5B%22rxjs%22,%22operators%22%5D,%22commonjs%22:%22rxjs/operators%22,%22commonjs2%22:%22rxjs/operators%22,%22amd%22:%22rxjs/operators%22%7D?"); /***/ }) /******/ }); });