manyfest 1.0.43 → 1.0.44

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.
@@ -0,0 +1,344 @@
1
+ # Validating Objects
2
+
3
+ Manyfest validates objects against their schema definitions, checking for required elements, data type conformance, and missing properties. Validation never throws exceptions; results come back as well-formed JSON.
4
+
5
+ ## Access
6
+
7
+ ```javascript
8
+ const libManyfest = require('manyfest');
9
+
10
+ // Validation requires a schema with descriptors
11
+ const manifest = new libManyfest({
12
+ Scope: 'Animal',
13
+ Descriptors: {
14
+ 'IDAnimal': { Name: 'Database ID', DataType: 'Integer', Default: 0 },
15
+ 'Name': { Description: 'The animal species name.' },
16
+ 'Type': { Description: 'Whether the animal is wild, domesticated, etc.' }
17
+ }
18
+ });
19
+ ```
20
+
21
+ ## Core Concepts
22
+
23
+ ### Validation Results
24
+
25
+ The `validate` method returns a result object with three properties:
26
+
27
+ ```javascript
28
+ {
29
+ Error: null, // null when valid, true when errors exist
30
+ Errors: [], // Array of human-readable error message strings
31
+ MissingElements: [] // Array of addresses for elements not found in the object
32
+ }
33
+ ```
34
+
35
+ A clean validation looks like this:
36
+
37
+ ```javascript
38
+ const result = manifest.validate({ IDAnimal: 42, Name: 'Rabbit', Type: 'Wild' });
39
+ // { Error: null, Errors: [], MissingElements: [] }
40
+ ```
41
+
42
+ ## Validating an Object
43
+
44
+ ### validate
45
+
46
+ Pass an object to check it against the schema:
47
+
48
+ ```javascript
49
+ const manifest = new libManyfest({
50
+ Scope: 'Animal',
51
+ Descriptors: {
52
+ 'IDAnimal': { DataType: 'Integer', Required: true },
53
+ 'Name': { DataType: 'String' },
54
+ 'Weight': { DataType: 'Float' }
55
+ }
56
+ });
57
+
58
+ const animal = { IDAnimal: 8675309, Name: 'BatBrains', Weight: 2.5 };
59
+ const result = manifest.validate(animal);
60
+ // { Error: null, Errors: [], MissingElements: [] }
61
+ ```
62
+
63
+ ### Non-Object Input
64
+
65
+ Passing a non-object produces an immediate error:
66
+
67
+ ```javascript
68
+ const result = manifest.validate('not an object');
69
+ // { Error: true, Errors: ['Expected passed in object to be type object but was passed in string'], MissingElements: [] }
70
+ ```
71
+
72
+ ## Required Elements
73
+
74
+ Mark a descriptor as `Required: true` to produce an error when that property is missing:
75
+
76
+ ```javascript
77
+ const manifest = new libManyfest({
78
+ Scope: 'User',
79
+ Descriptors: {
80
+ 'Email': { DataType: 'String', Required: true },
81
+ 'Name': { DataType: 'String', Required: true },
82
+ 'Bio': { DataType: 'String' }
83
+ }
84
+ });
85
+
86
+ const user = { Email: 'alice@example.com' };
87
+ const result = manifest.validate(user);
88
+ // {
89
+ // Error: true,
90
+ // Errors: ['Element at address "Name" is flagged REQUIRED but is not set in the object.'],
91
+ // MissingElements: ['Name', 'Bio']
92
+ // }
93
+ ```
94
+
95
+ Note that `Bio` appears in `MissingElements` but not in `Errors` because it is not required.
96
+
97
+ ## Strict Mode
98
+
99
+ When `strict` is enabled, every described element that is missing from the object becomes an error, regardless of the `Required` flag:
100
+
101
+ ```javascript
102
+ const manifest = new libManyfest({
103
+ Scope: 'Config',
104
+ strict: true,
105
+ Descriptors: {
106
+ 'Host': { DataType: 'String' },
107
+ 'Port': { DataType: 'Integer' },
108
+ 'Debug': { DataType: 'Boolean' }
109
+ }
110
+ });
111
+
112
+ const config = { Host: 'localhost' };
113
+ const result = manifest.validate(config);
114
+ // {
115
+ // Error: true,
116
+ // Errors: [
117
+ // 'Element at address "Port" is flagged REQUIRED but is not set in the object.',
118
+ // 'Element at address "Debug" is flagged REQUIRED but is not set in the object.'
119
+ // ],
120
+ // MissingElements: ['Port', 'Debug']
121
+ // }
122
+ ```
123
+
124
+ ## Data Type Checking
125
+
126
+ When a descriptor specifies a `DataType`, the value is checked for type conformance.
127
+
128
+ ### Supported Types
129
+
130
+ | DataType | Expected JavaScript Type | Notes |
131
+ |----------|------------------------|-------|
132
+ | String | `string` | |
133
+ | Number | `number` | Any numeric value |
134
+ | Integer | `number` | Must not contain a decimal point |
135
+ | Float | `number` | Any numeric value |
136
+ | PreciseNumber | `string` | A string that parses as a valid number |
137
+ | DateTime | any | Must be parsable by `new Date()` |
138
+
139
+ ### Type Validation Examples
140
+
141
+ ```javascript
142
+ const manifest = new libManyfest({
143
+ Scope: 'Record',
144
+ Descriptors: {
145
+ 'Name': { DataType: 'String' },
146
+ 'Count': { DataType: 'Integer' },
147
+ 'Price': { DataType: 'Float' },
148
+ 'Precision': { DataType: 'PreciseNumber' },
149
+ 'Created': { DataType: 'DateTime' }
150
+ }
151
+ });
152
+ ```
153
+
154
+ **Valid object:**
155
+
156
+ ```javascript
157
+ manifest.validate({
158
+ Name: 'Widget',
159
+ Count: 10,
160
+ Price: 19.99,
161
+ Precision: '19.9900',
162
+ Created: '2024-01-15T10:30:00Z'
163
+ });
164
+ // { Error: null, Errors: [], MissingElements: [] }
165
+ ```
166
+
167
+ **Type mismatches:**
168
+
169
+ ```javascript
170
+ manifest.validate({
171
+ Name: 42,
172
+ Count: 10.5,
173
+ Price: 'free',
174
+ Precision: 19.99,
175
+ Created: 'not a date'
176
+ });
177
+ // Errors include:
178
+ // 'Element at address "Name" has a DataType String but is of the type number.'
179
+ // 'Element at address "Count" has a DataType Integer but has a decimal point in the number.'
180
+ // 'Element at address "Price" has a DataType Float but is of the type string.'
181
+ // 'Element at address "Precision" has a DataType PreciseNumber but is of the type number.'
182
+ // 'Element at address "Created" has a DataType DateTime but is not parsable as a Date by Javascript.'
183
+ ```
184
+
185
+ ### Integer vs Float
186
+
187
+ Both `Integer` and `Float` require a JavaScript `number` type. The distinction is that `Integer` additionally checks that the value does not contain a decimal point:
188
+
189
+ ```javascript
190
+ const manifest = new libManyfest({
191
+ Scope: 'Test',
192
+ Descriptors: {
193
+ 'WholeNumber': { DataType: 'Integer' },
194
+ 'Decimal': { DataType: 'Float' }
195
+ }
196
+ });
197
+
198
+ manifest.validate({ WholeNumber: 10, Decimal: 3.14 });
199
+ // No errors
200
+
201
+ manifest.validate({ WholeNumber: 10.5, Decimal: 3.14 });
202
+ // Error: 'Element at address "WholeNumber" has a DataType Integer but has a decimal point in the number.'
203
+ ```
204
+
205
+ ### PreciseNumber
206
+
207
+ The `PreciseNumber` type is for numeric values stored as strings to preserve precision (useful for financial calculations). Validation checks that the value is a `string` that matches a valid number pattern:
208
+
209
+ ```javascript
210
+ const manifest = new libManyfest({
211
+ Scope: 'Financial',
212
+ Descriptors: {
213
+ 'Balance': { DataType: 'PreciseNumber' }
214
+ }
215
+ });
216
+
217
+ manifest.validate({ Balance: '1234567890.12' }); // Valid
218
+ manifest.validate({ Balance: 'not a number' }); // Error: not a valid number
219
+ manifest.validate({ Balance: 1234.56 }); // Error: expects string type
220
+ ```
221
+
222
+ ### Unrecognized Data Types
223
+
224
+ If a `DataType` is specified but not recognized, it defaults to `String` checking:
225
+
226
+ ```javascript
227
+ const manifest = new libManyfest({
228
+ Scope: 'Test',
229
+ Descriptors: {
230
+ 'Value': { DataType: 'CustomType' }
231
+ }
232
+ });
233
+
234
+ manifest.validate({ Value: 'hello' }); // Valid (treated as String)
235
+ manifest.validate({ Value: 42 }); // Error (expected string)
236
+ ```
237
+
238
+ ## Nested Object Validation
239
+
240
+ Descriptors with dot-notation addresses validate nested properties:
241
+
242
+ ```javascript
243
+ const manifest = new libManyfest({
244
+ Scope: 'User',
245
+ Descriptors: {
246
+ 'Profile.Name': { DataType: 'String', Required: true },
247
+ 'Profile.Age': { DataType: 'Integer' },
248
+ 'Contact.Email': { DataType: 'String', Required: true }
249
+ }
250
+ });
251
+
252
+ const user = {
253
+ Profile: { Name: 'Alice', Age: 30 },
254
+ Contact: { Email: 'alice@example.com' }
255
+ };
256
+
257
+ manifest.validate(user);
258
+ // { Error: null, Errors: [], MissingElements: [] }
259
+ ```
260
+
261
+ ## Use Cases
262
+
263
+ ### API Input Validation
264
+
265
+ ```javascript
266
+ const requestManifest = new libManyfest({
267
+ Scope: 'CreateUser',
268
+ Descriptors: {
269
+ 'email': { DataType: 'String', Required: true },
270
+ 'password': { DataType: 'String', Required: true },
271
+ 'profile.displayName': { DataType: 'String', Required: true },
272
+ 'profile.age': { DataType: 'Integer' }
273
+ }
274
+ });
275
+
276
+ function validateCreateUserRequest(requestBody) {
277
+ let result = requestManifest.validate(requestBody);
278
+ if (result.Error) {
279
+ return { valid: false, errors: result.Errors };
280
+ }
281
+ return { valid: true };
282
+ }
283
+ ```
284
+
285
+ ### Configuration Verification
286
+
287
+ ```javascript
288
+ const configManifest = new libManyfest({
289
+ Scope: 'AppConfig',
290
+ strict: true,
291
+ Descriptors: {
292
+ 'Database.Host': { DataType: 'String' },
293
+ 'Database.Port': { DataType: 'Integer' },
294
+ 'Database.Name': { DataType: 'String' },
295
+ 'Server.Port': { DataType: 'Integer' },
296
+ 'Server.LogLevel': { DataType: 'String' }
297
+ }
298
+ });
299
+
300
+ function verifyConfig(config) {
301
+ let result = configManifest.validate(config);
302
+ if (result.Error) {
303
+ console.error('Configuration errors:', result.Errors);
304
+ process.exit(1);
305
+ }
306
+ if (result.MissingElements.length > 0) {
307
+ console.warn('Optional config missing:', result.MissingElements);
308
+ }
309
+ }
310
+ ```
311
+
312
+ ### Schema Completeness Checks
313
+
314
+ Use `MissingElements` to identify which properties are absent, even when validation passes:
315
+
316
+ ```javascript
317
+ const manifest = new libManyfest({
318
+ Scope: 'Profile',
319
+ Descriptors: {
320
+ 'Name': { DataType: 'String', Required: true },
321
+ 'Bio': { DataType: 'String' },
322
+ 'Avatar': { DataType: 'String' },
323
+ 'Website': { DataType: 'String' }
324
+ }
325
+ });
326
+
327
+ const profile = { Name: 'Alice', Bio: 'Developer' };
328
+ const result = manifest.validate(profile);
329
+ // result.Error is null (no errors)
330
+ // result.MissingElements is ['Avatar', 'Website']
331
+
332
+ const completeness = 1 - (result.MissingElements.length / 4);
333
+ // 50% complete
334
+ ```
335
+
336
+ ## Notes
337
+
338
+ - Validation never throws exceptions; errors are returned as structured data
339
+ - `Error` is `null` when no errors exist, `true` when errors are present
340
+ - `MissingElements` tracks all absent schema elements, not just required ones
341
+ - In strict mode, every missing element is treated as an error
342
+ - Data type checking is case-insensitive (`"String"`, `"string"`, `"STRING"` all work)
343
+ - `undefined` values and non-existent properties are both treated as missing
344
+ - Unrecognized `DataType` values default to `String` validation
@@ -0,0 +1,300 @@
1
+ # Writing Values to Objects
2
+
3
+ Manyfest provides safe, address-based value assignment that automatically creates intermediate objects and arrays as needed. Write to any depth in an object without manually building the path.
4
+
5
+ ## Access
6
+
7
+ ```javascript
8
+ const libManyfest = require('manyfest');
9
+
10
+ // Create a manifest (schema optional for write operations)
11
+ const manifest = new libManyfest();
12
+
13
+ // Or with a schema definition
14
+ const manifest = new libManyfest({
15
+ Scope: 'User',
16
+ Descriptors: {
17
+ 'Name': { Hash: 'name', DataType: 'String' },
18
+ 'Profile.Email': { Hash: 'email', DataType: 'String' }
19
+ }
20
+ });
21
+ ```
22
+
23
+ ## Core Concepts
24
+
25
+ ### Automatic Structure Creation
26
+
27
+ When setting a value at a nested address, manyfest creates any intermediate objects that do not yet exist:
28
+
29
+ ```javascript
30
+ const data = {};
31
+
32
+ manifest.setValueAtAddress(data, 'user.profile.name', 'Alice');
33
+ // data is now: { user: { profile: { name: 'Alice' } } }
34
+ ```
35
+
36
+ No need to manually initialize `data.user` or `data.user.profile` first.
37
+
38
+ ## Setting Values
39
+
40
+ ### setValueAtAddress
41
+
42
+ Set a value at any depth using a dot-notation address:
43
+
44
+ ```javascript
45
+ const data = {};
46
+
47
+ manifest.setValueAtAddress(data, 'name', 'Alice');
48
+ // { name: 'Alice' }
49
+
50
+ manifest.setValueAtAddress(data, 'profile.age', 30);
51
+ // { name: 'Alice', profile: { age: 30 } }
52
+
53
+ manifest.setValueAtAddress(data, 'profile.address.city', 'Portland');
54
+ // { name: 'Alice', profile: { age: 30, address: { city: 'Portland' } } }
55
+ ```
56
+
57
+ Returns `true` if the value was set successfully, `false` otherwise.
58
+
59
+ ### setValueByHash
60
+
61
+ Set a value using a hash rather than a direct address. When descriptors define hash-to-address mappings, this lets you use friendly short names:
62
+
63
+ ```javascript
64
+ const manifest = new libManyfest({
65
+ Scope: 'Animal',
66
+ Descriptors: {
67
+ 'MedicalStats.Temps.CET': { Hash: 'ComfET', DataType: 'Float' },
68
+ 'MedicalStats.Temps.MaxET': { Hash: 'MaxET', DataType: 'Float' }
69
+ }
70
+ });
71
+
72
+ const animal = {};
73
+
74
+ manifest.setValueByHash(animal, 'ComfET', 98.6);
75
+ manifest.setValueByHash(animal, 'MaxET', 104.2);
76
+ // animal is now: { MedicalStats: { Temps: { CET: 98.6, MaxET: 104.2 } } }
77
+ ```
78
+
79
+ If the hash is not found in the descriptor table, manyfest treats it as a direct address and sets the value that way.
80
+
81
+ ### Overwriting Existing Values
82
+
83
+ Setting a value at an address that already contains data replaces it:
84
+
85
+ ```javascript
86
+ const data = { color: 'blue' };
87
+
88
+ manifest.setValueAtAddress(data, 'color', 'red');
89
+ // { color: 'red' }
90
+ ```
91
+
92
+ Nested values work the same way:
93
+
94
+ ```javascript
95
+ const data = { user: { name: 'Alice' } };
96
+
97
+ manifest.setValueAtAddress(data, 'user.name', 'Bob');
98
+ // { user: { name: 'Bob' } }
99
+ ```
100
+
101
+ ## Array Assignment
102
+
103
+ Set values at specific array indices using bracket notation:
104
+
105
+ ```javascript
106
+ const data = { items: [] };
107
+
108
+ manifest.setValueAtAddress(data, 'items[0]', 'first');
109
+ manifest.setValueAtAddress(data, 'items[1]', 'second');
110
+ manifest.setValueAtAddress(data, 'items[2]', 'third');
111
+ // data.items is ['first', 'second', 'third']
112
+ ```
113
+
114
+ Nested array elements work as expected:
115
+
116
+ ```javascript
117
+ const data = { users: [{ name: 'Alice' }, { name: 'Bob' }] };
118
+
119
+ manifest.setValueAtAddress(data, 'users[0].score', 95);
120
+ manifest.setValueAtAddress(data, 'users[1].score', 88);
121
+ // data.users is [{ name: 'Alice', score: 95 }, { name: 'Bob', score: 88 }]
122
+ ```
123
+
124
+ ## Boxed Properties
125
+
126
+ Write to properties with special characters in their keys using bracket notation with quotes:
127
+
128
+ ```javascript
129
+ const data = {};
130
+
131
+ manifest.setValueAtAddress(data, '["my-special-key"]', 'value1');
132
+ manifest.setValueAtAddress(data, 'nested["some.dotted.key"]', 'value2');
133
+ // data is: { 'my-special-key': 'value1', nested: { 'some.dotted.key': 'value2' } }
134
+ ```
135
+
136
+ ## Populating Defaults
137
+
138
+ ### populateDefaults
139
+
140
+ Fill in default values for any descriptor that defines a `Default` property, without overwriting existing data:
141
+
142
+ ```javascript
143
+ const manifest = new libManyfest({
144
+ Scope: 'Settings',
145
+ Descriptors: {
146
+ 'Theme': { DataType: 'String', Default: 'dark' },
147
+ 'FontSize': { DataType: 'Integer', Default: 14 },
148
+ 'Language': { DataType: 'String', Default: 'en' }
149
+ }
150
+ });
151
+
152
+ const settings = { Theme: 'light' };
153
+
154
+ manifest.populateDefaults(settings);
155
+ // settings is now: { Theme: 'light', FontSize: 14, Language: 'en' }
156
+ // Theme was not overwritten because it already existed
157
+ ```
158
+
159
+ Pass `true` as the second argument to overwrite existing properties:
160
+
161
+ ```javascript
162
+ manifest.populateDefaults(settings, true);
163
+ // settings is now: { Theme: 'dark', FontSize: 14, Language: 'en' }
164
+ // Theme was overwritten to its default
165
+ ```
166
+
167
+ ### populateObject
168
+
169
+ Populate all values based on the schema, using type defaults even when no explicit `Default` is defined:
170
+
171
+ ```javascript
172
+ const manifest = new libManyfest({
173
+ Scope: 'Record',
174
+ Descriptors: {
175
+ 'Name': { DataType: 'String' },
176
+ 'Count': { DataType: 'Integer' },
177
+ 'Active': { DataType: 'Boolean' },
178
+ 'Tags': { DataType: 'Array' }
179
+ }
180
+ });
181
+
182
+ const record = manifest.populateObject({});
183
+ // record is: { Name: '', Count: 0, Active: false, Tags: [] }
184
+ ```
185
+
186
+ A filter function can be passed to selectively populate:
187
+
188
+ ```javascript
189
+ const record = manifest.populateObject({}, false,
190
+ (pDescriptor) => { return pDescriptor.DataType === 'String'; }
191
+ );
192
+ // Only String-typed descriptors are populated
193
+ ```
194
+
195
+ ## Deleting Values
196
+
197
+ ### deleteValueAtAddress
198
+
199
+ Remove a value at an address:
200
+
201
+ ```javascript
202
+ const data = { user: { name: 'Alice', age: 30 } };
203
+
204
+ manifest.deleteValueAtAddress(data, 'user.age');
205
+ // data is now: { user: { name: 'Alice' } }
206
+ ```
207
+
208
+ ### deleteValueByHash
209
+
210
+ The hash-based equivalent:
211
+
212
+ ```javascript
213
+ manifest.deleteValueByHash(data, 'email');
214
+ ```
215
+
216
+ ## Use Cases
217
+
218
+ ### Building Objects from Flat Data
219
+
220
+ ```javascript
221
+ function buildUserFromForm(formFields) {
222
+ const manifest = new libManyfest();
223
+ const user = {};
224
+
225
+ for (let tmpField of formFields) {
226
+ manifest.setValueAtAddress(user, tmpField.path, tmpField.value);
227
+ }
228
+
229
+ return user;
230
+ }
231
+
232
+ const fields = [
233
+ { path: 'name.first', value: 'Alice' },
234
+ { path: 'name.last', value: 'Smith' },
235
+ { path: 'contact.email', value: 'alice@example.com' },
236
+ { path: 'contact.phone', value: '555-1234' }
237
+ ];
238
+
239
+ buildUserFromForm(fields);
240
+ // { name: { first: 'Alice', last: 'Smith' }, contact: { email: 'alice@example.com', phone: '555-1234' } }
241
+ ```
242
+
243
+ ### Data Transformation
244
+
245
+ ```javascript
246
+ function transformData(source, mappings) {
247
+ const manifest = new libManyfest();
248
+ const result = {};
249
+
250
+ for (let [targetPath, sourcePath] of Object.entries(mappings)) {
251
+ let value = manifest.getValueAtAddress(source, sourcePath);
252
+ if (value !== undefined) {
253
+ manifest.setValueAtAddress(result, targetPath, value);
254
+ }
255
+ }
256
+
257
+ return result;
258
+ }
259
+
260
+ const apiData = {
261
+ data: { user: { display_name: 'Alice', contact: { primary_email: 'alice@example.com' } } }
262
+ };
263
+
264
+ transformData(apiData, {
265
+ 'userName': 'data.user.display_name',
266
+ 'userEmail': 'data.user.contact.primary_email'
267
+ });
268
+ // { userName: 'Alice', userEmail: 'alice@example.com' }
269
+ ```
270
+
271
+ ### Initializing Records with Schema Defaults
272
+
273
+ ```javascript
274
+ const invoiceManifest = new libManyfest({
275
+ Scope: 'Invoice',
276
+ Descriptors: {
277
+ 'InvoiceNumber': { DataType: 'String', Default: '' },
278
+ 'Status': { DataType: 'String', Default: 'draft' },
279
+ 'LineItems': { DataType: 'Array', Default: [] },
280
+ 'Total': { DataType: 'Float', Default: 0.0 },
281
+ 'Metadata.CreatedBy': { DataType: 'String', Default: 'system' }
282
+ }
283
+ });
284
+
285
+ function createNewInvoice() {
286
+ return invoiceManifest.populateDefaults({});
287
+ }
288
+
289
+ createNewInvoice();
290
+ // { InvoiceNumber: '', Status: 'draft', LineItems: [], Total: 0, Metadata: { CreatedBy: 'system' } }
291
+ ```
292
+
293
+ ## Notes
294
+
295
+ - Non-existent intermediate objects are created automatically during write operations
296
+ - Setting a value at an address where an intermediate path resolves to a non-object (e.g. a string) will not overwrite that value
297
+ - Array indices use bracket notation: `items[0]`
298
+ - `populateDefaults` does not overwrite existing properties unless the second argument is `true`
299
+ - `populateObject` without a filter populates every descriptor in the schema
300
+ - Paths are case-sensitive
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "manyfest",
3
- "version": "1.0.43",
3
+ "version": "1.0.44",
4
4
  "description": "JSON Object Manifest for Data Description and Parsing",
5
5
  "main": "source/Manyfest.js",
6
6
  "scripts": {
@@ -244,7 +244,7 @@ class ManyfestObjectAddressResolverCheckAddressExists
244
244
  {
245
245
  let tmpArgumentValues = [];
246
246
 
247
- let tmpRootObject = (typeof(pRootObject) == 'undefined') ? pObject : pRootObject;
247
+
248
248
 
249
249
  // Now get the value for each argument
250
250
  for (let i = 0; i < tmpFunctionArguments.length; i++)
@@ -351,9 +351,8 @@ class ManyfestObjectAddressResolverCheckAddressExists
351
351
  }
352
352
  else
353
353
  {
354
- // Create a subobject and then pass that
355
- pObject[tmpSubObjectName] = {};
356
- return this.checkAddressExists(pObject[tmpSubObjectName], tmpNewAddress, tmpRootObject);
354
+ // The sub-object doesn't exist, so the address doesn't exist
355
+ return false;
357
356
  }
358
357
  }
359
358
  }
@@ -5,6 +5,8 @@ let libSimpleLog = require('./Manyfest-LogToConsole.js');
5
5
  let fCleanWrapCharacters = require('./Manyfest-CleanWrapCharacters.js');
6
6
  let fParseConditionals = require(`../source/Manyfest-ParseConditionals.js`)
7
7
 
8
+ let _MockFable = { DataFormat: require('./Manyfest-ObjectAddress-Parser.js') };
9
+
8
10
  /**
9
11
  * Object Address Resolver - DeleteValue
10
12
  *
@@ -74,11 +76,11 @@ class ManyfestObjectAddressResolverDeleteValue
74
76
  tmpParentAddress = pParentAddress;
75
77
  }
76
78
 
77
- // TODO: Make this work for things like SomeRootObject.Metadata["Some.People.Use.Bad.Object.Property.Names"]
78
- let tmpSeparatorIndex = pAddress.indexOf('.');
79
+ // Use enclosure-aware parser to find the first segment separator
80
+ let tmpAddressPartBeginning = _MockFable.DataFormat.stringGetFirstSegment(pAddress);
79
81
 
80
82
  // This is the terminal address string (no more dots so the RECUSION ENDS IN HERE somehow)
81
- if (tmpSeparatorIndex == -1)
83
+ if (tmpAddressPartBeginning.length == pAddress.length)
82
84
  {
83
85
  // Check if the address refers to a boxed property
84
86
  let tmpBracketStartIndex = pAddress.indexOf('[');
@@ -201,8 +203,8 @@ class ManyfestObjectAddressResolverDeleteValue
201
203
  }
202
204
  else
203
205
  {
204
- let tmpSubObjectName = pAddress.substring(0, tmpSeparatorIndex);
205
- let tmpNewAddress = pAddress.substring(tmpSeparatorIndex+1);
206
+ let tmpSubObjectName = tmpAddressPartBeginning;
207
+ let tmpNewAddress = pAddress.substring(tmpAddressPartBeginning.length+1);
206
208
 
207
209
  // BOXED ELEMENTS
208
210
  // Test if the tmpNewAddress is an array or object