-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathDotNotationPointers.js
125 lines (107 loc) · 3.82 KB
/
DotNotationPointers.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
var DotNotationPointers = module.exports = function(rootObject, property) {
if(property === undefined) {
property = []
} else if(!(property instanceof Array)) {
property = property.split('.')
}
return createPointers(rootObject, property)
}
function createPointers(rootObject, propertyParts) {
var initialObject = {dummy: rootObject}
var curInfoObjects = [{obj: initialObject, last: 'dummy', propertyPath: []}]
propertyParts.forEach(function(part) {
var nextInfoObjects = []
curInfoObjects.forEach(function(current) {
var curValue = getValue(current.obj, current.last)
if(curValue instanceof Array && !isInteger(part)) {
curValue.forEach(function(property, index) {
nextInfoObjects.push({obj: getValue(curValue, index), propertyPath: current.propertyPath.concat(index, part), last: part})
})
} else {
nextInfoObjects.push({obj: curValue, propertyPath: current.propertyPath.concat(part), last: part})
}
})
curInfoObjects = nextInfoObjects
})
return curInfoObjects.map(function(current) {
if(current.obj === initialObject) {
var obj = current.obj.dummy
var last = undefined
} else {
var obj = current.obj
var last = current.last
}
return new DotNotationPointer(rootObject, current.propertyPath, {obj:obj, last: last})
})
}
function getValue(object, key) {
if(object === undefined)
return undefined
else
return object[key]
}
// an object that is passed a dot-syntax property path and can manipulate the value at that path
// rootObject is the object in which a value will be pointed to
// property can either be:
// a string, in which case it can have dot notation like "a.b.c"
// an array, in which case, each member of the array is a property of the last property (e.g. ['a','b'] is the same thing as "a.b")
var DotNotationPointer = function(rootObject, property, propertyInfo) {
this.root = rootObject
if(property === undefined) {
this.property = []
} else if(property instanceof Array) {
this.property = property
} else {
this.property = property.split('.')
}
if(propertyInfo !== undefined) {
this.propertyInfo = propertyInfo
}
}
DotNotationPointer.prototype = {}
// getter and setter for the value being pointed to
Object.defineProperty(DotNotationPointer.prototype, 'val', {
get: function() {
var info = this.propertyInfo
if(info.obj === undefined) {
return undefined
} else {
if(info.last !== undefined) {
return info.obj[info.last]
} else {
return info.obj
}
}
}, set: function(value) {
if (value === undefined) {
if (this.propertyInfo.obj !== undefined) {
delete this.propertyInfo.obj[this.propertyInfo.last]
}
} else {
if(this.propertyInfo.obj === undefined) { // create the path if it doesn't exist
createProperty(this)
}
this.propertyInfo.obj[this.propertyInfo.last] = value
}
}
})
function createProperty(that) {
var result = that.root
var lastIndex = that.property.length-1
for(var n=0; n<lastIndex; n++) {
var value = result[that.property[n]]
if(value === undefined) {
if(isInteger(that.property[n+1]))
var newValue = []
else
var newValue = {}
value = result[that.property[n]] = newValue
}
result = value
}
that.propertyInfo = {obj:result, last: that.property[lastIndex]}
}
function isInteger(v) {
var number = parseInt(v)
return !isNaN(number)
}