urx.esm.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984
  1. var PUBLISH = 0;
  2. var SUBSCRIBE = 1;
  3. var RESET = 2;
  4. var VALUE = 4;
  5. /**
  6. * Utils includes
  7. * - a handful of functional utilities inspired by or taken from the [Ramda library](https://ramdajs.com/);
  8. * - TypeScript crutches - the [[tup]] function.
  9. *
  10. * Use these for your convenience - they are here so that urx is zero-dependency package.
  11. *
  12. * @packageDocumentation
  13. */
  14. /**
  15. * Performs left to right composition of two functions.
  16. */
  17. function compose(a, b) {
  18. return function (arg) {
  19. return a(b(arg));
  20. };
  21. }
  22. /**
  23. * Takes a value and applies a function to it.
  24. */
  25. function thrush(arg, proc) {
  26. return proc(arg);
  27. }
  28. /**
  29. * Takes a 2 argument function and partially applies the first argument.
  30. */
  31. function curry2to1(proc, arg1) {
  32. return function (arg2) {
  33. return proc(arg1, arg2);
  34. };
  35. }
  36. /**
  37. * Takes a 1 argument function and returns a function which when called, executes it with the provided argument.
  38. */
  39. function curry1to0(proc, arg) {
  40. return function () {
  41. return proc(arg);
  42. };
  43. }
  44. /**
  45. * Returns a function which extracts the property from from the passed object.
  46. */
  47. function prop(property) {
  48. return function (object) {
  49. return object[property];
  50. };
  51. }
  52. /**
  53. * Calls callback with the first argument, and returns it.
  54. */
  55. function tap(arg, proc) {
  56. proc(arg);
  57. return arg;
  58. }
  59. /**
  60. * Utility function to help typescript figure out that what we pass is a tuple and not a generic array.
  61. * Taken from (this StackOverflow tread)[https://stackoverflow.com/questions/49729550/implicitly-create-a-tuple-in-typescript/52445008#52445008]
  62. */
  63. function tup() {
  64. for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
  65. args[_key] = arguments[_key];
  66. }
  67. return args;
  68. }
  69. /**
  70. * Calls the passed function.
  71. */
  72. function call(proc) {
  73. proc();
  74. }
  75. /**
  76. * returns a function which when called always returns the passed value
  77. */
  78. function always(value) {
  79. return function () {
  80. return value;
  81. };
  82. }
  83. /**
  84. * returns a function which calls all passed functions in the passed order.
  85. * joinProc does not pass arguments or collect return values.
  86. */
  87. function joinProc() {
  88. for (var _len2 = arguments.length, procs = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
  89. procs[_key2] = arguments[_key2];
  90. }
  91. return function () {
  92. procs.map(call);
  93. };
  94. }
  95. function noop() {}
  96. /**
  97. * urx Actions operate on streams - `publish` publishes data in a stream, and `subscribe` attaches a subscription to a stream.
  98. * @packageDocumentation
  99. */
  100. /**
  101. * Subscribes the specified [[Subscription]] to the updates from the Emitter.
  102. * The emitter calls the subscription with the new data each time new data is published into it.
  103. *
  104. * ```ts
  105. * const foo = stream<number>();
  106. * subscribe(foo, (value) => console.log(value));
  107. * ```
  108. *
  109. * @returns an [[Unsubscribe]] handle - calling it will unbind the subscription from the emitter.
  110. *```ts
  111. * const foo = stream<number>();
  112. * const unsub = subscribe(foo, (value) => console.log(value));
  113. * unsub();
  114. *```
  115. */
  116. function subscribe(emitter, subscription) {
  117. return emitter(SUBSCRIBE, subscription);
  118. }
  119. /**
  120. * Publishes the value into the passed [[Publisher]].
  121. *
  122. * ```ts
  123. * const foo = stream<number>();
  124. * publish(foo, 42);
  125. * ```
  126. */
  127. function publish(publisher, value) {
  128. publisher(PUBLISH, value);
  129. }
  130. /**
  131. * Clears all subscriptions from the [[Emitter]].
  132. * ```ts
  133. * const foo = stream<number>();
  134. * subscribe(foo, (value) => console.log(value));
  135. * reset(foo);
  136. * publish(foo, 42);
  137. * ```
  138. */
  139. function reset(emitter) {
  140. emitter(RESET);
  141. }
  142. /**
  143. * Extracts the current value from a stateful stream. Use it only as an escape hatch, as it violates the concept of reactive programming.
  144. * ```ts
  145. * const foo = statefulStream(42);
  146. * console.log(getValue(foo));
  147. * ```
  148. */
  149. function getValue(depot) {
  150. return depot(VALUE);
  151. }
  152. /**
  153. * Connects two streams - any value emitted from the emitter will be published in the publisher.
  154. * ```ts
  155. * const foo = stream<number>();
  156. * const bar = stream<number>();
  157. * subscribe(bar, (value) => console.log(`Bar emitted ${value}`));
  158. *
  159. * connect(foo, bar);
  160. * publish(foo);
  161. * ```
  162. * @returns an [[Unsubscribe]] handle which will disconnect the two streams.
  163. */
  164. function connect(emitter, publisher) {
  165. return subscribe(emitter, curry2to1(publisher, PUBLISH));
  166. }
  167. /**
  168. * Executes the passed subscription at most once, for the next emit from the emitter.
  169. * ```ts
  170. * const foo = stream<number>()
  171. * handleNext(foo, value => console.log(value)) // called once, with 42
  172. * publish(foo, 42)
  173. * publish(foo, 43)
  174. * ```
  175. * @returns an [[Unsubscribe]] handle to unbind the subscription if necessary.
  176. */
  177. function handleNext(emitter, subscription) {
  178. var unsub = emitter(SUBSCRIBE, function (value) {
  179. unsub();
  180. subscription(value);
  181. });
  182. return unsub;
  183. }
  184. /**
  185. * Streams are the basic building blocks of a reactive system. Think of them as the system permanent "data tubes".
  186. *
  187. * A stream acts as both an [[Emitter]] and [[Publisher]]. Each stream can have multiple {@link Subscription | Subscriptions}.
  188. *
  189. * urx streams are either **stateless** or **stateful**.
  190. * Stateless streams emit data to existing subscriptions when published, without keeping track of it.
  191. * Stateful streams remember the last published value and immediately publish it to new subscriptions.
  192. *
  193. * ```ts
  194. * import { stream, statefulStream, publish, subscribe } from "@virtuoso.dev/urx";
  195. *
  196. * // foo is a stateless stream
  197. * const foo = stream<number>();
  198. *
  199. * publish(foo, 42);
  200. * // this subsription will not be called...
  201. * subscribe(foo, (value) => console.log(value));
  202. * // it will only catch published values after it
  203. * publish(foo, 43);
  204. *
  205. * // stateful streams always start with an initial value
  206. * const bar = statefulStream(42);
  207. *
  208. * // subscribing to a stateful stream
  209. * // immediately calls the subscription with the current value
  210. * subscribe(bar, (value) => console.log(value));
  211. *
  212. * // subsequent publishing works just like stateless streams
  213. * publish(bar, 43);
  214. * ```
  215. * @packageDocumentation
  216. */
  217. /**
  218. * Constructs a new stateless stream.
  219. * ```ts
  220. * const foo = stream<number>();
  221. * ```
  222. * @typeParam T the type of values to publish in the stream.
  223. * @returns a [[Stream]]
  224. */
  225. function stream() {
  226. var subscriptions = [];
  227. return function (action, arg) {
  228. switch (action) {
  229. case RESET:
  230. subscriptions.splice(0, subscriptions.length);
  231. return;
  232. case SUBSCRIBE:
  233. subscriptions.push(arg);
  234. return function () {
  235. var indexOf = subscriptions.indexOf(arg);
  236. if (indexOf > -1) {
  237. subscriptions.splice(indexOf, 1);
  238. }
  239. };
  240. case PUBLISH:
  241. subscriptions.slice().forEach(function (subscription) {
  242. subscription(arg);
  243. });
  244. return;
  245. default:
  246. throw new Error("unrecognized action " + action);
  247. }
  248. };
  249. }
  250. /**
  251. * Constructs a new stateful stream.
  252. * ```ts
  253. * const foo = statefulStream(42);
  254. * ```
  255. * @param initial the initial value in the stream.
  256. * @typeParam T the type of values to publish in the stream. If omitted, the function infers it from the initial value.
  257. * @returns a [[StatefulStream]]
  258. */
  259. function statefulStream(initial) {
  260. var value = initial;
  261. var innerSubject = stream();
  262. return function (action, arg) {
  263. switch (action) {
  264. case SUBSCRIBE:
  265. var subscription = arg;
  266. subscription(value);
  267. break;
  268. case PUBLISH:
  269. value = arg;
  270. break;
  271. case VALUE:
  272. return value;
  273. }
  274. return innerSubject(action, arg);
  275. };
  276. }
  277. /**
  278. * Event handlers are special emitters which can have **at most one active subscription**.
  279. * Subscribing to an event handler unsubscribes the previous subscription, if present.
  280. * ```ts
  281. * const foo = stream<number>();
  282. * const fooEvent = eventHandler(foo);
  283. *
  284. * // will be called once with 42
  285. * subscribe(fooEvent, (value) => console.log(`Sub 1 ${value}`));
  286. * publish(foo, 42);
  287. *
  288. * // unsubscribes sub 1
  289. * subscribe(fooEvent, (value) => console.log(`Sub 2 ${value}`));
  290. * publish(foo, 43);
  291. * ```
  292. * @param emitter the source emitter.
  293. * @returns the single-subscription emitter.
  294. */
  295. function eventHandler(emitter) {
  296. var unsub;
  297. var currentSubscription;
  298. var cleanup = function cleanup() {
  299. return unsub && unsub();
  300. };
  301. return function (action, subscription) {
  302. switch (action) {
  303. case SUBSCRIBE:
  304. if (subscription) {
  305. if (currentSubscription === subscription) {
  306. return;
  307. }
  308. cleanup();
  309. currentSubscription = subscription;
  310. unsub = subscribe(emitter, subscription);
  311. return unsub;
  312. } else {
  313. cleanup();
  314. return noop;
  315. }
  316. case RESET:
  317. cleanup();
  318. currentSubscription = null;
  319. return;
  320. default:
  321. throw new Error("unrecognized action " + action);
  322. }
  323. };
  324. }
  325. /**
  326. * Creates and connects a "junction" stream to the specified emitter. Often used with [[pipe]], to avoid the multiple evaluation of operator sets.
  327. *
  328. * ```ts
  329. * const foo = stream<number>();
  330. *
  331. * const fooX2 = pipe(
  332. * foo,
  333. * map((value) => {
  334. * console.log(`multiplying ${value}`);
  335. * return value * 2;
  336. * })
  337. * );
  338. *
  339. * subscribe(fooX2, (value) => console.log(value));
  340. * subscribe(fooX2, (value) => console.log(value));
  341. *
  342. * publish(foo, 42); // executes the map operator twice for each subscription.
  343. *
  344. * const sharedFooX2 = streamFromEmitter(pipe(
  345. * foo,
  346. * map((value) => {
  347. * console.log(`shared multiplying ${value}`);
  348. * return value * 2;
  349. * })
  350. * ));
  351. *
  352. * subscribe(sharedFooX2, (value) => console.log(value));
  353. * subscribe(sharedFooX2, (value) => console.log(value));
  354. *
  355. * publish(foo, 42);
  356. *```
  357. * @returns the resulting stream.
  358. */
  359. function streamFromEmitter(emitter) {
  360. return tap(stream(), function (stream) {
  361. return connect(emitter, stream);
  362. });
  363. }
  364. /**
  365. * Creates and connects a "junction" stateful stream to the specified emitter. Often used with [[pipe]], to avoid the multiple evaluation of operator sets.
  366. *
  367. * ```ts
  368. * const foo = stream<number>();
  369. *
  370. * const fooX2 = pipe(
  371. * foo,
  372. * map((value) => {
  373. * console.log(`multiplying ${value}`);
  374. * return value * 2;
  375. * })
  376. * );
  377. *
  378. * subscribe(fooX2, (value) => console.log(value));
  379. * subscribe(fooX2, (value) => console.log(value));
  380. *
  381. * publish(foo, 42); // executes the map operator twice for each subscription.
  382. *
  383. * const sharedFooX2 = statefulStreamFromEmitter(pipe(
  384. * foo,
  385. * map((value) => {
  386. * console.log(`shared multiplying ${value}`);
  387. * return value * 2;
  388. * })
  389. * ), 42);
  390. *
  391. * subscribe(sharedFooX2, (value) => console.log(value));
  392. * subscribe(sharedFooX2, (value) => console.log(value));
  393. *
  394. * publish(foo, 42);
  395. *```
  396. * @param initial the initial value in the stream.
  397. * @returns the resulting stateful stream.
  398. */
  399. function statefulStreamFromEmitter(emitter, initial) {
  400. return tap(statefulStream(initial), function (stream) {
  401. return connect(emitter, stream);
  402. });
  403. }
  404. /**
  405. *
  406. * Stream values can be transformed and controlled by {@link pipe | **piping**} through **operators**.
  407. * urx includes several operators like [[map]], [[filter]], [[scan]], and [[throttleTime]].
  408. * The [[withLatestFrom]] operator allows the combination of values from other streams.
  409. *
  410. * ```ts
  411. * const foo = stream<number>()
  412. *
  413. * // create an emitter that first adds 2 to the passed value, then multiplies it by * 2
  414. * const bar = pipe(foo, map(value => value + 2), map(value => value * 2))
  415. * subscribe(bar, value => console.log(value))
  416. * publish(foo, 2) // outputs 8
  417. * ```
  418. *
  419. * ### Implementing Custom Operators
  420. * To implement your own operators, implement the [[Operator]] interface.
  421. * @packageDocumentation
  422. */
  423. /** @internal */
  424. function combineOperators() {
  425. for (var _len = arguments.length, operators = new Array(_len), _key = 0; _key < _len; _key++) {
  426. operators[_key] = arguments[_key];
  427. }
  428. return function (subscriber) {
  429. return operators.reduceRight(thrush, subscriber);
  430. };
  431. }
  432. function pipe(source) {
  433. for (var _len2 = arguments.length, operators = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
  434. operators[_key2 - 1] = arguments[_key2];
  435. }
  436. // prettier-ignore
  437. var project = combineOperators.apply(void 0, operators);
  438. return function (action, subscription) {
  439. switch (action) {
  440. case SUBSCRIBE:
  441. return subscribe(source, project(subscription));
  442. case RESET:
  443. reset(source);
  444. return;
  445. default:
  446. throw new Error("unrecognized action " + action);
  447. }
  448. };
  449. }
  450. /**
  451. * The default [[Comparator]] for [[distinctUntilChanged]] and [[duc]].
  452. */
  453. function defaultComparator(previous, next) {
  454. return previous === next;
  455. }
  456. /**
  457. * Filters out identical values. Pass an optional [[Comparator]] if you need to filter non-primitive values.
  458. * ```ts
  459. * const foo = stream<number>()
  460. *
  461. * subscribe(
  462. * pipe(foo, distinctUntilChanged()),
  463. * console.log
  464. * ) // will be called only once
  465. *
  466. * publish(foo, 42)
  467. * publish(foo, 42)
  468. * ```
  469. */
  470. function distinctUntilChanged(comparator) {
  471. if (comparator === void 0) {
  472. comparator = defaultComparator;
  473. }
  474. var current;
  475. return function (done) {
  476. return function (next) {
  477. if (!comparator(current, next)) {
  478. current = next;
  479. done(next);
  480. }
  481. };
  482. };
  483. }
  484. /**
  485. * Filters out values for which the predicator does not return `true`-ish.
  486. * ```ts
  487. * const foo = stream<number>()
  488. *
  489. * subscribe(
  490. * pipe(foo, filter(value => value % 2 === 0)),
  491. * console.log
  492. * ) // will be called only with even values
  493. *
  494. * publish(foo, 2)
  495. * publish(foo, 3)
  496. * publish(foo, 4)
  497. * publish(foo, 5)
  498. * ```
  499. */
  500. function filter(predicate) {
  501. return function (done) {
  502. return function (value) {
  503. predicate(value) && done(value);
  504. };
  505. };
  506. }
  507. /**
  508. * Maps values using the provided project function.
  509. * ```ts
  510. * const foo = stream<number>()
  511. *
  512. * subscribe(
  513. * pipe(foo, map(value => value * 2)),
  514. * console.log
  515. * ) // 4, 6
  516. *
  517. * publish(foo, 2)
  518. * publish(foo, 3)
  519. * ```
  520. */
  521. function map(project) {
  522. return function (done) {
  523. return compose(done, project);
  524. };
  525. }
  526. /**
  527. * Maps values to the hard-coded value.
  528. * ```ts
  529. * const foo = stream<number>()
  530. *
  531. * subscribe(
  532. * pipe(foo, mapTo(3)),
  533. * console.log
  534. * ) // 3, 3
  535. *
  536. * publish(foo, 1)
  537. * publish(foo, 2)
  538. * ```
  539. */
  540. function mapTo(value) {
  541. return function (done) {
  542. return function () {
  543. return done(value);
  544. };
  545. };
  546. }
  547. /**
  548. * Works like Array#reduce.
  549. * Applies an accumulator function on the emitter, and outputs intermediate result. Starts with the initial value.
  550. * ```ts
  551. * const foo = stream<number>()
  552. *
  553. * subscribe(
  554. * pipe(foo, scan((acc, value) => acc + value, 2),
  555. * console.log
  556. * ) // 3, 5
  557. *
  558. * publish(foo, 1)
  559. * publish(foo, 2)
  560. * ```
  561. */
  562. function scan(scanner, initial) {
  563. return function (done) {
  564. return function (value) {
  565. return done(initial = scanner(initial, value));
  566. };
  567. };
  568. }
  569. /**
  570. * Skips the specified amount of values from the emitter.
  571. * ```ts
  572. * const foo = stream<number>()
  573. *
  574. * subscribe(
  575. * pipe(foo, skip(2)),
  576. * console.log
  577. * ) // 3, 4
  578. *
  579. * publish(foo, 1) // skipped
  580. * publish(foo, 2) // skipped
  581. * publish(foo, 3)
  582. * publish(foo, 4)
  583. * ```
  584. */
  585. function skip(times) {
  586. return function (done) {
  587. return function (value) {
  588. times > 0 ? times-- : done(value);
  589. };
  590. };
  591. }
  592. /**
  593. * Throttles flowing values at the provided interval in milliseconds.
  594. * [Throttle VS Debounce in SO](https://stackoverflow.com/questions/25991367/difference-between-throttling-and-debouncing-a-function).
  595. *
  596. * ```ts
  597. * const foo = stream<number>()
  598. * publish(foo, 1)
  599. *
  600. * setTimeout(() => publish(foo, 2), 20)
  601. * setTimeout(() => publish(foo, 3), 20)
  602. *
  603. * subscribe(pipe(foo, throttleTime(50)), val => {
  604. * console.log(value); // 3
  605. * })
  606. * ```
  607. */
  608. function throttleTime(interval) {
  609. var currentValue;
  610. var timeout;
  611. return function (done) {
  612. return function (value) {
  613. currentValue = value;
  614. if (timeout) {
  615. return;
  616. }
  617. timeout = setTimeout(function () {
  618. timeout = undefined;
  619. done(currentValue);
  620. }, interval);
  621. };
  622. };
  623. }
  624. /**
  625. * Debounces flowing values at the provided interval in milliseconds.
  626. * [Throttle VS Debounce in SO](https://stackoverflow.com/questions/25991367/difference-between-throttling-and-debouncing-a-function).
  627. *
  628. * ```ts
  629. * const foo = stream<number>()
  630. * publish(foo, 1)
  631. *
  632. * setTimeout(() => publish(foo, 2), 20)
  633. * setTimeout(() => publish(foo, 3), 20)
  634. *
  635. * subscribe(pipe(foo, debounceTime(50)), val => {
  636. * console.log(value); // 3
  637. * })
  638. * ```
  639. */
  640. function debounceTime(interval) {
  641. var currentValue;
  642. var timeout;
  643. return function (done) {
  644. return function (value) {
  645. currentValue = value;
  646. if (timeout) {
  647. clearTimeout(timeout);
  648. }
  649. timeout = setTimeout(function () {
  650. done(currentValue);
  651. }, interval);
  652. };
  653. };
  654. }
  655. function withLatestFrom() {
  656. for (var _len3 = arguments.length, sources = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
  657. sources[_key3] = arguments[_key3];
  658. }
  659. var values = new Array(sources.length);
  660. var called = 0;
  661. var pendingCall = null;
  662. var allCalled = Math.pow(2, sources.length) - 1;
  663. sources.forEach(function (source, index) {
  664. var bit = Math.pow(2, index);
  665. subscribe(source, function (value) {
  666. var prevCalled = called;
  667. called = called | bit;
  668. values[index] = value;
  669. if (prevCalled !== allCalled && called === allCalled && pendingCall) {
  670. pendingCall();
  671. pendingCall = null;
  672. }
  673. });
  674. });
  675. return function (done) {
  676. return function (value) {
  677. var call = function call() {
  678. return done([value].concat(values));
  679. };
  680. if (called === allCalled) {
  681. call();
  682. } else {
  683. pendingCall = call;
  684. }
  685. };
  686. };
  687. }
  688. /**
  689. * Transformers change and combine streams, similar to operators.
  690. * urx comes with two combinators - [[combineLatest]] and [[merge]], and one convenience filter - [[duc]].
  691. *
  692. * @packageDocumentation
  693. */
  694. /**
  695. * Merges one or more emitters from the same type into a new Emitter which emits values from any of the source emitters.
  696. * ```ts
  697. * const foo = stream<number>()
  698. * const bar = stream<number>()
  699. *
  700. * subscribe(merge(foo, bar), (value) => console.log(value)) // 42, 43
  701. *
  702. * publish(foo, 42)
  703. * publish(bar, 43)
  704. * ```
  705. */
  706. function merge() {
  707. for (var _len = arguments.length, sources = new Array(_len), _key = 0; _key < _len; _key++) {
  708. sources[_key] = arguments[_key];
  709. }
  710. return function (action, subscription) {
  711. switch (action) {
  712. case SUBSCRIBE:
  713. return joinProc.apply(void 0, sources.map(function (source) {
  714. return subscribe(source, subscription);
  715. }));
  716. case RESET:
  717. // do nothing, we are stateless
  718. return;
  719. default:
  720. throw new Error("unrecognized action " + action);
  721. }
  722. };
  723. }
  724. /**
  725. * A convenience wrapper that emits only the distinct values from the passed Emitter. Wraps [[pipe]] and [[distinctUntilChanged]].
  726. *
  727. * ```ts
  728. * const foo = stream<number>()
  729. *
  730. * // this line...
  731. * const a = duc(foo)
  732. *
  733. * // is equivalent to this
  734. * const b = pipe(distinctUntilChanged(foo))
  735. * ```
  736. *
  737. * @param source The source emitter.
  738. * @param comparator optional custom comparison function for the two values.
  739. *
  740. * @typeParam T the type of the value emitted by the source.
  741. *
  742. * @returns the resulting emitter.
  743. */
  744. function duc(source, comparator) {
  745. if (comparator === void 0) {
  746. comparator = defaultComparator;
  747. }
  748. return pipe(source, distinctUntilChanged(comparator));
  749. }
  750. function combineLatest() {
  751. var innerSubject = stream();
  752. for (var _len2 = arguments.length, emitters = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
  753. emitters[_key2] = arguments[_key2];
  754. }
  755. var values = new Array(emitters.length);
  756. var called = 0;
  757. var allCalled = Math.pow(2, emitters.length) - 1;
  758. emitters.forEach(function (source, index) {
  759. var bit = Math.pow(2, index);
  760. subscribe(source, function (value) {
  761. values[index] = value;
  762. called = called | bit;
  763. if (called === allCalled) {
  764. publish(innerSubject, values);
  765. }
  766. });
  767. });
  768. return function (action, subscription) {
  769. switch (action) {
  770. case SUBSCRIBE:
  771. if (called === allCalled) {
  772. subscription(values);
  773. }
  774. return subscribe(innerSubject, subscription);
  775. case RESET:
  776. return reset(innerSubject);
  777. default:
  778. throw new Error("unrecognized action " + action);
  779. }
  780. };
  781. }
  782. /**
  783. * `system` defines a specification of a system - its constructor, dependencies and if it should act as a singleton in a system dependency tree.
  784. * When called, system returns a [[SystemSpec]], which is then initialized along with its dependencies by passing it to [[init]].
  785. *
  786. * ```ts
  787. * @import { subscribe, publish, system, init, tup, connect, map, pipe } from 'urx'
  788. *
  789. * // a simple system with two streams
  790. * const sys1 = system(() => {
  791. * const a = stream<number>()
  792. * const b = stream<number>()
  793. *
  794. * connect(pipe(a, map(value => value * 2)), b)
  795. * return { a, b }
  796. * })
  797. *
  798. * // a second system which depends on the streams from the first one
  799. * const sys2 = system(([ {a, b} ]) => {
  800. * const c = stream<number>()
  801. * connect(pipe(b, map(value => value * 2)), c)
  802. * // re-export the `a` stream, keep `b` internal
  803. * return { a, c }
  804. * }, tup(sys1))
  805. *
  806. * // init will recursively initialize sys2 dependencies, in this case sys1
  807. * const { a, c } = init(sys2)
  808. * subscribe(c, c => console.log(`Value multiplied by 4`, c))
  809. * publish(a, 2)
  810. * ```
  811. *
  812. * #### Singletons in Dependency Tree
  813. *
  814. * By default, systems will be initialized only once if encountered multiple times in the dependency tree.
  815. * In the below dependency system tree, systems `b` and `c` will receive the same stream instances from system `a` when system `d` is initialized.
  816. * ```txt
  817. * a
  818. * / \
  819. * b c
  820. * \ /
  821. * d
  822. * ```
  823. * If `a` gets `{singleton: false}` as a last argument, `init` creates two separate instances - one for `b` and one for `c`.
  824. *
  825. * @param constructor the system constructor function. Initialize and connect the streams in its body.
  826. *
  827. * @param dependencies the system dependencies, which the constructor will receive as arguments.
  828. * Use the [[tup]] utility **For TypeScript type inference to work correctly**.
  829. * ```ts
  830. * const sys3 = system(() => { ... }, tup(sys2, sys1))
  831. * ```
  832. * @param __namedParameters Options
  833. * @param singleton determines if the system will act as a singleton in a system dependency tree. `true` by default.
  834. */
  835. function system(constructor, dependencies, _temp) {
  836. if (dependencies === void 0) {
  837. dependencies = [];
  838. }
  839. var _ref = _temp === void 0 ? {
  840. singleton: true
  841. } : _temp,
  842. singleton = _ref.singleton;
  843. return {
  844. id: id(),
  845. constructor: constructor,
  846. dependencies: dependencies,
  847. singleton: singleton
  848. };
  849. }
  850. /** @internal */
  851. var id = function id() {
  852. return Symbol();
  853. };
  854. /**
  855. * Initializes a [[SystemSpec]] by recursively initializing its dependencies.
  856. *
  857. * ```ts
  858. * // a simple system with two streams
  859. * const sys1 = system(() => {
  860. * const a = stream<number>()
  861. * const b = stream<number>()
  862. *
  863. * connect(pipe(a, map(value => value * 2)), b)
  864. * return { a, b }
  865. * })
  866. *
  867. * const { a, b } = init(sys1)
  868. * subscribe(b, b => console.log(b))
  869. * publish(a, 2)
  870. * ```
  871. *
  872. * @returns the [[System]] constructed by the spec constructor.
  873. * @param systemSpec the system spec to initialize.
  874. */
  875. function init(systemSpec) {
  876. var singletons = new Map();
  877. var _init = function _init(_ref2) {
  878. var id = _ref2.id,
  879. constructor = _ref2.constructor,
  880. dependencies = _ref2.dependencies,
  881. singleton = _ref2.singleton;
  882. if (singleton && singletons.has(id)) {
  883. return singletons.get(id);
  884. }
  885. var system = constructor(dependencies.map(function (e) {
  886. return _init(e);
  887. }));
  888. if (singleton) {
  889. singletons.set(id, system);
  890. }
  891. return system;
  892. };
  893. return _init(systemSpec);
  894. }
  895. export { always, call, combineLatest, compose, connect, curry1to0, curry2to1, debounceTime, defaultComparator, distinctUntilChanged, duc, eventHandler, filter, getValue, handleNext, init, joinProc, map, mapTo, merge, noop, pipe, prop, publish, reset, scan, skip, statefulStream, statefulStreamFromEmitter, stream, streamFromEmitter, subscribe, system, tap, throttleTime, thrush, tup, withLatestFrom };
  896. //# sourceMappingURL=urx.esm.js.map