-
Notifications
You must be signed in to change notification settings - Fork 3
/
Target.js
140 lines (131 loc) · 4.12 KB
/
Target.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
const TargetExposition = require('./TargetExposition');
const map = require('./map');
/**
* Target mapper
*/
class Target {
/**
* @param {string} path dot-notation path to some property of your `vm` instance
*/
constructor(path) {
this.path = path;
// properties:
// this.action = undefined;
// this.mutation = undefined;
// this.dispatcher = undefined;
// this.customPayload = undefined
}
/**
* Should be used if you need to map some properties of the object, selected as a target into your computed properties.
* It allows to attach action dispatcher or hook callback on each property change.
*
* Also, both `dispatch()` and `hook()` can provide object mapped by Target instance to the callee, while setting
* the second argument `true` (you can read more in the documentation for them)
*
* @param {array} projection `target` object properties to be exposed
* @returns {TargetExposition}
*/
expose(projection) {
return new TargetExposition(this, projection);
}
/**
* In fact, that's syntax sugar for `hook()` method.
*
* Sets `mutation` to be commited on mapped property change
*
* `mutation` shall be called in the format:
*
* `commit(mutation, newValue)`
*
* @param {string} mutation mutation name
* @returns {Target}
*/
commit(mutation) {
this.mutation = mutation;
return this;
}
/**
* In fact, that's syntax sugar for `hook()` method.
*
* Sets `action` to be dispatched on mapped property change
*
* Your `action` shall be called in the format:
*
* `dispatch(action, newValue)`
*
* @param {string} action action name
* @returns {Target}
*/
dispatch(action) {
this.action = action;
return this;
}
/**
* Set hook that should be run on mapped property change.
*
* @param {Target~dispatcher} dispatcher
* @returns {Target}
*/
hook(dispatcher) {
this.dispatcher = dispatcher;
return this;
}
/**
* @callback Target~dispatcher
* @param {Store} store `vuex` store
* @param {mixed} value
*/
/**
* returns computed property pair of getters or/and setters for specified projection.
*
* If an alias is set, it can be used with spread operator setting provided alias as the computed property name
*
* @param {String} alias name of computed field target to be accessible
* @returns {*}
*/
map(alias) {
if (!alias) return map(this);
return Object.assign({ [ alias ]: map(this) }, this.inject || {});
}
/**
* apply plugin
*
* plugin is described by object, composed in such format:
*
* ```javascript
* {
* setter: function(key, value, nextSetter) { //setter is mandatory
* nextSetter(value);
* },
* getter: function(key, nextGetter) { //getter is optional
* return nextGetter();
* },
* inject: { // optional, here you can describe additional fields, you want to inject into result map
* $internal: {
* get() { ... },
* set(value) { ... }
* }
* },
* customPayload: if set to `true` it means that your plugin shall use own payload format, so we do not need to pass
* key to hook (action, commit)
* }
* ```
*
* @param {Object} plugin object, describing your plugin.
* @return {Target}
*/
use(plugin) {
const makeSetterGate = oldGate => !!oldGate ?
(key, setter) => function (value) { plugin.setter.call(this, key, value, oldGate(key, setter).bind(this)); } :
(key, setter) => function (value) { plugin.setter.call(this, key, value, setter.bind(this)); };
const makeGetterGate = oldGate => !!oldGate ?
(key, getter) => function () { return plugin.getter.call(this, key, oldGate(key, getter).bind(this)); } :
(key, getter) => function () { return plugin.getter.call(this, key, getter.bind(this)); };
this.gate = makeSetterGate(this.gate);
if (!!plugin.getter) this.getterGate = makeGetterGate(this.getterGate);
this.inject = Object.assign({}, plugin.inject, this.inject);
this.customPayload = this.customPayload || plugin.customPayload;
return this;
}
}
module.exports = Target;