pinia.prod.cjs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846
  1. /*!
  2. * pinia v2.3.0
  3. * (c) 2024 Eduardo San Martin Morote
  4. * @license MIT
  5. */
  6. 'use strict';
  7. var vueDemi = require('vue-demi');
  8. /**
  9. * setActivePinia must be called to handle SSR at the top of functions like
  10. * `fetch`, `setup`, `serverPrefetch` and others
  11. */
  12. let activePinia;
  13. /**
  14. * Sets or unsets the active pinia. Used in SSR and internally when calling
  15. * actions and getters
  16. *
  17. * @param pinia - Pinia instance
  18. */
  19. // @ts-expect-error: cannot constrain the type of the return
  20. const setActivePinia = (pinia) => (activePinia = pinia);
  21. /**
  22. * Get the currently active pinia if there is any.
  23. */
  24. const getActivePinia = () => (vueDemi.hasInjectionContext() && vueDemi.inject(piniaSymbol)) || activePinia;
  25. const piniaSymbol = (/* istanbul ignore next */ Symbol());
  26. function isPlainObject(
  27. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  28. o) {
  29. return (o &&
  30. typeof o === 'object' &&
  31. Object.prototype.toString.call(o) === '[object Object]' &&
  32. typeof o.toJSON !== 'function');
  33. }
  34. // type DeepReadonly<T> = { readonly [P in keyof T]: DeepReadonly<T[P]> }
  35. // TODO: can we change these to numbers?
  36. /**
  37. * Possible types for SubscriptionCallback
  38. */
  39. exports.MutationType = void 0;
  40. (function (MutationType) {
  41. /**
  42. * Direct mutation of the state:
  43. *
  44. * - `store.name = 'new name'`
  45. * - `store.$state.name = 'new name'`
  46. * - `store.list.push('new item')`
  47. */
  48. MutationType["direct"] = "direct";
  49. /**
  50. * Mutated the state with `$patch` and an object
  51. *
  52. * - `store.$patch({ name: 'newName' })`
  53. */
  54. MutationType["patchObject"] = "patch object";
  55. /**
  56. * Mutated the state with `$patch` and a function
  57. *
  58. * - `store.$patch(state => state.name = 'newName')`
  59. */
  60. MutationType["patchFunction"] = "patch function";
  61. // maybe reset? for $state = {} and $reset
  62. })(exports.MutationType || (exports.MutationType = {}));
  63. const IS_CLIENT = typeof window !== 'undefined';
  64. /**
  65. * Creates a Pinia instance to be used by the application
  66. */
  67. function createPinia() {
  68. const scope = vueDemi.effectScope(true);
  69. // NOTE: here we could check the window object for a state and directly set it
  70. // if there is anything like it with Vue 3 SSR
  71. const state = scope.run(() => vueDemi.ref({}));
  72. let _p = [];
  73. // plugins added before calling app.use(pinia)
  74. let toBeInstalled = [];
  75. const pinia = vueDemi.markRaw({
  76. install(app) {
  77. // this allows calling useStore() outside of a component setup after
  78. // installing pinia's plugin
  79. setActivePinia(pinia);
  80. if (!vueDemi.isVue2) {
  81. pinia._a = app;
  82. app.provide(piniaSymbol, pinia);
  83. app.config.globalProperties.$pinia = pinia;
  84. toBeInstalled.forEach((plugin) => _p.push(plugin));
  85. toBeInstalled = [];
  86. }
  87. },
  88. use(plugin) {
  89. if (!this._a && !vueDemi.isVue2) {
  90. toBeInstalled.push(plugin);
  91. }
  92. else {
  93. _p.push(plugin);
  94. }
  95. return this;
  96. },
  97. _p,
  98. // it's actually undefined here
  99. // @ts-expect-error
  100. _a: null,
  101. _e: scope,
  102. _s: new Map(),
  103. state,
  104. });
  105. return pinia;
  106. }
  107. /**
  108. * Dispose a Pinia instance by stopping its effectScope and removing the state, plugins and stores. This is mostly
  109. * useful in tests, with both a testing pinia or a regular pinia and in applications that use multiple pinia instances.
  110. * Once disposed, the pinia instance cannot be used anymore.
  111. *
  112. * @param pinia - pinia instance
  113. */
  114. function disposePinia(pinia) {
  115. pinia._e.stop();
  116. pinia._s.clear();
  117. pinia._p.splice(0);
  118. pinia.state.value = {};
  119. // @ts-expect-error: non valid
  120. pinia._a = null;
  121. }
  122. /**
  123. * Creates an _accept_ function to pass to `import.meta.hot` in Vite applications.
  124. *
  125. * @example
  126. * ```js
  127. * const useUser = defineStore(...)
  128. * if (import.meta.hot) {
  129. * import.meta.hot.accept(acceptHMRUpdate(useUser, import.meta.hot))
  130. * }
  131. * ```
  132. *
  133. * @param initialUseStore - return of the defineStore to hot update
  134. * @param hot - `import.meta.hot`
  135. */
  136. function acceptHMRUpdate(initialUseStore, hot) {
  137. // strip as much as possible from iife.prod
  138. {
  139. return () => { };
  140. }
  141. }
  142. const noop = () => { };
  143. function addSubscription(subscriptions, callback, detached, onCleanup = noop) {
  144. subscriptions.push(callback);
  145. const removeSubscription = () => {
  146. const idx = subscriptions.indexOf(callback);
  147. if (idx > -1) {
  148. subscriptions.splice(idx, 1);
  149. onCleanup();
  150. }
  151. };
  152. if (!detached && vueDemi.getCurrentScope()) {
  153. vueDemi.onScopeDispose(removeSubscription);
  154. }
  155. return removeSubscription;
  156. }
  157. function triggerSubscriptions(subscriptions, ...args) {
  158. subscriptions.slice().forEach((callback) => {
  159. callback(...args);
  160. });
  161. }
  162. const fallbackRunWithContext = (fn) => fn();
  163. /**
  164. * Marks a function as an action for `$onAction`
  165. * @internal
  166. */
  167. const ACTION_MARKER = Symbol();
  168. /**
  169. * Action name symbol. Allows to add a name to an action after defining it
  170. * @internal
  171. */
  172. const ACTION_NAME = Symbol();
  173. function mergeReactiveObjects(target, patchToApply) {
  174. // Handle Map instances
  175. if (target instanceof Map && patchToApply instanceof Map) {
  176. patchToApply.forEach((value, key) => target.set(key, value));
  177. }
  178. else if (target instanceof Set && patchToApply instanceof Set) {
  179. // Handle Set instances
  180. patchToApply.forEach(target.add, target);
  181. }
  182. // no need to go through symbols because they cannot be serialized anyway
  183. for (const key in patchToApply) {
  184. if (!patchToApply.hasOwnProperty(key))
  185. continue;
  186. const subPatch = patchToApply[key];
  187. const targetValue = target[key];
  188. if (isPlainObject(targetValue) &&
  189. isPlainObject(subPatch) &&
  190. target.hasOwnProperty(key) &&
  191. !vueDemi.isRef(subPatch) &&
  192. !vueDemi.isReactive(subPatch)) {
  193. // NOTE: here I wanted to warn about inconsistent types but it's not possible because in setup stores one might
  194. // start the value of a property as a certain type e.g. a Map, and then for some reason, during SSR, change that
  195. // to `undefined`. When trying to hydrate, we want to override the Map with `undefined`.
  196. target[key] = mergeReactiveObjects(targetValue, subPatch);
  197. }
  198. else {
  199. // @ts-expect-error: subPatch is a valid value
  200. target[key] = subPatch;
  201. }
  202. }
  203. return target;
  204. }
  205. const skipHydrateSymbol = /* istanbul ignore next */ Symbol();
  206. /**
  207. * Tells Pinia to skip the hydration process of a given object. This is useful in setup stores (only) when you return a
  208. * stateful object in the store but it isn't really state. e.g. returning a router instance in a setup store.
  209. *
  210. * @param obj - target object
  211. * @returns obj
  212. */
  213. function skipHydrate(obj) {
  214. return Object.defineProperty(obj, skipHydrateSymbol, {});
  215. }
  216. /**
  217. * Returns whether a value should be hydrated
  218. *
  219. * @param obj - target variable
  220. * @returns true if `obj` should be hydrated
  221. */
  222. function shouldHydrate(obj) {
  223. return !isPlainObject(obj) || !obj.hasOwnProperty(skipHydrateSymbol);
  224. }
  225. const { assign } = Object;
  226. function isComputed(o) {
  227. return !!(vueDemi.isRef(o) && o.effect);
  228. }
  229. function createOptionsStore(id, options, pinia, hot) {
  230. const { state, actions, getters } = options;
  231. const initialState = pinia.state.value[id];
  232. let store;
  233. function setup() {
  234. if (!initialState && (!false)) {
  235. /* istanbul ignore if */
  236. if (vueDemi.isVue2) {
  237. vueDemi.set(pinia.state.value, id, state ? state() : {});
  238. }
  239. else {
  240. pinia.state.value[id] = state ? state() : {};
  241. }
  242. }
  243. // avoid creating a state in pinia.state.value
  244. const localState = vueDemi.toRefs(pinia.state.value[id]);
  245. return assign(localState, actions, Object.keys(getters || {}).reduce((computedGetters, name) => {
  246. computedGetters[name] = vueDemi.markRaw(vueDemi.computed(() => {
  247. setActivePinia(pinia);
  248. // it was created just before
  249. const store = pinia._s.get(id);
  250. // allow cross using stores
  251. /* istanbul ignore if */
  252. if (vueDemi.isVue2 && !store._r)
  253. return;
  254. // @ts-expect-error
  255. // return getters![name].call(context, context)
  256. // TODO: avoid reading the getter while assigning with a global variable
  257. return getters[name].call(store, store);
  258. }));
  259. return computedGetters;
  260. }, {}));
  261. }
  262. store = createSetupStore(id, setup, options, pinia, hot, true);
  263. return store;
  264. }
  265. function createSetupStore($id, setup, options = {}, pinia, hot, isOptionsStore) {
  266. let scope;
  267. const optionsForPlugin = assign({ actions: {} }, options);
  268. // watcher options for $subscribe
  269. const $subscribeOptions = { deep: true };
  270. // internal state
  271. let isListening; // set to true at the end
  272. let isSyncListening; // set to true at the end
  273. let subscriptions = [];
  274. let actionSubscriptions = [];
  275. let debuggerEvents;
  276. const initialState = pinia.state.value[$id];
  277. // avoid setting the state for option stores if it is set
  278. // by the setup
  279. if (!isOptionsStore && !initialState && (!false)) {
  280. /* istanbul ignore if */
  281. if (vueDemi.isVue2) {
  282. vueDemi.set(pinia.state.value, $id, {});
  283. }
  284. else {
  285. pinia.state.value[$id] = {};
  286. }
  287. }
  288. vueDemi.ref({});
  289. // avoid triggering too many listeners
  290. // https://github.com/vuejs/pinia/issues/1129
  291. let activeListener;
  292. function $patch(partialStateOrMutator) {
  293. let subscriptionMutation;
  294. isListening = isSyncListening = false;
  295. if (typeof partialStateOrMutator === 'function') {
  296. partialStateOrMutator(pinia.state.value[$id]);
  297. subscriptionMutation = {
  298. type: exports.MutationType.patchFunction,
  299. storeId: $id,
  300. events: debuggerEvents,
  301. };
  302. }
  303. else {
  304. mergeReactiveObjects(pinia.state.value[$id], partialStateOrMutator);
  305. subscriptionMutation = {
  306. type: exports.MutationType.patchObject,
  307. payload: partialStateOrMutator,
  308. storeId: $id,
  309. events: debuggerEvents,
  310. };
  311. }
  312. const myListenerId = (activeListener = Symbol());
  313. vueDemi.nextTick().then(() => {
  314. if (activeListener === myListenerId) {
  315. isListening = true;
  316. }
  317. });
  318. isSyncListening = true;
  319. // because we paused the watcher, we need to manually call the subscriptions
  320. triggerSubscriptions(subscriptions, subscriptionMutation, pinia.state.value[$id]);
  321. }
  322. const $reset = isOptionsStore
  323. ? function $reset() {
  324. const { state } = options;
  325. const newState = state ? state() : {};
  326. // we use a patch to group all changes into one single subscription
  327. this.$patch(($state) => {
  328. // @ts-expect-error: FIXME: shouldn't error?
  329. assign($state, newState);
  330. });
  331. }
  332. : /* istanbul ignore next */
  333. noop;
  334. function $dispose() {
  335. scope.stop();
  336. subscriptions = [];
  337. actionSubscriptions = [];
  338. pinia._s.delete($id);
  339. }
  340. /**
  341. * Helper that wraps function so it can be tracked with $onAction
  342. * @param fn - action to wrap
  343. * @param name - name of the action
  344. */
  345. const action = (fn, name = '') => {
  346. if (ACTION_MARKER in fn) {
  347. fn[ACTION_NAME] = name;
  348. return fn;
  349. }
  350. const wrappedAction = function () {
  351. setActivePinia(pinia);
  352. const args = Array.from(arguments);
  353. const afterCallbackList = [];
  354. const onErrorCallbackList = [];
  355. function after(callback) {
  356. afterCallbackList.push(callback);
  357. }
  358. function onError(callback) {
  359. onErrorCallbackList.push(callback);
  360. }
  361. // @ts-expect-error
  362. triggerSubscriptions(actionSubscriptions, {
  363. args,
  364. name: wrappedAction[ACTION_NAME],
  365. store,
  366. after,
  367. onError,
  368. });
  369. let ret;
  370. try {
  371. ret = fn.apply(this && this.$id === $id ? this : store, args);
  372. // handle sync errors
  373. }
  374. catch (error) {
  375. triggerSubscriptions(onErrorCallbackList, error);
  376. throw error;
  377. }
  378. if (ret instanceof Promise) {
  379. return ret
  380. .then((value) => {
  381. triggerSubscriptions(afterCallbackList, value);
  382. return value;
  383. })
  384. .catch((error) => {
  385. triggerSubscriptions(onErrorCallbackList, error);
  386. return Promise.reject(error);
  387. });
  388. }
  389. // trigger after callbacks
  390. triggerSubscriptions(afterCallbackList, ret);
  391. return ret;
  392. };
  393. wrappedAction[ACTION_MARKER] = true;
  394. wrappedAction[ACTION_NAME] = name; // will be set later
  395. // @ts-expect-error: we are intentionally limiting the returned type to just Fn
  396. // because all the added properties are internals that are exposed through `$onAction()` only
  397. return wrappedAction;
  398. };
  399. const partialStore = {
  400. _p: pinia,
  401. // _s: scope,
  402. $id,
  403. $onAction: addSubscription.bind(null, actionSubscriptions),
  404. $patch,
  405. $reset,
  406. $subscribe(callback, options = {}) {
  407. const removeSubscription = addSubscription(subscriptions, callback, options.detached, () => stopWatcher());
  408. const stopWatcher = scope.run(() => vueDemi.watch(() => pinia.state.value[$id], (state) => {
  409. if (options.flush === 'sync' ? isSyncListening : isListening) {
  410. callback({
  411. storeId: $id,
  412. type: exports.MutationType.direct,
  413. events: debuggerEvents,
  414. }, state);
  415. }
  416. }, assign({}, $subscribeOptions, options)));
  417. return removeSubscription;
  418. },
  419. $dispose,
  420. };
  421. /* istanbul ignore if */
  422. if (vueDemi.isVue2) {
  423. // start as non ready
  424. partialStore._r = false;
  425. }
  426. const store = vueDemi.reactive(partialStore);
  427. // store the partial store now so the setup of stores can instantiate each other before they are finished without
  428. // creating infinite loops.
  429. pinia._s.set($id, store);
  430. const runWithContext = (pinia._a && pinia._a.runWithContext) || fallbackRunWithContext;
  431. // TODO: idea create skipSerialize that marks properties as non serializable and they are skipped
  432. const setupStore = runWithContext(() => pinia._e.run(() => (scope = vueDemi.effectScope()).run(() => setup({ action }))));
  433. // overwrite existing actions to support $onAction
  434. for (const key in setupStore) {
  435. const prop = setupStore[key];
  436. if ((vueDemi.isRef(prop) && !isComputed(prop)) || vueDemi.isReactive(prop)) {
  437. // mark it as a piece of state to be serialized
  438. if (!isOptionsStore) {
  439. // in setup stores we must hydrate the state and sync pinia state tree with the refs the user just created
  440. if (initialState && shouldHydrate(prop)) {
  441. if (vueDemi.isRef(prop)) {
  442. prop.value = initialState[key];
  443. }
  444. else {
  445. // probably a reactive object, lets recursively assign
  446. // @ts-expect-error: prop is unknown
  447. mergeReactiveObjects(prop, initialState[key]);
  448. }
  449. }
  450. // transfer the ref to the pinia state to keep everything in sync
  451. /* istanbul ignore if */
  452. if (vueDemi.isVue2) {
  453. vueDemi.set(pinia.state.value[$id], key, prop);
  454. }
  455. else {
  456. pinia.state.value[$id][key] = prop;
  457. }
  458. }
  459. // action
  460. }
  461. else if (typeof prop === 'function') {
  462. const actionValue = action(prop, key);
  463. // this a hot module replacement store because the hotUpdate method needs
  464. // to do it with the right context
  465. /* istanbul ignore if */
  466. if (vueDemi.isVue2) {
  467. vueDemi.set(setupStore, key, actionValue);
  468. }
  469. else {
  470. // @ts-expect-error
  471. setupStore[key] = actionValue;
  472. }
  473. // list actions so they can be used in plugins
  474. // @ts-expect-error
  475. optionsForPlugin.actions[key] = prop;
  476. }
  477. else ;
  478. }
  479. // add the state, getters, and action properties
  480. /* istanbul ignore if */
  481. if (vueDemi.isVue2) {
  482. Object.keys(setupStore).forEach((key) => {
  483. vueDemi.set(store, key, setupStore[key]);
  484. });
  485. }
  486. else {
  487. assign(store, setupStore);
  488. // allows retrieving reactive objects with `storeToRefs()`. Must be called after assigning to the reactive object.
  489. // Make `storeToRefs()` work with `reactive()` #799
  490. assign(vueDemi.toRaw(store), setupStore);
  491. }
  492. // use this instead of a computed with setter to be able to create it anywhere
  493. // without linking the computed lifespan to wherever the store is first
  494. // created.
  495. Object.defineProperty(store, '$state', {
  496. get: () => (pinia.state.value[$id]),
  497. set: (state) => {
  498. $patch(($state) => {
  499. // @ts-expect-error: FIXME: shouldn't error?
  500. assign($state, state);
  501. });
  502. },
  503. });
  504. /* istanbul ignore if */
  505. if (vueDemi.isVue2) {
  506. // mark the store as ready before plugins
  507. store._r = true;
  508. }
  509. // apply all plugins
  510. pinia._p.forEach((extender) => {
  511. /* istanbul ignore else */
  512. {
  513. assign(store, scope.run(() => extender({
  514. store: store,
  515. app: pinia._a,
  516. pinia,
  517. options: optionsForPlugin,
  518. })));
  519. }
  520. });
  521. // only apply hydrate to option stores with an initial state in pinia
  522. if (initialState &&
  523. isOptionsStore &&
  524. options.hydrate) {
  525. options.hydrate(store.$state, initialState);
  526. }
  527. isListening = true;
  528. isSyncListening = true;
  529. return store;
  530. }
  531. // allows unused stores to be tree shaken
  532. /*! #__NO_SIDE_EFFECTS__ */
  533. function defineStore(
  534. // TODO: add proper types from above
  535. idOrOptions, setup, setupOptions) {
  536. let id;
  537. let options;
  538. const isSetupStore = typeof setup === 'function';
  539. if (typeof idOrOptions === 'string') {
  540. id = idOrOptions;
  541. // the option store setup will contain the actual options in this case
  542. options = isSetupStore ? setupOptions : setup;
  543. }
  544. else {
  545. options = idOrOptions;
  546. id = idOrOptions.id;
  547. }
  548. function useStore(pinia, hot) {
  549. const hasContext = vueDemi.hasInjectionContext();
  550. pinia =
  551. // in test mode, ignore the argument provided as we can always retrieve a
  552. // pinia instance with getActivePinia()
  553. ((process.env.NODE_ENV === 'test') && activePinia && activePinia._testing ? null : pinia) ||
  554. (hasContext ? vueDemi.inject(piniaSymbol, null) : null);
  555. if (pinia)
  556. setActivePinia(pinia);
  557. pinia = activePinia;
  558. if (!pinia._s.has(id)) {
  559. // creating the store registers it in `pinia._s`
  560. if (isSetupStore) {
  561. createSetupStore(id, setup, options, pinia);
  562. }
  563. else {
  564. createOptionsStore(id, options, pinia);
  565. }
  566. }
  567. const store = pinia._s.get(id);
  568. // StoreGeneric cannot be casted towards Store
  569. return store;
  570. }
  571. useStore.$id = id;
  572. return useStore;
  573. }
  574. let mapStoreSuffix = 'Store';
  575. /**
  576. * Changes the suffix added by `mapStores()`. Can be set to an empty string.
  577. * Defaults to `"Store"`. Make sure to extend the MapStoresCustomization
  578. * interface if you are using TypeScript.
  579. *
  580. * @param suffix - new suffix
  581. */
  582. function setMapStoreSuffix(suffix // could be 'Store' but that would be annoying for JS
  583. ) {
  584. mapStoreSuffix = suffix;
  585. }
  586. /**
  587. * Allows using stores without the composition API (`setup()`) by generating an
  588. * object to be spread in the `computed` field of a component. It accepts a list
  589. * of store definitions.
  590. *
  591. * @example
  592. * ```js
  593. * export default {
  594. * computed: {
  595. * // other computed properties
  596. * ...mapStores(useUserStore, useCartStore)
  597. * },
  598. *
  599. * created() {
  600. * this.userStore // store with id "user"
  601. * this.cartStore // store with id "cart"
  602. * }
  603. * }
  604. * ```
  605. *
  606. * @param stores - list of stores to map to an object
  607. */
  608. function mapStores(...stores) {
  609. return stores.reduce((reduced, useStore) => {
  610. // @ts-expect-error: $id is added by defineStore
  611. reduced[useStore.$id + mapStoreSuffix] = function () {
  612. return useStore(this.$pinia);
  613. };
  614. return reduced;
  615. }, {});
  616. }
  617. /**
  618. * Allows using state and getters from one store without using the composition
  619. * API (`setup()`) by generating an object to be spread in the `computed` field
  620. * of a component.
  621. *
  622. * @param useStore - store to map from
  623. * @param keysOrMapper - array or object
  624. */
  625. function mapState(useStore, keysOrMapper) {
  626. return Array.isArray(keysOrMapper)
  627. ? keysOrMapper.reduce((reduced, key) => {
  628. reduced[key] = function () {
  629. // @ts-expect-error: FIXME: should work?
  630. return useStore(this.$pinia)[key];
  631. };
  632. return reduced;
  633. }, {})
  634. : Object.keys(keysOrMapper).reduce((reduced, key) => {
  635. // @ts-expect-error
  636. reduced[key] = function () {
  637. const store = useStore(this.$pinia);
  638. const storeKey = keysOrMapper[key];
  639. // for some reason TS is unable to infer the type of storeKey to be a
  640. // function
  641. return typeof storeKey === 'function'
  642. ? storeKey.call(this, store)
  643. : // @ts-expect-error: FIXME: should work?
  644. store[storeKey];
  645. };
  646. return reduced;
  647. }, {});
  648. }
  649. /**
  650. * Alias for `mapState()`. You should use `mapState()` instead.
  651. * @deprecated use `mapState()` instead.
  652. */
  653. const mapGetters = mapState;
  654. /**
  655. * Allows directly using actions from your store without using the composition
  656. * API (`setup()`) by generating an object to be spread in the `methods` field
  657. * of a component.
  658. *
  659. * @param useStore - store to map from
  660. * @param keysOrMapper - array or object
  661. */
  662. function mapActions(useStore, keysOrMapper) {
  663. return Array.isArray(keysOrMapper)
  664. ? keysOrMapper.reduce((reduced, key) => {
  665. // @ts-expect-error
  666. reduced[key] = function (...args) {
  667. // @ts-expect-error: FIXME: should work?
  668. return useStore(this.$pinia)[key](...args);
  669. };
  670. return reduced;
  671. }, {})
  672. : Object.keys(keysOrMapper).reduce((reduced, key) => {
  673. // @ts-expect-error
  674. reduced[key] = function (...args) {
  675. // @ts-expect-error: FIXME: should work?
  676. return useStore(this.$pinia)[keysOrMapper[key]](...args);
  677. };
  678. return reduced;
  679. }, {});
  680. }
  681. /**
  682. * Allows using state and getters from one store without using the composition
  683. * API (`setup()`) by generating an object to be spread in the `computed` field
  684. * of a component.
  685. *
  686. * @param useStore - store to map from
  687. * @param keysOrMapper - array or object
  688. */
  689. function mapWritableState(useStore, keysOrMapper) {
  690. return Array.isArray(keysOrMapper)
  691. ? keysOrMapper.reduce((reduced, key) => {
  692. reduced[key] = {
  693. get() {
  694. return useStore(this.$pinia)[key];
  695. },
  696. set(value) {
  697. return (useStore(this.$pinia)[key] = value);
  698. },
  699. };
  700. return reduced;
  701. }, {})
  702. : Object.keys(keysOrMapper).reduce((reduced, key) => {
  703. reduced[key] = {
  704. get() {
  705. return useStore(this.$pinia)[keysOrMapper[key]];
  706. },
  707. set(value) {
  708. return (useStore(this.$pinia)[keysOrMapper[key]] = value);
  709. },
  710. };
  711. return reduced;
  712. }, {});
  713. }
  714. /**
  715. * Creates an object of references with all the state, getters, and plugin-added
  716. * state properties of the store. Similar to `toRefs()` but specifically
  717. * designed for Pinia stores so methods and non reactive properties are
  718. * completely ignored.
  719. *
  720. * @param store - store to extract the refs from
  721. */
  722. function storeToRefs(store) {
  723. // See https://github.com/vuejs/pinia/issues/852
  724. // It's easier to just use toRefs() even if it includes more stuff
  725. if (vueDemi.isVue2) {
  726. // @ts-expect-error: toRefs include methods and others
  727. return vueDemi.toRefs(store);
  728. }
  729. else {
  730. const rawStore = vueDemi.toRaw(store);
  731. const refs = {};
  732. for (const key in rawStore) {
  733. const value = rawStore[key];
  734. // There is no native method to check for a computed
  735. // https://github.com/vuejs/core/pull/4165
  736. if (value.effect) {
  737. // @ts-expect-error: too hard to type correctly
  738. refs[key] =
  739. // ...
  740. vueDemi.computed({
  741. get: () => store[key],
  742. set(value) {
  743. store[key] = value;
  744. },
  745. });
  746. }
  747. else if (vueDemi.isRef(value) || vueDemi.isReactive(value)) {
  748. // @ts-expect-error: the key is state or getter
  749. refs[key] =
  750. // ---
  751. vueDemi.toRef(store, key);
  752. }
  753. }
  754. return refs;
  755. }
  756. }
  757. /**
  758. * Vue 2 Plugin that must be installed for pinia to work. Note **you don't need
  759. * this plugin if you are using Nuxt.js**. Use the `buildModule` instead:
  760. * https://pinia.vuejs.org/ssr/nuxt.html.
  761. *
  762. * @example
  763. * ```js
  764. * import Vue from 'vue'
  765. * import { PiniaVuePlugin, createPinia } from 'pinia'
  766. *
  767. * Vue.use(PiniaVuePlugin)
  768. * const pinia = createPinia()
  769. *
  770. * new Vue({
  771. * el: '#app',
  772. * // ...
  773. * pinia,
  774. * })
  775. * ```
  776. *
  777. * @param _Vue - `Vue` imported from 'vue'.
  778. */
  779. const PiniaVuePlugin = function (_Vue) {
  780. // Equivalent of
  781. // app.config.globalProperties.$pinia = pinia
  782. _Vue.mixin({
  783. beforeCreate() {
  784. const options = this.$options;
  785. if (options.pinia) {
  786. const pinia = options.pinia;
  787. // HACK: taken from provide(): https://github.com/vuejs/composition-api/blob/main/src/apis/inject.ts#L31
  788. /* istanbul ignore else */
  789. if (!this._provided) {
  790. const provideCache = {};
  791. Object.defineProperty(this, '_provided', {
  792. get: () => provideCache,
  793. set: (v) => Object.assign(provideCache, v),
  794. });
  795. }
  796. this._provided[piniaSymbol] = pinia;
  797. // propagate the pinia instance in an SSR friendly way
  798. // avoid adding it to nuxt twice
  799. /* istanbul ignore else */
  800. if (!this.$pinia) {
  801. this.$pinia = pinia;
  802. }
  803. pinia._a = this;
  804. if (IS_CLIENT) {
  805. // this allows calling useStore() outside of a component setup after
  806. // installing pinia's plugin
  807. setActivePinia(pinia);
  808. }
  809. }
  810. else if (!this.$pinia && options.parent && options.parent.$pinia) {
  811. this.$pinia = options.parent.$pinia;
  812. }
  813. },
  814. destroyed() {
  815. delete this._pStores;
  816. },
  817. });
  818. };
  819. exports.PiniaVuePlugin = PiniaVuePlugin;
  820. exports.acceptHMRUpdate = acceptHMRUpdate;
  821. exports.createPinia = createPinia;
  822. exports.defineStore = defineStore;
  823. exports.disposePinia = disposePinia;
  824. exports.getActivePinia = getActivePinia;
  825. exports.mapActions = mapActions;
  826. exports.mapGetters = mapGetters;
  827. exports.mapState = mapState;
  828. exports.mapStores = mapStores;
  829. exports.mapWritableState = mapWritableState;
  830. exports.setActivePinia = setActivePinia;
  831. exports.setMapStoreSuffix = setMapStoreSuffix;
  832. exports.shouldHydrate = shouldHydrate;
  833. exports.skipHydrate = skipHydrate;
  834. exports.storeToRefs = storeToRefs;