manyfest 1.0.30 → 1.0.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/debug/Harness.js +12 -14
- package/dist/manyfest.compatible.js +502 -66
- package/dist/manyfest.compatible.min.js +1 -1
- package/dist/manyfest.compatible.min.js.map +1 -1
- package/dist/manyfest.js +491 -54
- package/dist/manyfest.min.js +1 -1
- package/dist/manyfest.min.js.map +1 -1
- package/package.json +1 -1
- package/source/Manyfest-ObjectAddress-CheckAddressExists.js +109 -13
- package/source/Manyfest-ObjectAddress-DeleteValue.js +0 -2
- package/source/Manyfest-ObjectAddress-GetValue.js +136 -10
- package/source/Manyfest-ObjectAddress-Parser.js +298 -0
- package/source/Manyfest-ParseConditionals.js +10 -12
- package/test/Manyfest_Embedded_Solvers_tests.js +18 -16
- package/test/Manyfest_ObjectAddress_Parser_tests.js +160 -0
- package/test/Manyfest_Object_CheckExistence_tests.js +54 -0
- package/test/Manyfest_Object_Read_tests.js +126 -0
package/package.json
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @author <steven@velozo.com>
|
|
3
3
|
*/
|
|
4
|
-
|
|
4
|
+
const libSimpleLog = require('./Manyfest-LogToConsole.js');
|
|
5
|
+
// This is for resolving functions mid-address
|
|
6
|
+
const libGetObjectValue = require('./Manyfest-ObjectAddress-GetValue.js');
|
|
7
|
+
|
|
8
|
+
// TODO: Just until this is a fable service.
|
|
9
|
+
let _MockFable = { DataFormat: require('./Manyfest-ObjectAddress-Parser.js') };
|
|
5
10
|
|
|
6
11
|
/**
|
|
7
12
|
* Object Address Resolver
|
|
@@ -25,6 +30,7 @@ class ManyfestObjectAddressResolverCheckAddressExists
|
|
|
25
30
|
{
|
|
26
31
|
constructor()
|
|
27
32
|
{
|
|
33
|
+
this.getObjectValueClass = new libGetObjectValue(libSimpleLog, libSimpleLog);
|
|
28
34
|
}
|
|
29
35
|
|
|
30
36
|
// Check if an address exists.
|
|
@@ -33,7 +39,7 @@ class ManyfestObjectAddressResolverCheckAddressExists
|
|
|
33
39
|
// whether the element/property is actually there or not (it returns
|
|
34
40
|
// undefined whether the property exists or not). This function checks for
|
|
35
41
|
// existance and returns true or false dependent.
|
|
36
|
-
checkAddressExists (pObject, pAddress)
|
|
42
|
+
checkAddressExists (pObject, pAddress, pRootObject)
|
|
37
43
|
{
|
|
38
44
|
// TODO: Should these throw an error?
|
|
39
45
|
// Make sure pObject is an object
|
|
@@ -41,15 +47,51 @@ class ManyfestObjectAddressResolverCheckAddressExists
|
|
|
41
47
|
// Make sure pAddress is a string
|
|
42
48
|
if (typeof(pAddress) != 'string') return false;
|
|
43
49
|
|
|
44
|
-
//
|
|
45
|
-
|
|
50
|
+
// Set the root object to the passed-in object if it isn't set yet. This is expected to be the root object.
|
|
51
|
+
// NOTE: This was added to support functions mid-stream
|
|
52
|
+
let tmpRootObject = (typeof(pRootObject) == 'undefined') ? pObject : pRootObject;
|
|
53
|
+
|
|
54
|
+
// DONE: Make this work for things like SomeRootObject.Metadata["Some.People.Use.Bad.Object.Property.Names"]
|
|
55
|
+
let tmpAddressPartBeginning = _MockFable.DataFormat.stringGetFirstSegment(pAddress);
|
|
46
56
|
|
|
47
57
|
// This is the terminal address string (no more dots so the RECUSION ENDS IN HERE somehow)
|
|
48
|
-
if (
|
|
58
|
+
if (tmpAddressPartBeginning.length == pAddress.length)
|
|
49
59
|
{
|
|
50
60
|
// Check if the address refers to a boxed property
|
|
51
61
|
let tmpBracketStartIndex = pAddress.indexOf('[');
|
|
52
62
|
let tmpBracketStopIndex = pAddress.indexOf(']');
|
|
63
|
+
|
|
64
|
+
// Check if there is a function somewhere in the address... parenthesis start should only be in a function
|
|
65
|
+
let tmpFunctionStartIndex = pAddress.indexOf('(');
|
|
66
|
+
|
|
67
|
+
// NOTE THAT FUNCTIONS MUST RESOLVE FIRST
|
|
68
|
+
// Functions look like this
|
|
69
|
+
// MyFunction()
|
|
70
|
+
// MyFunction(Some.Address)
|
|
71
|
+
// MyFunction(Some.Address,Some.Other.Address)
|
|
72
|
+
// MyFunction(Some.Address,Some.Other.Address,Some.Third.Address)
|
|
73
|
+
//
|
|
74
|
+
// This could be enhanced to allow purely numeric and string values to be passed to the function. For now,
|
|
75
|
+
// To heck with that. This is a simple function call.
|
|
76
|
+
//
|
|
77
|
+
// The requirements to detect a function are:
|
|
78
|
+
// 1) The start bracket is after character 0
|
|
79
|
+
if ((tmpFunctionStartIndex > 0)
|
|
80
|
+
// 2) The end bracket is after the start bracket
|
|
81
|
+
&& (_MockFable.DataFormat.stringCountEnclosures(pAddress) > 0))
|
|
82
|
+
{
|
|
83
|
+
let tmpFunctionAddress = pAddress.substring(0, tmpFunctionStartIndex).trim();
|
|
84
|
+
|
|
85
|
+
if ((pObject.hasOwnProperty(tmpFunctionAddress)) && (typeof(pObject[tmpFunctionAddress]) == 'function'))
|
|
86
|
+
{
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
else
|
|
90
|
+
{
|
|
91
|
+
// The address suggests it is a function, but it is not.
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
53
95
|
// Boxed elements look like this:
|
|
54
96
|
// MyValues[10]
|
|
55
97
|
// MyValues['Name']
|
|
@@ -59,7 +101,7 @@ class ManyfestObjectAddressResolverCheckAddressExists
|
|
|
59
101
|
// When we are passed SomeObject["Name"] this code below recurses as if it were SomeObject.Name
|
|
60
102
|
// The requirements to detect a boxed element are:
|
|
61
103
|
// 1) The start bracket is after character 0
|
|
62
|
-
if ((tmpBracketStartIndex > 0)
|
|
104
|
+
else if ((tmpBracketStartIndex > 0)
|
|
63
105
|
// 2) The end bracket has something between them
|
|
64
106
|
&& (tmpBracketStopIndex > tmpBracketStartIndex)
|
|
65
107
|
// 3) There is data
|
|
@@ -117,13 +159,67 @@ class ManyfestObjectAddressResolverCheckAddressExists
|
|
|
117
159
|
}
|
|
118
160
|
else
|
|
119
161
|
{
|
|
120
|
-
let tmpSubObjectName =
|
|
121
|
-
let tmpNewAddress = pAddress.substring(
|
|
162
|
+
let tmpSubObjectName = tmpAddressPartBeginning;
|
|
163
|
+
let tmpNewAddress = pAddress.substring(tmpAddressPartBeginning.length+1);
|
|
122
164
|
|
|
123
165
|
// Test if the tmpNewAddress is an array or object
|
|
124
166
|
// Check if it's a boxed property
|
|
125
167
|
let tmpBracketStartIndex = tmpSubObjectName.indexOf('[');
|
|
126
168
|
let tmpBracketStopIndex = tmpSubObjectName.indexOf(']');
|
|
169
|
+
|
|
170
|
+
// Check if there is a function somewhere in the address... parenthesis start should only be in a function
|
|
171
|
+
let tmpFunctionStartIndex = tmpSubObjectName.indexOf('(');
|
|
172
|
+
|
|
173
|
+
// NOTE THAT FUNCTIONS MUST RESOLVE FIRST
|
|
174
|
+
// Functions look like this
|
|
175
|
+
// MyFunction()
|
|
176
|
+
// MyFunction(Some.Address)
|
|
177
|
+
// MyFunction(Some.Address,Some.Other.Address)
|
|
178
|
+
// MyFunction(Some.Address,Some.Other.Address,Some.Third.Address)
|
|
179
|
+
//
|
|
180
|
+
// This could be enhanced to allow purely numeric and string values to be passed to the function. For now,
|
|
181
|
+
// To heck with that. This is a simple function call.
|
|
182
|
+
//
|
|
183
|
+
// The requirements to detect a function are:
|
|
184
|
+
// 1) The start bracket is after character 0
|
|
185
|
+
if ((tmpFunctionStartIndex > 0)
|
|
186
|
+
// 2) The end bracket is after the start bracket
|
|
187
|
+
&& (_MockFable.DataFormat.stringCountEnclosures(tmpSubObjectName) > 0))
|
|
188
|
+
{
|
|
189
|
+
let tmpFunctionAddress = tmpSubObjectName.substring(0, tmpFunctionStartIndex).trim();
|
|
190
|
+
//tmpParentAddress = `${tmpParentAddress}${(tmpParentAddress.length > 0) ? '.' : ''}${tmpSubObjectName}`;
|
|
191
|
+
|
|
192
|
+
if (!typeof(pObject[tmpFunctionAddress]) == 'function')
|
|
193
|
+
{
|
|
194
|
+
// The address suggests it is a function, but it is not.
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Now see if the function has arguments.
|
|
199
|
+
// Implementation notes: * ARGUMENTS MUST SHARE THE SAME ROOT OBJECT CONTEXT *
|
|
200
|
+
let tmpFunctionArguments = _MockFable.DataFormat.stringGetSegments(_MockFable.DataFormat.stringGetEnclosureValueByIndex(tmpSubObjectName.substring(tmpFunctionAddress.length), 0), ',');
|
|
201
|
+
if ((tmpFunctionArguments.length == 0) || (tmpFunctionArguments[0] == ''))
|
|
202
|
+
{
|
|
203
|
+
// No arguments... just call the function (bound to the scope of the object it is contained withing)
|
|
204
|
+
return this.checkAddressExists(pObject[tmpFunctionAddress].apply(pObject), tmpNewAddress, tmpRootObject);
|
|
205
|
+
}
|
|
206
|
+
else
|
|
207
|
+
{
|
|
208
|
+
let tmpArgumentValues = [];
|
|
209
|
+
|
|
210
|
+
let tmpRootObject = (typeof(pRootObject) == 'undefined') ? pObject : pRootObject;
|
|
211
|
+
|
|
212
|
+
// Now get the value for each argument
|
|
213
|
+
for (let i = 0; i < tmpFunctionArguments.length; i++)
|
|
214
|
+
{
|
|
215
|
+
// Resolve the values for each subsequent entry
|
|
216
|
+
// NOTE: This is where the resolves get really tricky. Recursion within recursion. Programming gom jabbar, yo.
|
|
217
|
+
tmpArgumentValues.push(this.getObjectValueClass.getValueAtAddress(tmpRootObject, tmpFunctionArguments[i]));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return this.checkAddressExists(pObject[tmpFunctionAddress].apply(pObject, tmpArgumentValues), tmpNewAddress, tmpRootObject);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
127
223
|
// Boxed elements look like this:
|
|
128
224
|
// MyValues[42]
|
|
129
225
|
// MyValues['Color']
|
|
@@ -133,7 +229,7 @@ class ManyfestObjectAddressResolverCheckAddressExists
|
|
|
133
229
|
// When we are passed SomeObject["Name"] this code below recurses as if it were SomeObject.Name
|
|
134
230
|
// The requirements to detect a boxed element are:
|
|
135
231
|
// 1) The start bracket is after character 0
|
|
136
|
-
if ((tmpBracketStartIndex > 0)
|
|
232
|
+
else if ((tmpBracketStartIndex > 0)
|
|
137
233
|
// 2) The end bracket has something between them
|
|
138
234
|
&& (tmpBracketStopIndex > tmpBracketStartIndex)
|
|
139
235
|
// 3) There is data
|
|
@@ -177,12 +273,12 @@ class ManyfestObjectAddressResolverCheckAddressExists
|
|
|
177
273
|
tmpBoxedPropertyReference = this.cleanWrapCharacters("'", tmpBoxedPropertyReference);
|
|
178
274
|
|
|
179
275
|
// Recurse directly into the subobject
|
|
180
|
-
return this.checkAddressExists(pObject[tmpBoxedPropertyName][tmpBoxedPropertyReference], tmpNewAddress);
|
|
276
|
+
return this.checkAddressExists(pObject[tmpBoxedPropertyName][tmpBoxedPropertyReference], tmpNewAddress, tmpRootObject);
|
|
181
277
|
}
|
|
182
278
|
else
|
|
183
279
|
{
|
|
184
280
|
// We parsed a valid number out of the boxed property name, so recurse into the array
|
|
185
|
-
return this.checkAddressExists(pObject[tmpBoxedPropertyName][tmpBoxedPropertyNumber], tmpNewAddress);
|
|
281
|
+
return this.checkAddressExists(pObject[tmpBoxedPropertyName][tmpBoxedPropertyNumber], tmpNewAddress, tmpRootObject);
|
|
186
282
|
}
|
|
187
283
|
}
|
|
188
284
|
|
|
@@ -195,13 +291,13 @@ class ManyfestObjectAddressResolverCheckAddressExists
|
|
|
195
291
|
else if (pObject.hasOwnProperty(tmpSubObjectName))
|
|
196
292
|
{
|
|
197
293
|
// If there is already a subobject pass that to the recursive thingy
|
|
198
|
-
return this.checkAddressExists(pObject[tmpSubObjectName], tmpNewAddress);
|
|
294
|
+
return this.checkAddressExists(pObject[tmpSubObjectName], tmpNewAddress, tmpRootObject);
|
|
199
295
|
}
|
|
200
296
|
else
|
|
201
297
|
{
|
|
202
298
|
// Create a subobject and then pass that
|
|
203
299
|
pObject[tmpSubObjectName] = {};
|
|
204
|
-
return this.checkAddressExists(pObject[tmpSubObjectName], tmpNewAddress);
|
|
300
|
+
return this.checkAddressExists(pObject[tmpSubObjectName], tmpNewAddress, tmpRootObject);
|
|
205
301
|
}
|
|
206
302
|
}
|
|
207
303
|
}
|
|
@@ -235,8 +235,6 @@ class ManyfestObjectAddressResolverDeleteValue
|
|
|
235
235
|
{
|
|
236
236
|
return false;
|
|
237
237
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
238
|
//This is a bracketed value
|
|
241
239
|
// 4) If the middle part is *only* a number (no single, double or backtick quotes) it is an array element,
|
|
242
240
|
// otherwise we will try to reat it as a dynamic object property.
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
*/
|
|
4
4
|
let libSimpleLog = require('./Manyfest-LogToConsole.js');
|
|
5
5
|
let fCleanWrapCharacters = require('./Manyfest-CleanWrapCharacters.js');
|
|
6
|
-
let fParseConditionals = require(`../source/Manyfest-ParseConditionals.js`)
|
|
6
|
+
let fParseConditionals = require(`../source/Manyfest-ParseConditionals.js`);
|
|
7
|
+
|
|
8
|
+
let _MockFable = { DataFormat: require('./Manyfest-ObjectAddress-Parser.js') };
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* Object Address Resolver - GetValue
|
|
@@ -58,15 +60,15 @@ class ManyfestObjectAddressResolverGetValue
|
|
|
58
60
|
// Set the root object to the passed-in object if it isn't set yet. This is expected to be the root object.
|
|
59
61
|
let tmpRootObject = (typeof(pRootObject) == 'undefined') ? pObject : pRootObject;
|
|
60
62
|
|
|
61
|
-
//
|
|
62
|
-
let
|
|
63
|
+
// DONE: Make this work for things like SomeRootObject.Metadata["Some.People.Use.Bad.Object.Property.Names"]
|
|
64
|
+
let tmpAddressPartBeginning = _MockFable.DataFormat.stringGetFirstSegment(pAddress);
|
|
63
65
|
|
|
64
66
|
// Adding simple back-navigation in objects
|
|
65
|
-
if (
|
|
67
|
+
if (tmpAddressPartBeginning == '')
|
|
66
68
|
{
|
|
67
69
|
// Given an address of "Bundle.Contract.IDContract...Project.IDProject" the ... would be interpreted as two back-navigations from IDContract.
|
|
68
70
|
// When the address is passed in, though, the first . is already eliminated. So we can count the dots.
|
|
69
|
-
let tmpParentAddressParts =
|
|
71
|
+
let tmpParentAddressParts = _MockFable.DataFormat.stringGetSegments(tmpParentAddress);
|
|
70
72
|
|
|
71
73
|
let tmpBackNavigationCount = 0;
|
|
72
74
|
|
|
@@ -104,8 +106,10 @@ class ManyfestObjectAddressResolverGetValue
|
|
|
104
106
|
}
|
|
105
107
|
|
|
106
108
|
// This is the terminal address string (no more dots so the RECUSION ENDS IN HERE somehow)
|
|
107
|
-
if (
|
|
109
|
+
if (tmpAddressPartBeginning.length == pAddress.length)
|
|
108
110
|
{
|
|
111
|
+
// TODO: Optimize this by having these calls only happen when the previous fails.
|
|
112
|
+
// TODO: Alternatively look for all markers in one pass?
|
|
109
113
|
// Check if the address refers to a boxed property
|
|
110
114
|
let tmpBracketStartIndex = pAddress.indexOf('[');
|
|
111
115
|
let tmpBracketStopIndex = pAddress.indexOf(']');
|
|
@@ -114,6 +118,72 @@ class ManyfestObjectAddressResolverGetValue
|
|
|
114
118
|
// Note this will not work with a bracket in the same address box set
|
|
115
119
|
let tmpObjectTypeMarkerIndex = pAddress.indexOf('{}');
|
|
116
120
|
|
|
121
|
+
|
|
122
|
+
// Check if there is a function somewhere in the address... parenthesis start should only be in a function
|
|
123
|
+
let tmpFunctionStartIndex = pAddress.indexOf('(');
|
|
124
|
+
|
|
125
|
+
// NOTE THAT FUNCTIONS MUST RESOLVE FIRST
|
|
126
|
+
// Functions look like this
|
|
127
|
+
// MyFunction()
|
|
128
|
+
// MyFunction(Some.Address)
|
|
129
|
+
// MyFunction(Some.Address,Some.Other.Address)
|
|
130
|
+
// MyFunction(Some.Address,Some.Other.Address,Some.Third.Address)
|
|
131
|
+
//
|
|
132
|
+
// This could be enhanced to allow purely numeric and string values to be passed to the function. For now,
|
|
133
|
+
// To heck with that. This is a simple function call.
|
|
134
|
+
//
|
|
135
|
+
// The requirements to detect a function are:
|
|
136
|
+
// 1) The start bracket is after character 0
|
|
137
|
+
if ((tmpFunctionStartIndex > 0)
|
|
138
|
+
// 2) The end bracket is after the start bracket
|
|
139
|
+
&& (_MockFable.DataFormat.stringCountEnclosures(pAddress) > 0))
|
|
140
|
+
{
|
|
141
|
+
let tmpFunctionAddress = pAddress.substring(0, tmpFunctionStartIndex).trim();
|
|
142
|
+
|
|
143
|
+
if (!typeof(pObject[tmpFunctionAddress]) == 'function')
|
|
144
|
+
{
|
|
145
|
+
// The address suggests it is a function, but it is not.
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Now see if the function has arguments.
|
|
150
|
+
// Implementation notes: * ARGUMENTS MUST SHARE THE SAME ROOT OBJECT CONTEXT *
|
|
151
|
+
let tmpFunctionArguments = _MockFable.DataFormat.stringGetSegments(_MockFable.DataFormat.stringGetEnclosureValueByIndex(pAddress.substring(tmpFunctionAddress.length), 0), ',');
|
|
152
|
+
if ((tmpFunctionArguments.length == 0) || (tmpFunctionArguments[0] == ''))
|
|
153
|
+
{
|
|
154
|
+
// No arguments... just call the function (bound to the scope of the object it is contained withing)
|
|
155
|
+
return pObject[tmpFunctionAddress].apply(pObject);
|
|
156
|
+
}
|
|
157
|
+
else
|
|
158
|
+
{
|
|
159
|
+
let tmpArgumentValues = [];
|
|
160
|
+
|
|
161
|
+
let tmpRootObject = (typeof(pRootObject) == 'undefined') ? pObject : pRootObject;
|
|
162
|
+
|
|
163
|
+
// Now get the value for each argument
|
|
164
|
+
for (let i = 0; i < tmpFunctionArguments.length; i++)
|
|
165
|
+
{
|
|
166
|
+
if(tmpFunctionArguments[i][0] == "'" && tmpFunctionArguments[i][tmpFunctionArguments[i].length - 1] == "'")
|
|
167
|
+
{
|
|
168
|
+
tmpArgumentValues.push(tmpFunctionArguments[i].substring(1, tmpFunctionArguments[i].length - 1));
|
|
169
|
+
}
|
|
170
|
+
else if(tmpFunctionArguments[i][0] == '"' && tmpFunctionArguments[i][tmpFunctionArguments[i].length - 1] == '"')
|
|
171
|
+
{
|
|
172
|
+
tmpArgumentValues.push(tmpFunctionArguments[i].substring(1, tmpFunctionArguments[i].length - 1));
|
|
173
|
+
}
|
|
174
|
+
else if(tmpFunctionArguments[i][0] == "`" && tmpFunctionArguments[i][tmpFunctionArguments[i].length - 1] == "`")
|
|
175
|
+
{
|
|
176
|
+
tmpArgumentValues.push(tmpFunctionArguments[i].substring(1, tmpFunctionArguments[i].length - 1));
|
|
177
|
+
}
|
|
178
|
+
else
|
|
179
|
+
{
|
|
180
|
+
tmpArgumentValues.push(this.getValueAtAddress(tmpRootObject, tmpFunctionArguments[i]));
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return pObject[tmpFunctionAddress].apply(pObject, tmpArgumentValues);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
117
187
|
// Boxed elements look like this:
|
|
118
188
|
// MyValues[10]
|
|
119
189
|
// MyValues['Name']
|
|
@@ -123,7 +193,7 @@ class ManyfestObjectAddressResolverGetValue
|
|
|
123
193
|
// When we are passed SomeObject["Name"] this code below recurses as if it were SomeObject.Name
|
|
124
194
|
// The requirements to detect a boxed element are:
|
|
125
195
|
// 1) The start bracket is after character 0
|
|
126
|
-
if ((tmpBracketStartIndex > 0)
|
|
196
|
+
else if ((tmpBracketStartIndex > 0)
|
|
127
197
|
// 2) The end bracket has something between them
|
|
128
198
|
&& (tmpBracketStopIndex > tmpBracketStartIndex)
|
|
129
199
|
// 3) There is data
|
|
@@ -197,6 +267,7 @@ class ManyfestObjectAddressResolverGetValue
|
|
|
197
267
|
if (tmpKeepRecord)
|
|
198
268
|
{
|
|
199
269
|
tmpOutputArray.push(tmpInputArray[i]);
|
|
270
|
+
|
|
200
271
|
}
|
|
201
272
|
}
|
|
202
273
|
|
|
@@ -230,14 +301,69 @@ class ManyfestObjectAddressResolverGetValue
|
|
|
230
301
|
}
|
|
231
302
|
else
|
|
232
303
|
{
|
|
233
|
-
let tmpSubObjectName = pAddress.substring(0, tmpSeparatorIndex);
|
|
234
|
-
let tmpNewAddress = pAddress.substring(tmpSeparatorIndex+1);
|
|
304
|
+
//let tmpSubObjectName = pAddress.substring(0, tmpSeparatorIndex);
|
|
305
|
+
//let tmpNewAddress = pAddress.substring(tmpSeparatorIndex+1);
|
|
306
|
+
let tmpSubObjectName = tmpAddressPartBeginning;
|
|
307
|
+
let tmpNewAddress = pAddress.substring(tmpAddressPartBeginning.length+1);
|
|
235
308
|
|
|
236
309
|
// BOXED ELEMENTS
|
|
237
310
|
// Test if the tmpNewAddress is an array or object
|
|
238
311
|
// Check if it's a boxed property
|
|
239
312
|
let tmpBracketStartIndex = tmpSubObjectName.indexOf('[');
|
|
240
313
|
let tmpBracketStopIndex = tmpSubObjectName.indexOf(']');
|
|
314
|
+
|
|
315
|
+
// Check if there is a function somewhere in the address... parenthesis start should only be in a function
|
|
316
|
+
let tmpFunctionStartIndex = tmpSubObjectName.indexOf('(');
|
|
317
|
+
|
|
318
|
+
// NOTE THAT FUNCTIONS MUST RESOLVE FIRST
|
|
319
|
+
// Functions look like this
|
|
320
|
+
// MyFunction()
|
|
321
|
+
// MyFunction(Some.Address)
|
|
322
|
+
// MyFunction(Some.Address,Some.Other.Address)
|
|
323
|
+
// MyFunction(Some.Address,Some.Other.Address,Some.Third.Address)
|
|
324
|
+
//
|
|
325
|
+
// This could be enhanced to allow purely numeric and string values to be passed to the function. For now,
|
|
326
|
+
// To heck with that. This is a simple function call.
|
|
327
|
+
//
|
|
328
|
+
// The requirements to detect a function are:
|
|
329
|
+
// 1) The start bracket is after character 0
|
|
330
|
+
if ((tmpFunctionStartIndex > 0)
|
|
331
|
+
// 2) The end bracket is after the start bracket
|
|
332
|
+
&& (_MockFable.DataFormat.stringCountEnclosures(tmpSubObjectName) > 0))
|
|
333
|
+
{
|
|
334
|
+
let tmpFunctionAddress = tmpSubObjectName.substring(0, tmpFunctionStartIndex).trim();
|
|
335
|
+
tmpParentAddress = `${tmpParentAddress}${(tmpParentAddress.length > 0) ? '.' : ''}${tmpSubObjectName}`;
|
|
336
|
+
|
|
337
|
+
if (!typeof(pObject[tmpFunctionAddress]) == 'function')
|
|
338
|
+
{
|
|
339
|
+
// The address suggests it is a function, but it is not.
|
|
340
|
+
return false;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Now see if the function has arguments.
|
|
344
|
+
// Implementation notes: * ARGUMENTS MUST SHARE THE SAME ROOT OBJECT CONTEXT *
|
|
345
|
+
let tmpFunctionArguments = _MockFable.DataFormat.stringGetSegments(_MockFable.DataFormat.stringGetEnclosureValueByIndex(tmpSubObjectName.substring(tmpFunctionAddress.length), 0), ',');
|
|
346
|
+
if ((tmpFunctionArguments.length == 0) || (tmpFunctionArguments[0] == ''))
|
|
347
|
+
{
|
|
348
|
+
// No arguments... just call the function (bound to the scope of the object it is contained withing)
|
|
349
|
+
return this.getValueAtAddress(pObject[tmpFunctionAddress].apply(pObject), tmpNewAddress, tmpParentAddress, tmpRootObject);
|
|
350
|
+
}
|
|
351
|
+
else
|
|
352
|
+
{
|
|
353
|
+
let tmpArgumentValues = [];
|
|
354
|
+
|
|
355
|
+
let tmpRootObject = (typeof(pRootObject) == 'undefined') ? pObject : pRootObject;
|
|
356
|
+
|
|
357
|
+
// Now get the value for each argument
|
|
358
|
+
for (let i = 0; i < tmpFunctionArguments.length; i++)
|
|
359
|
+
{
|
|
360
|
+
// Resolve the values for each subsequent entry
|
|
361
|
+
tmpArgumentValues.push(this.getValueAtAddress(tmpRootObject, tmpFunctionArguments[i]));
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return this.getValueAtAddress(pObject[tmpFunctionAddress].apply(pObject, tmpArgumentValues), tmpNewAddress, tmpParentAddress, tmpRootObject);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
241
367
|
// Boxed elements look like this:
|
|
242
368
|
// MyValues[42]
|
|
243
369
|
// MyValues['Color']
|
|
@@ -247,7 +373,7 @@ class ManyfestObjectAddressResolverGetValue
|
|
|
247
373
|
// When we are passed SomeObject["Name"] this code below recurses as if it were SomeObject.Name
|
|
248
374
|
// The requirements to detect a boxed element are:
|
|
249
375
|
// 1) The start bracket is after character 0
|
|
250
|
-
if ((tmpBracketStartIndex > 0)
|
|
376
|
+
else if ((tmpBracketStartIndex > 0)
|
|
251
377
|
// 2) The end bracket has something between them
|
|
252
378
|
&& (tmpBracketStopIndex > tmpBracketStartIndex)
|
|
253
379
|
// 3) There is data
|