{"version":3,"file":"pinia-decorator.min.cjs","sources":["../src/action.js","../src/raw-field.js","../src/to-store.js","../src/getter.js","../src/state.js","../src/store.js","../src/writable-state.js"],"sourcesContent":["////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { createDecorator } from '@haixing_hu/vue3-class-component';\nimport { mapActions } from 'pinia';\n\n/**\n * Injects a Pinia store's action to a Vue component class.\n *\n * This decorator should be used to decorate a class field.\n *\n * @param {object} store\n *     The Pinia store to be injected, which should be the object returned by\n *     the Pinia's `defineStore()` function..\n * @param {string} actionName\n *     The name of the action to be injected. If this argument is not specified,\n *     use the name of the decorated class field as the key.\n * @return {function}\n *     A class field decorator function.\n * @author Haixing Hu\n */\nfunction Action(store, actionName = undefined) {\n  return createDecorator((Class, instance, target, context, options) => {\n    if (context.kind !== 'field') {\n      throw new Error('The @Action decorator can only be used to decorate a class field.');\n    }\n    const key = actionName ?? context.name;\n    const actions = mapActions(store, [key]);\n    options['methods'][context.name] = actions[key];\n  });\n}\n\nexport default Action;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2024.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\n/**\n * The key of the metadata of a field of a Pinia store class, which indicates\n * that the field is a non-reactive raw field.\n *\n * @type {string}\n * @private\n * @author Haixing Hu\n */\nconst RAW_PROPERTY_KEY = '__pinia_decorator_raw_field__';\n\n/**\n * The decorator used to decorate a field of a Pinia store class, which indicates\n * that the field is a non-reactive raw field.\n *\n * The raw fields are not reactive, which means that the changes of the raw fields\n * will not trigger the reactivity of the Pinia store. The raw fields are useful\n * to store the data that should not be reactive.\n *\n * @param {undefined} target\n *     the target of the decorator. Since this decorator is used to decorate a\n *     class field, the target is always `undefined`.\n * @param {object} context\n *     the context of the decorator.\n * @author Haixing Hu\n */\nfunction RawField(target, context) {\n  if (context.kind !== 'field') {\n    throw new Error('The @RawField decorator can only be used to decorate a class field.');\n  }\n  const metadata = context.metadata;\n  metadata[RAW_PROPERTY_KEY] ??= [];\n  metadata[RAW_PROPERTY_KEY].push(context.name);\n}\n\nexport {\n  RAW_PROPERTY_KEY,\n  RawField,\n};\n\nexport default RawField;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2024.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { defineStore } from 'pinia';\nimport { markRaw } from 'vue';\nimport { RAW_PROPERTY_KEY } from './raw-field';\n\n/**\n * This function is used to convert a class into a Pinia store.\n *\n * For example, the following code defines a Pinia store named `user`.\n * Note that this function also support the inheritance of the store class.\n *\n * ```js\n * import { toStore } from '@haixing_hu/pinia-decorators';\n * import dayjs from 'dayjs';\n *\n * class BaseUserStore {\n *   id = '';\n *\n *   username = '';\n *\n *   password = '';\n *\n *   nickname = '';\n *\n *   get age() {\n *     throw new Error('Should be override by subclass');\n *   }\n *\n *   setNickname(nickname) {\n *     this.nickname = nickname;\n *   }\n *\n *   login() {\n *     throw new Error('Should be override by subclass');\n *   }\n * }\n *\n * class UserStore extends BaseUserStore {   // support inheritance of the store class\n *  avatar = '';\n *\n *  birthday = '';\n *\n *  get age() {\n *    return dayjs().diff(this.birthday, 'year');\n *  }\n *\n *  setAvatar(avatar) {\n *    this.avatar = avatar;\n *  }\n *\n *  updatePassword(password) {\n *    this.password = newPassword;\n *    return api.updatePassword(this.username, newPassword);\n *  }\n *\n *  login() {\n *    return api.login(this.username, this.password);\n *  }\n * }\n *\n * export default toStore('user', UserStore);\n * ```\n *\n * The above example is equivalent to the following code:\n *\n * ```javascript\n * import { defineStore } from 'pinia';\n *\n * const useUserStore = defineStore('user', {\n *   state: () => ({\n *     id: '',\n *     username: '',\n *     password: '',\n *     nickname: '',\n *     avatar: '',\n *     birthday: '',\n *   }),\n *\n *   getters: {\n *     age: (state) => dayjs().diff(state.birthday, 'year'),\n *   },\n *\n *   actions: {\n *     setNickname(nickname) {\n *       this.nickname = nickname;\n *     },\n *     setAvatar(avatar) {\n *       this.avatar = avatar;\n *     },\n *     updatePassword(newPassword) {\n *       this.password = newPassword;\n *       return api.updatePassword(this.username, newPassword);\n *     },\n *     login() {\n *       return api.login(this.username, this.password);\n *     },\n *   },\n * });\n *\n * export default useUserStore;\n * ```\n *\n * We can use the `user` store in the Vue components as follows:\n * ```vue\n * <template>\n *   <div>\n *     <div>Username: {{ username }}</div>\n *     <div>Age: {{ age }}</div>\n *     <div>Avatar: <img :src=\"avatar\" /></div>\n *     <button @click=\"setNickname('new-nickname')\">Set Nickname</button>\n *     <button @click=\"updatePassword('new-password')\">Change Password</button>\n *     <button @click=\"login()\">Login</button>\n *   </div>\n * </template>\n * <script>\n * import { Component, toVue } from '@haixing_hu/vue3-class-component';\n * import { State, Getter, Action } from '@haixing_hu/pinia-decorators';\n * import useUserStore from 'src/stores/user';\n *\n * &#064;Component\n * class UserPage {\n *   &#064;State(useUserStore)\n *   username;\n *\n *   &#064;State(useUserStore)\n *   avatar;\n *\n *   &#064;Getter(useUserStore)\n *   age;\n *\n *   &#064;Action(useUserStore)\n *   setNickname;\n *\n *   &#064;Action(useUserStore)\n *   updatePassword;\n *\n *   &#064;Action(useUserStore)\n *   login;\n * }\n *\n * export default toVue(UserPage);\n * </script>\n * ```\n *\n * @param {string} storeId\n *     The ID of the Pinia store.\n * @param {function} Class\n *     The class to be converted into a Pinia store.\n * @return {function}\n *     A class decorator function, which decorates a class as a Pinia store.\n */\nfunction toStore(storeId, Class) {\n  if (typeof storeId !== 'string') {\n    throw new TypeError('The first argument must be a string.');\n  }\n  if (typeof Class !== 'function') {\n    throw new TypeError('The second argument must be a class.');\n  }\n  const state = () => {\n    const instance = new Class();\n    const metadata = Class[Symbol.metadata] ?? {};\n    const rawFields = metadata[RAW_PROPERTY_KEY] ?? [];\n    // Gets all fields of the instance as the state object of the store.\n    const stateObj = {};\n    Object.getOwnPropertyNames(instance).forEach((key) => {\n      if (rawFields.includes(key)) {\n        stateObj[key] = markRaw(instance[key]);\n      } else {\n        stateObj[key] = instance[key];\n      }\n    });\n    return stateObj;\n  };\n  const getters = {};\n  const actions = {};\n  // Traverses the prototype chain to get all getters and methods.\n  let proto = Class.prototype;\n  while (proto !== Object.prototype) {\n    const currentProto = proto;\n    Object.getOwnPropertyNames(currentProto).forEach((key) => {\n      if (key === 'constructor') {\n        return;\n      }\n      const descriptor = Object.getOwnPropertyDescriptor(currentProto, key);\n      if (descriptor.get) {\n        if (!Object.prototype.hasOwnProperty.call(getters, key)) {\n          // the getter of the class is treated as a getter of the store\n          getters[key] = (state) => descriptor.get.call(state);\n        }\n      } else if (typeof descriptor.value === 'function') {\n        if (!Object.prototype.hasOwnProperty.call(actions, key)) {\n          // the method of the class is treated as an action of the store\n          actions[key] = descriptor.value;\n        }\n      }\n    });\n    proto = Object.getPrototypeOf(currentProto);\n  }\n  // Creates a store using the `defineStore` function of Pinia.\n  return defineStore(storeId, { state, getters, actions });\n}\n\nexport default toStore;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { createDecorator } from '@haixing_hu/vue3-class-component';\nimport { mapState } from 'pinia';\n\n/**\n * Injects a Pinia store's getter to a Vue component class.\n *\n * This decorator should be used to decorate a class field.\n *\n * @param {object} store\n *     The Pinia store to be injected, which should be the object returned by\n *     the Pinia's `defineStore()` function..\n * @param {string} getterName\n *     The name of the getter to be injected. If this argument is not specified,\n *     use the name of the decorated class field as the key.\n * @return {function}\n *     A class field decorator function.\n * @author Haixing Hu\n */\nfunction Getter(store, getterName = undefined) {\n  return createDecorator((Class, instance, target, context, options) => {\n    if (context.kind !== 'field') {\n      throw new Error('The @Getter decorator can only be used to decorate a class field.');\n    }\n    const key = getterName ?? context.name;\n    delete options.fields[context.name];\n    const getters = mapState(store, [key]);\n    options['computed'][context.name] = getters[key];\n  });\n}\n\nexport default Getter;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { createDecorator } from '@haixing_hu/vue3-class-component';\nimport { mapState } from 'pinia';\n\n/**\n * Injects a Pinia store's state to a Vue component class.\n *\n * This decorator should be used to decorate a class field.\n *\n * @param {object} store\n *     The Pinia store to be injected, which should be the object returned by\n *     the Pinia's `defineStore()` function..\n * @param {string} stateName\n *     The name of the state to be injected. If this argument is not specified,\n *     use the name of the decorated class field as the key.\n * @return {function}\n *     A class field decorator function.\n * @author Haixing Hu\n */\nfunction State(store, stateName = undefined) {\n  return createDecorator((Class, instance, target, context, options) => {\n    if (context.kind !== 'field') {\n      throw new Error('The @State decorator can only be used to decorate a class field.');\n    }\n    const key = stateName ?? context.name;\n    delete options.fields[context.name];\n    const states = mapState(store, [key]);\n    options['computed'][context.name] = states[key];\n  });\n}\n\nexport default State;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { createDecorator } from '@haixing_hu/vue3-class-component';\nimport { mapStores } from 'pinia';\n\n/**\n * Injects a Pinia store to a Vue component class.\n *\n * This decorator should be used to decorate a class field.\n *\n * @param {object} store\n *     The Pinia store to be injected, which should be the object returned by\n *     the Pinia's `defineStore()` function..\n * @return {function}\n *     A class field decorator function.\n * @author Haixing Hu\n */\nfunction Store(store) {\n  return createDecorator((Class, instance, target, context, options) => {\n    if (context.kind !== 'field') {\n      throw new Error('The @Store decorator can only be used to decorate a class field.');\n    }\n    const realId = `${store.$id}Store`;\n    const stores = mapStores(store);\n    const key = context.name;\n    delete options.fields[key];\n    options['computed'][context.name] = stores[realId];\n  });\n}\n\nexport default Store;\n","////////////////////////////////////////////////////////////////////////////////\n//\n//    Copyright (c) 2022 - 2023.\n//    Haixing Hu, Qubit Co. Ltd.\n//\n//    All rights reserved.\n//\n////////////////////////////////////////////////////////////////////////////////\nimport { createDecorator } from '@haixing_hu/vue3-class-component';\nimport { mapWritableState } from 'pinia';\n\n/**\n * Injects a Pinia store's writable state to a Vue component class.\n *\n * This decorator should be used to decorate a class field.\n *\n * @param {object} store\n *     The Pinia store to be injected, which should be the object returned by\n *     the Pinia's `defineStore()` function..\n * @param {string} stateName\n *     The name of the state to be injected. If this argument is not specified,\n *     use the name of the decorated class field as the key.\n * @return {function}\n *     A class field decorator function.\n * @author Haixing Hu\n */\nfunction WritableState(store, stateName = undefined) {\n  return createDecorator((Class, instance, target, context, options) => {\n    if (context.kind !== 'field') {\n      throw new Error('The @WritableState decorator can only be used to decorate a class field.');\n    }\n    const key = stateName ?? context.name;\n    delete options.fields[context.name];\n    const states = mapWritableState(store, [key]);\n    options['computed'][context.name] = states[key];\n  });\n}\n\nexport default WritableState;\n"],"names":["vue3ClassComponent","require","pinia","vue","RAW_PROPERTY_KEY","exports","Action","store","actionName","arguments","length","undefined","createDecorator","Class","instance","target","context","options","kind","Error","key","name","actions","mapActions","Getter","getterName","fields","getters","mapState","RawField","_metadata$RAW_PROPERT","metadata","push","State","stateName","states","Store","realId","concat","$id","stores","mapStores","WritableState","mapWritableState","toStore","storeId","TypeError","proto","prototype","_loop","currentProto","Object","getOwnPropertyNames","forEach","descriptor","getOwnPropertyDescriptor","get","hasOwnProperty","call","state","value","getPrototypeOf","defineStore","_Class$Symbol$metadat","rawFields","Symbol","stateObj","includes","markRaw"],"mappings":"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"}