-
Notifications
You must be signed in to change notification settings - Fork 0
/
Editor.js
54 lines (40 loc) · 1.41 KB
/
Editor.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
const isObject = require('./lib/is-object')
const mapObj = require('./lib/map-object')
const isEmptyObject = require('./lib/is-empty-object')
const uniqueKeys = require('./lib/unique-keys')
const EDITS = Symbol('@Edits')
const DELETED = Symbol('@Delete')
function edit (target, edits = {}) {
if (!target || !isObject(target) || target[EDITS]) return target
const getEdited = (target, key) => {
if (edits.hasOwnProperty(key)) return edits[key]
if (target.hasOwnProperty(key)) return (edits[key] = edit(target[key]))
return undefined
}
return new Proxy(target, {
get (target, key) {
if (key === EDITS) return edits
const result = getEdited(target, key)
return (result === DELETED) ? undefined : result
},
set (_, key, value) {
edits[key] = (!isObject(value) || value[EDITS]) ? value : edit({}, value)
},
ownKeys (target) {
return uniqueKeys(edits, target).filter(key => getEdited(target, key) !== DELETED)
},
getOwnPropertyDescriptor (target, key) {
return Object.getOwnPropertyDescriptor(edits.hasOwnProperty(key) ? edits : target, key)
},
deleteProperty (target, key) {
edits[key] = DELETED
}
})
}
function edits (obj) {
if (!isObject(obj)) return obj
if (obj[EDITS]) return edits(obj[EDITS])
const reduced = mapObj(edits)(obj)
return isEmptyObject(reduced) ? undefined : reduced
}
module.exports = {edit, edits, DELETED}