pinia.prod.cjs 28 KB

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