· 6 years ago · Oct 17, 2019, 03:58 AM
1// APIStoreProps are properties that need to be
2// ignored when running APIStore.makeStore()
3const APIStoreProps = ['use', 'classes', 'constructor', 'init', 'state']
4
5// getMethods returns methods defined
6// in a given class' prototype, except init and constructor
7const getMethods = (cls) => {
8 return Object.getOwnPropertyNames(cls.prototype)
9 .reduce((obj, prop) => {
10 if (APIStoreProps.includes(prop)) {
11 return obj
12 } else if (typeof cls.prototype[prop] === 'function') {
13 return { ...obj, [prop]: cls.prototype[prop] }
14 }
15 }, {})
16}
17
18const getGetters = (cls) => {
19 return Object.getOwnPropertyNames(cls.prototype)
20 .reduce((obj, prop) => {
21 if (APIStoreProps.includes(prop)) {
22 return obj
23 } else if (typeof cls.prototype.__lookupGetter__(prop) === 'function') {
24 return { ...obj, [prop]: cls.prototype.__lookupGetter__(prop) }
25 }
26 }, {})
27}
28
29// APIStore is a metaclass in the sense that its derived
30// class serve as data entry points for the makeStore() static method,
31// whose ultimate purpose is to generate the Vuex global store
32export class APIStore {
33 static use (cls) {
34 if (!this.classes) {
35 this.classes = [cls]
36 } else {
37 this.classes.push(cls)
38 }
39 }
40 static makeClientReadyHandler (cls) {
41 if (process.browser) {
42 window.onNuxtReady((app) => {
43 if (cls.client) {
44 cls.client(app)
45 }
46 })
47 }
48 }
49 static makeStore () {
50 if (!this.classes) {
51 this.classes = []
52 }
53 this.makeClientReadyHandler(this)
54 return {
55 state: this.prototype.state,
56 getters: {
57 ...getGetters(this),
58 ...this.classes.reduce((obj, cls) => {
59 return { ...obj, ...getGetters(cls) }
60 }, {})
61 },
62 actions: {
63 ...getMethods(this),
64 ...this.classes.reduce((obj, cls) => {
65 return { ...obj, ...getMethods(cls) }
66 }, {}),
67 nuxtServerInit: this.prototype.init,
68 api: apiRequest
69 },
70 mutations: {
71 ...apiErrorMutations,
72 ...networkStateMutations,
73 update (state, props) {
74 for (const key in props) {
75 Vue.set(state, key, props[key])
76 }
77 }
78 }
79 }
80 }
81}