utils.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. import { __values, __spreadArray, __read, __assign } from './_virtual/_tslib.js';
  2. import { SpecialTargets } from './types.js';
  3. import { raise, send } from './actionTypes.js';
  4. import { DEFAULT_GUARD_TYPE, TARGETLESS_KEY, STATE_DELIMITER } from './constants.js';
  5. import { IS_PRODUCTION } from './environment.js';
  6. var _a;
  7. function keys(value) {
  8. return Object.keys(value);
  9. }
  10. function matchesState(parentStateId, childStateId, delimiter) {
  11. if (delimiter === void 0) {
  12. delimiter = STATE_DELIMITER;
  13. }
  14. var parentStateValue = toStateValue(parentStateId, delimiter);
  15. var childStateValue = toStateValue(childStateId, delimiter);
  16. if (isString(childStateValue)) {
  17. if (isString(parentStateValue)) {
  18. return childStateValue === parentStateValue;
  19. } // Parent more specific than child
  20. return false;
  21. }
  22. if (isString(parentStateValue)) {
  23. return parentStateValue in childStateValue;
  24. }
  25. return Object.keys(parentStateValue).every(function (key) {
  26. if (!(key in childStateValue)) {
  27. return false;
  28. }
  29. return matchesState(parentStateValue[key], childStateValue[key]);
  30. });
  31. }
  32. function getEventType(event) {
  33. try {
  34. return isString(event) || typeof event === 'number' ? "".concat(event) : event.type;
  35. } catch (e) {
  36. throw new Error('Events must be strings or objects with a string event.type property.');
  37. }
  38. }
  39. function getActionType(action) {
  40. try {
  41. return isString(action) || typeof action === 'number' ? "".concat(action) : isFunction(action) ? action.name : action.type;
  42. } catch (e) {
  43. throw new Error('Actions must be strings or objects with a string action.type property.');
  44. }
  45. }
  46. function toStatePath(stateId, delimiter) {
  47. try {
  48. if (isArray(stateId)) {
  49. return stateId;
  50. }
  51. return stateId.toString().split(delimiter);
  52. } catch (e) {
  53. throw new Error("'".concat(stateId, "' is not a valid state path."));
  54. }
  55. }
  56. function isStateLike(state) {
  57. return typeof state === 'object' && 'value' in state && 'context' in state && 'event' in state && '_event' in state;
  58. }
  59. function toStateValue(stateValue, delimiter) {
  60. if (isStateLike(stateValue)) {
  61. return stateValue.value;
  62. }
  63. if (isArray(stateValue)) {
  64. return pathToStateValue(stateValue);
  65. }
  66. if (typeof stateValue !== 'string') {
  67. return stateValue;
  68. }
  69. var statePath = toStatePath(stateValue, delimiter);
  70. return pathToStateValue(statePath);
  71. }
  72. function pathToStateValue(statePath) {
  73. if (statePath.length === 1) {
  74. return statePath[0];
  75. }
  76. var value = {};
  77. var marker = value;
  78. for (var i = 0; i < statePath.length - 1; i++) {
  79. if (i === statePath.length - 2) {
  80. marker[statePath[i]] = statePath[i + 1];
  81. } else {
  82. marker[statePath[i]] = {};
  83. marker = marker[statePath[i]];
  84. }
  85. }
  86. return value;
  87. }
  88. function mapValues(collection, iteratee) {
  89. var result = {};
  90. var collectionKeys = Object.keys(collection);
  91. for (var i = 0; i < collectionKeys.length; i++) {
  92. var key = collectionKeys[i];
  93. result[key] = iteratee(collection[key], key, collection, i);
  94. }
  95. return result;
  96. }
  97. function mapFilterValues(collection, iteratee, predicate) {
  98. var e_1, _a;
  99. var result = {};
  100. try {
  101. for (var _b = __values(Object.keys(collection)), _c = _b.next(); !_c.done; _c = _b.next()) {
  102. var key = _c.value;
  103. var item = collection[key];
  104. if (!predicate(item)) {
  105. continue;
  106. }
  107. result[key] = iteratee(item, key, collection);
  108. }
  109. } catch (e_1_1) {
  110. e_1 = {
  111. error: e_1_1
  112. };
  113. } finally {
  114. try {
  115. if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
  116. } finally {
  117. if (e_1) throw e_1.error;
  118. }
  119. }
  120. return result;
  121. }
  122. /**
  123. * Retrieves a value at the given path.
  124. * @param props The deep path to the prop of the desired value
  125. */
  126. var path = function (props) {
  127. return function (object) {
  128. var e_2, _a;
  129. var result = object;
  130. try {
  131. for (var props_1 = __values(props), props_1_1 = props_1.next(); !props_1_1.done; props_1_1 = props_1.next()) {
  132. var prop = props_1_1.value;
  133. result = result[prop];
  134. }
  135. } catch (e_2_1) {
  136. e_2 = {
  137. error: e_2_1
  138. };
  139. } finally {
  140. try {
  141. if (props_1_1 && !props_1_1.done && (_a = props_1.return)) _a.call(props_1);
  142. } finally {
  143. if (e_2) throw e_2.error;
  144. }
  145. }
  146. return result;
  147. };
  148. };
  149. /**
  150. * Retrieves a value at the given path via the nested accessor prop.
  151. * @param props The deep path to the prop of the desired value
  152. */
  153. function nestedPath(props, accessorProp) {
  154. return function (object) {
  155. var e_3, _a;
  156. var result = object;
  157. try {
  158. for (var props_2 = __values(props), props_2_1 = props_2.next(); !props_2_1.done; props_2_1 = props_2.next()) {
  159. var prop = props_2_1.value;
  160. result = result[accessorProp][prop];
  161. }
  162. } catch (e_3_1) {
  163. e_3 = {
  164. error: e_3_1
  165. };
  166. } finally {
  167. try {
  168. if (props_2_1 && !props_2_1.done && (_a = props_2.return)) _a.call(props_2);
  169. } finally {
  170. if (e_3) throw e_3.error;
  171. }
  172. }
  173. return result;
  174. };
  175. }
  176. function toStatePaths(stateValue) {
  177. if (!stateValue) {
  178. return [[]];
  179. }
  180. if (isString(stateValue)) {
  181. return [[stateValue]];
  182. }
  183. var result = flatten(Object.keys(stateValue).map(function (key) {
  184. var subStateValue = stateValue[key];
  185. if (typeof subStateValue !== 'string' && (!subStateValue || !Object.keys(subStateValue).length)) {
  186. return [[key]];
  187. }
  188. return toStatePaths(stateValue[key]).map(function (subPath) {
  189. return [key].concat(subPath);
  190. });
  191. }));
  192. return result;
  193. }
  194. function pathsToStateValue(paths) {
  195. var e_4, _a;
  196. var result = {};
  197. if (paths && paths.length === 1 && paths[0].length === 1) {
  198. return paths[0][0];
  199. }
  200. try {
  201. for (var paths_1 = __values(paths), paths_1_1 = paths_1.next(); !paths_1_1.done; paths_1_1 = paths_1.next()) {
  202. var currentPath = paths_1_1.value;
  203. var marker = result; // tslint:disable-next-line:prefer-for-of
  204. for (var i = 0; i < currentPath.length; i++) {
  205. var subPath = currentPath[i];
  206. if (i === currentPath.length - 2) {
  207. marker[subPath] = currentPath[i + 1];
  208. break;
  209. }
  210. marker[subPath] = marker[subPath] || {};
  211. marker = marker[subPath];
  212. }
  213. }
  214. } catch (e_4_1) {
  215. e_4 = {
  216. error: e_4_1
  217. };
  218. } finally {
  219. try {
  220. if (paths_1_1 && !paths_1_1.done && (_a = paths_1.return)) _a.call(paths_1);
  221. } finally {
  222. if (e_4) throw e_4.error;
  223. }
  224. }
  225. return result;
  226. }
  227. function flatten(array) {
  228. var _a;
  229. return (_a = []).concat.apply(_a, __spreadArray([], __read(array), false));
  230. }
  231. function toArrayStrict(value) {
  232. if (isArray(value)) {
  233. return value;
  234. }
  235. return [value];
  236. }
  237. function toArray(value) {
  238. if (value === undefined) {
  239. return [];
  240. }
  241. return toArrayStrict(value);
  242. }
  243. function mapContext(mapper, context, _event) {
  244. var e_5, _a;
  245. if (isFunction(mapper)) {
  246. return mapper(context, _event.data);
  247. }
  248. var result = {};
  249. try {
  250. for (var _b = __values(Object.keys(mapper)), _c = _b.next(); !_c.done; _c = _b.next()) {
  251. var key = _c.value;
  252. var subMapper = mapper[key];
  253. if (isFunction(subMapper)) {
  254. result[key] = subMapper(context, _event.data);
  255. } else {
  256. result[key] = subMapper;
  257. }
  258. }
  259. } catch (e_5_1) {
  260. e_5 = {
  261. error: e_5_1
  262. };
  263. } finally {
  264. try {
  265. if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
  266. } finally {
  267. if (e_5) throw e_5.error;
  268. }
  269. }
  270. return result;
  271. }
  272. function isBuiltInEvent(eventType) {
  273. return /^(done|error)\./.test(eventType);
  274. }
  275. function isPromiseLike(value) {
  276. if (value instanceof Promise) {
  277. return true;
  278. } // Check if shape matches the Promise/A+ specification for a "thenable".
  279. if (value !== null && (isFunction(value) || typeof value === 'object') && isFunction(value.then)) {
  280. return true;
  281. }
  282. return false;
  283. }
  284. function isBehavior(value) {
  285. return value !== null && typeof value === 'object' && 'transition' in value && typeof value.transition === 'function';
  286. }
  287. function partition(items, predicate) {
  288. var e_6, _a;
  289. var _b = __read([[], []], 2),
  290. truthy = _b[0],
  291. falsy = _b[1];
  292. try {
  293. for (var items_1 = __values(items), items_1_1 = items_1.next(); !items_1_1.done; items_1_1 = items_1.next()) {
  294. var item = items_1_1.value;
  295. if (predicate(item)) {
  296. truthy.push(item);
  297. } else {
  298. falsy.push(item);
  299. }
  300. }
  301. } catch (e_6_1) {
  302. e_6 = {
  303. error: e_6_1
  304. };
  305. } finally {
  306. try {
  307. if (items_1_1 && !items_1_1.done && (_a = items_1.return)) _a.call(items_1);
  308. } finally {
  309. if (e_6) throw e_6.error;
  310. }
  311. }
  312. return [truthy, falsy];
  313. }
  314. function updateHistoryStates(hist, stateValue) {
  315. return mapValues(hist.states, function (subHist, key) {
  316. if (!subHist) {
  317. return undefined;
  318. }
  319. var subStateValue = (isString(stateValue) ? undefined : stateValue[key]) || (subHist ? subHist.current : undefined);
  320. if (!subStateValue) {
  321. return undefined;
  322. }
  323. return {
  324. current: subStateValue,
  325. states: updateHistoryStates(subHist, subStateValue)
  326. };
  327. });
  328. }
  329. function updateHistoryValue(hist, stateValue) {
  330. return {
  331. current: stateValue,
  332. states: updateHistoryStates(hist, stateValue)
  333. };
  334. }
  335. function updateContext(context, _event, assignActions, state) {
  336. if (!IS_PRODUCTION) {
  337. warn(!!context, 'Attempting to update undefined context');
  338. }
  339. var updatedContext = context ? assignActions.reduce(function (acc, assignAction) {
  340. var e_7, _a;
  341. var assignment = assignAction.assignment;
  342. var meta = {
  343. state: state,
  344. action: assignAction,
  345. _event: _event
  346. };
  347. var partialUpdate = {};
  348. if (isFunction(assignment)) {
  349. partialUpdate = assignment(acc, _event.data, meta);
  350. } else {
  351. try {
  352. for (var _b = __values(Object.keys(assignment)), _c = _b.next(); !_c.done; _c = _b.next()) {
  353. var key = _c.value;
  354. var propAssignment = assignment[key];
  355. partialUpdate[key] = isFunction(propAssignment) ? propAssignment(acc, _event.data, meta) : propAssignment;
  356. }
  357. } catch (e_7_1) {
  358. e_7 = {
  359. error: e_7_1
  360. };
  361. } finally {
  362. try {
  363. if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
  364. } finally {
  365. if (e_7) throw e_7.error;
  366. }
  367. }
  368. }
  369. return Object.assign({}, acc, partialUpdate);
  370. }, context) : context;
  371. return updatedContext;
  372. } // tslint:disable-next-line:no-empty
  373. var warn = function () {};
  374. if (!IS_PRODUCTION) {
  375. warn = function (condition, message) {
  376. var error = condition instanceof Error ? condition : undefined;
  377. if (!error && condition) {
  378. return;
  379. }
  380. if (console !== undefined) {
  381. var args = ["Warning: ".concat(message)];
  382. if (error) {
  383. args.push(error);
  384. } // tslint:disable-next-line:no-console
  385. console.warn.apply(console, args);
  386. }
  387. };
  388. }
  389. function isArray(value) {
  390. return Array.isArray(value);
  391. } // tslint:disable-next-line:ban-types
  392. function isFunction(value) {
  393. return typeof value === 'function';
  394. }
  395. function isString(value) {
  396. return typeof value === 'string';
  397. }
  398. function toGuard(condition, guardMap) {
  399. if (!condition) {
  400. return undefined;
  401. }
  402. if (isString(condition)) {
  403. return {
  404. type: DEFAULT_GUARD_TYPE,
  405. name: condition,
  406. predicate: guardMap ? guardMap[condition] : undefined
  407. };
  408. }
  409. if (isFunction(condition)) {
  410. return {
  411. type: DEFAULT_GUARD_TYPE,
  412. name: condition.name,
  413. predicate: condition
  414. };
  415. }
  416. return condition;
  417. }
  418. function isObservable(value) {
  419. try {
  420. return 'subscribe' in value && isFunction(value.subscribe);
  421. } catch (e) {
  422. return false;
  423. }
  424. }
  425. var symbolObservable = /*#__PURE__*/function () {
  426. return typeof Symbol === 'function' && Symbol.observable || '@@observable';
  427. }(); // TODO: to be removed in v5, left it out just to minimize the scope of the change and maintain compatibility with older versions of integration paackages
  428. var interopSymbols = (_a = {}, _a[symbolObservable] = function () {
  429. return this;
  430. }, _a[Symbol.observable] = function () {
  431. return this;
  432. }, _a);
  433. function isMachine(value) {
  434. return !!value && '__xstatenode' in value;
  435. }
  436. function isActor(value) {
  437. return !!value && typeof value.send === 'function';
  438. }
  439. var uniqueId = /*#__PURE__*/function () {
  440. var currentId = 0;
  441. return function () {
  442. currentId++;
  443. return currentId.toString(16);
  444. };
  445. }();
  446. function toEventObject(event, payload // id?: TEvent['type']
  447. ) {
  448. if (isString(event) || typeof event === 'number') {
  449. return __assign({
  450. type: event
  451. }, payload);
  452. }
  453. return event;
  454. }
  455. function toSCXMLEvent(event, scxmlEvent) {
  456. if (!isString(event) && '$$type' in event && event.$$type === 'scxml') {
  457. return event;
  458. }
  459. var eventObject = toEventObject(event);
  460. return __assign({
  461. name: eventObject.type,
  462. data: eventObject,
  463. $$type: 'scxml',
  464. type: 'external'
  465. }, scxmlEvent);
  466. }
  467. function toTransitionConfigArray(event, configLike) {
  468. var transitions = toArrayStrict(configLike).map(function (transitionLike) {
  469. if (typeof transitionLike === 'undefined' || typeof transitionLike === 'string' || isMachine(transitionLike)) {
  470. return {
  471. target: transitionLike,
  472. event: event
  473. };
  474. }
  475. return __assign(__assign({}, transitionLike), {
  476. event: event
  477. });
  478. });
  479. return transitions;
  480. }
  481. function normalizeTarget(target) {
  482. if (target === undefined || target === TARGETLESS_KEY) {
  483. return undefined;
  484. }
  485. return toArray(target);
  486. }
  487. function reportUnhandledExceptionOnInvocation(originalError, currentError, id) {
  488. if (!IS_PRODUCTION) {
  489. var originalStackTrace = originalError.stack ? " Stacktrace was '".concat(originalError.stack, "'") : '';
  490. if (originalError === currentError) {
  491. // tslint:disable-next-line:no-console
  492. console.error("Missing onError handler for invocation '".concat(id, "', error was '").concat(originalError, "'.").concat(originalStackTrace));
  493. } else {
  494. var stackTrace = currentError.stack ? " Stacktrace was '".concat(currentError.stack, "'") : ''; // tslint:disable-next-line:no-console
  495. console.error("Missing onError handler and/or unhandled exception/promise rejection for invocation '".concat(id, "'. ") + "Original error: '".concat(originalError, "'. ").concat(originalStackTrace, " Current error is '").concat(currentError, "'.").concat(stackTrace));
  496. }
  497. }
  498. }
  499. function evaluateGuard(machine, guard, context, _event, state) {
  500. var guards = machine.options.guards;
  501. var guardMeta = {
  502. state: state,
  503. cond: guard,
  504. _event: _event
  505. }; // TODO: do not hardcode!
  506. if (guard.type === DEFAULT_GUARD_TYPE) {
  507. return ((guards === null || guards === void 0 ? void 0 : guards[guard.name]) || guard.predicate)(context, _event.data, guardMeta);
  508. }
  509. var condFn = guards === null || guards === void 0 ? void 0 : guards[guard.type];
  510. if (!condFn) {
  511. throw new Error("Guard '".concat(guard.type, "' is not implemented on machine '").concat(machine.id, "'."));
  512. }
  513. return condFn(context, _event.data, guardMeta);
  514. }
  515. function toInvokeSource(src) {
  516. if (typeof src === 'string') {
  517. return {
  518. type: src
  519. };
  520. }
  521. return src;
  522. }
  523. function toObserver(nextHandler, errorHandler, completionHandler) {
  524. var noop = function () {};
  525. var isObserver = typeof nextHandler === 'object';
  526. var self = isObserver ? nextHandler : null;
  527. return {
  528. next: ((isObserver ? nextHandler.next : nextHandler) || noop).bind(self),
  529. error: ((isObserver ? nextHandler.error : errorHandler) || noop).bind(self),
  530. complete: ((isObserver ? nextHandler.complete : completionHandler) || noop).bind(self)
  531. };
  532. }
  533. function createInvokeId(stateNodeId, index) {
  534. return "".concat(stateNodeId, ":invocation[").concat(index, "]");
  535. }
  536. function isRaisableAction(action) {
  537. return (action.type === raise || action.type === send && action.to === SpecialTargets.Internal) && typeof action.delay !== 'number';
  538. }
  539. export { createInvokeId, evaluateGuard, flatten, getActionType, getEventType, interopSymbols, isActor, isArray, isBehavior, isBuiltInEvent, isFunction, isMachine, isObservable, isPromiseLike, isRaisableAction, isStateLike, isString, keys, mapContext, mapFilterValues, mapValues, matchesState, nestedPath, normalizeTarget, partition, path, pathToStateValue, pathsToStateValue, reportUnhandledExceptionOnInvocation, symbolObservable, toArray, toArrayStrict, toEventObject, toGuard, toInvokeSource, toObserver, toSCXMLEvent, toStatePath, toStatePaths, toStateValue, toTransitionConfigArray, uniqueId, updateContext, updateHistoryStates, updateHistoryValue, warn };