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.
- package/README.md +91 -260
- package/docs/.nojekyll +0 -0
- package/docs/README.md +108 -0
- package/docs/_sidebar.md +17 -0
- package/docs/address-notation.md +244 -0
- package/docs/cover.md +11 -0
- package/docs/hash-translation.md +202 -0
- package/docs/index.html +51 -0
- package/docs/quickstart.md +203 -0
- package/docs/reading.md +339 -0
- package/docs/schema-manipulation.md +186 -0
- package/docs/schema.md +319 -0
- package/docs/validating.md +344 -0
- package/docs/writing.md +300 -0
- package/package.json +1 -1
- package/source/Manyfest-ObjectAddress-CheckAddressExists.js +3 -4
- package/source/Manyfest-ObjectAddress-DeleteValue.js +7 -5
- package/source/Manyfest-ObjectAddress-GetValue.js +2 -6
- package/source/Manyfest-ObjectAddress-Parser.js +3 -3
- package/source/Manyfest-ObjectAddress-SetValue.js +7 -4
- package/source/Manyfest-ParseConditionals.js +0 -13
- package/source/Manyfest.js +28 -15
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# Quickstart
|
|
2
|
+
|
|
3
|
+
Get up and running with manyfest in under five minutes. This guide covers installation, basic schema definition, and the most common operations.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install manyfest
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Your First Manifest
|
|
12
|
+
|
|
13
|
+
A manifest describes the shape of your data. Create one by passing a scope and a set of descriptors:
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
const libManyfest = require('manyfest');
|
|
17
|
+
|
|
18
|
+
const userManifest = new libManyfest({
|
|
19
|
+
Scope: 'User',
|
|
20
|
+
Descriptors: {
|
|
21
|
+
'Name': { DataType: 'String', Required: true },
|
|
22
|
+
'Email': { DataType: 'String', Required: true },
|
|
23
|
+
'Profile.Age': { DataType: 'Integer' },
|
|
24
|
+
'Profile.Bio': { DataType: 'String', Default: '' }
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The `Scope` is just a label for logging. Each key in `Descriptors` is an address -- a dot-notation path into your objects.
|
|
30
|
+
|
|
31
|
+
## Reading Values
|
|
32
|
+
|
|
33
|
+
Read from nested objects safely, without worrying about missing intermediate properties:
|
|
34
|
+
|
|
35
|
+
```javascript
|
|
36
|
+
const user = {
|
|
37
|
+
Name: 'Alice',
|
|
38
|
+
Email: 'alice@example.com',
|
|
39
|
+
Profile: { Age: 30, Bio: 'Engineer' }
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
userManifest.getValueAtAddress(user, 'Profile.Age'); // 30
|
|
43
|
+
userManifest.getValueAtAddress(user, 'Profile.Bio'); // 'Engineer'
|
|
44
|
+
userManifest.getValueAtAddress(user, 'Profile.Phone'); // undefined (no error!)
|
|
45
|
+
|
|
46
|
+
// Read from an empty object -- returns the default if one is defined
|
|
47
|
+
userManifest.getValueAtAddress({}, 'Profile.Bio'); // '' (the Default)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Writing Values
|
|
51
|
+
|
|
52
|
+
Write to any depth and manyfest creates the structure for you:
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
const newUser = {};
|
|
56
|
+
|
|
57
|
+
userManifest.setValueAtAddress(newUser, 'Name', 'Bob');
|
|
58
|
+
userManifest.setValueAtAddress(newUser, 'Email', 'bob@example.com');
|
|
59
|
+
userManifest.setValueAtAddress(newUser, 'Profile.Age', 25);
|
|
60
|
+
userManifest.setValueAtAddress(newUser, 'Profile.Bio', 'Designer');
|
|
61
|
+
|
|
62
|
+
console.log(newUser);
|
|
63
|
+
// {
|
|
64
|
+
// Name: 'Bob',
|
|
65
|
+
// Email: 'bob@example.com',
|
|
66
|
+
// Profile: { Age: 25, Bio: 'Designer' }
|
|
67
|
+
// }
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
No need to manually create `newUser.Profile = {}` first.
|
|
71
|
+
|
|
72
|
+
## Validating Objects
|
|
73
|
+
|
|
74
|
+
Check an object against its schema:
|
|
75
|
+
|
|
76
|
+
```javascript
|
|
77
|
+
const result = userManifest.validate({ Name: 'Carol' });
|
|
78
|
+
|
|
79
|
+
console.log(result);
|
|
80
|
+
// {
|
|
81
|
+
// Error: true,
|
|
82
|
+
// Errors: [
|
|
83
|
+
// 'Element at address "Email" is flagged REQUIRED but is not set in the object.'
|
|
84
|
+
// ],
|
|
85
|
+
// MissingElements: ['Email', 'Profile.Age', 'Profile.Bio']
|
|
86
|
+
// }
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Validation never throws. Missing required elements produce entries in `Errors`. All missing elements (required or not) appear in `MissingElements`.
|
|
90
|
+
|
|
91
|
+
## Hash Shortcuts
|
|
92
|
+
|
|
93
|
+
Give an element a short hash to avoid typing long addresses:
|
|
94
|
+
|
|
95
|
+
```javascript
|
|
96
|
+
const manifest = new libManyfest({
|
|
97
|
+
Scope: 'Config',
|
|
98
|
+
Descriptors: {
|
|
99
|
+
'Database.Connection.Host': { Hash: 'DBHost', DataType: 'String', Default: 'localhost' },
|
|
100
|
+
'Database.Connection.Port': { Hash: 'DBPort', DataType: 'Integer', Default: 5432 }
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const config = {
|
|
105
|
+
Database: { Connection: { Host: 'db.example.com', Port: 3306 } }
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
manifest.getValueByHash(config, 'DBHost'); // 'db.example.com'
|
|
109
|
+
manifest.getValueByHash(config, 'DBPort'); // 3306
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Populating Defaults
|
|
113
|
+
|
|
114
|
+
Fill in missing values from your schema:
|
|
115
|
+
|
|
116
|
+
```javascript
|
|
117
|
+
const record = { Name: 'Alice', Email: 'alice@example.com' };
|
|
118
|
+
|
|
119
|
+
userManifest.populateDefaults(record);
|
|
120
|
+
// record is now:
|
|
121
|
+
// {
|
|
122
|
+
// Name: 'Alice',
|
|
123
|
+
// Email: 'alice@example.com',
|
|
124
|
+
// Profile: { Bio: '' }
|
|
125
|
+
// }
|
|
126
|
+
// Only 'Profile.Bio' was added because it has a Default defined.
|
|
127
|
+
// Existing values were not overwritten.
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Without a Schema
|
|
131
|
+
|
|
132
|
+
Manyfest works perfectly well without a pre-defined schema. Create an empty instance and use it purely for safe object navigation:
|
|
133
|
+
|
|
134
|
+
```javascript
|
|
135
|
+
const manifest = new libManyfest();
|
|
136
|
+
|
|
137
|
+
const data = { deeply: { nested: { value: 42 } } };
|
|
138
|
+
|
|
139
|
+
manifest.getValueAtAddress(data, 'deeply.nested.value'); // 42
|
|
140
|
+
manifest.getValueAtAddress(data, 'deeply.missing.value'); // undefined
|
|
141
|
+
|
|
142
|
+
manifest.setValueAtAddress(data, 'deeply.new.path', 'hello');
|
|
143
|
+
// data.deeply.new.path is now 'hello'
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Array Access
|
|
147
|
+
|
|
148
|
+
Access array elements with bracket notation:
|
|
149
|
+
|
|
150
|
+
```javascript
|
|
151
|
+
const manifest = new libManyfest();
|
|
152
|
+
|
|
153
|
+
const data = {
|
|
154
|
+
users: [
|
|
155
|
+
{ name: 'Alice', role: 'admin' },
|
|
156
|
+
{ name: 'Bob', role: 'user' }
|
|
157
|
+
]
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
manifest.getValueAtAddress(data, 'users[0].name'); // 'Alice'
|
|
161
|
+
manifest.getValueAtAddress(data, 'users[1].role'); // 'user'
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Building Schemas Programmatically
|
|
165
|
+
|
|
166
|
+
Add descriptors one at a time if you don't have the full schema up front:
|
|
167
|
+
|
|
168
|
+
```javascript
|
|
169
|
+
const manifest = new libManyfest();
|
|
170
|
+
manifest.scope = 'Order';
|
|
171
|
+
|
|
172
|
+
manifest.addDescriptor('OrderID', { DataType: 'Integer', Required: true });
|
|
173
|
+
manifest.addDescriptor('Customer.Name', { DataType: 'String', Required: true });
|
|
174
|
+
manifest.addDescriptor('Customer.Email', { DataType: 'String' });
|
|
175
|
+
manifest.addDescriptor('Total', { DataType: 'Float', Default: 0.0 });
|
|
176
|
+
|
|
177
|
+
// Now use it just like a pre-defined manifest
|
|
178
|
+
const order = manifest.populateDefaults({});
|
|
179
|
+
// { Total: 0 }
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Serialization
|
|
183
|
+
|
|
184
|
+
Save and restore manifests:
|
|
185
|
+
|
|
186
|
+
```javascript
|
|
187
|
+
// Serialize to JSON string
|
|
188
|
+
const saved = userManifest.serialize();
|
|
189
|
+
|
|
190
|
+
// Deserialize later
|
|
191
|
+
const restored = new libManyfest();
|
|
192
|
+
restored.deserialize(saved);
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Next Steps
|
|
196
|
+
|
|
197
|
+
- [Reading Values](reading.md) -- full guide to address notation, defaults, array access, boxed properties, back-navigation and more
|
|
198
|
+
- [Writing Values](writing.md) -- setting values, populating defaults, deleting values
|
|
199
|
+
- [Validating Objects](validating.md) -- required fields, strict mode, data type checking
|
|
200
|
+
- [Schema Definition](schema.md) -- descriptors, data types, scope, and the full descriptor object
|
|
201
|
+
- [Address Notation](address-notation.md) -- the complete address syntax reference
|
|
202
|
+
- [Hash Translation](hash-translation.md) -- reusing schemas with different hash mappings
|
|
203
|
+
- [Schema Manipulation](schema-manipulation.md) -- remapping and merging schemas
|
package/docs/reading.md
ADDED
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
# Reading Values from Objects
|
|
2
|
+
|
|
3
|
+
Manyfest provides safe, flexible access to values within complex object structures using dot-notation address paths. No more chaining `&&` checks or catching exceptions from deeply nested property access.
|
|
4
|
+
|
|
5
|
+
## Access
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
const libManyfest = require('manyfest');
|
|
9
|
+
|
|
10
|
+
// Create a manifest (schema optional for read 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', Default: 'none' }
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Core Concepts
|
|
24
|
+
|
|
25
|
+
### Address Notation
|
|
26
|
+
|
|
27
|
+
Addresses use dot-separated paths to navigate nested objects:
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
const data = {
|
|
31
|
+
user: {
|
|
32
|
+
profile: {
|
|
33
|
+
name: 'Alice',
|
|
34
|
+
scores: [95, 88, 72]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
manifest.getValueAtAddress(data, 'user.profile.name'); // 'Alice'
|
|
40
|
+
manifest.getValueAtAddress(data, 'user.profile.scores'); // [95, 88, 72]
|
|
41
|
+
manifest.getValueAtAddress(data, 'user.profile.scores[1]'); // 88
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Paths are case-sensitive and follow the exact structure of the object.
|
|
45
|
+
|
|
46
|
+
## Getting Values
|
|
47
|
+
|
|
48
|
+
### getValueAtAddress
|
|
49
|
+
|
|
50
|
+
Resolve a value at any depth using a dot-notation address:
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
const data = { a: { b: { c: 'deep value' } } };
|
|
54
|
+
|
|
55
|
+
manifest.getValueAtAddress(data, 'a.b.c'); // 'deep value'
|
|
56
|
+
manifest.getValueAtAddress(data, 'a.b'); // { c: 'deep value' }
|
|
57
|
+
manifest.getValueAtAddress(data, 'a'); // { b: { c: 'deep value' } }
|
|
58
|
+
manifest.getValueAtAddress(data, 'x.y.z'); // undefined
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
When a descriptor exists for the address and defines a `Default` value, the default is returned instead of `undefined`:
|
|
62
|
+
|
|
63
|
+
```javascript
|
|
64
|
+
const manifest = new libManyfest({
|
|
65
|
+
Scope: 'Config',
|
|
66
|
+
Descriptors: {
|
|
67
|
+
'Theme': { DataType: 'String', Default: 'light' }
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
manifest.getValueAtAddress({}, 'Theme'); // 'light'
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### getValueByHash
|
|
75
|
+
|
|
76
|
+
Retrieve a value using a hash rather than a direct address. When descriptors define hash-to-address mappings, this lets you use friendly short names:
|
|
77
|
+
|
|
78
|
+
```javascript
|
|
79
|
+
const manifest = new libManyfest({
|
|
80
|
+
Scope: 'Animal',
|
|
81
|
+
Descriptors: {
|
|
82
|
+
'MedicalStats.Temps.CET': { Hash: 'ComfET', DataType: 'Float' },
|
|
83
|
+
'MedicalStats.Temps.MaxET': { Hash: 'MaxET', DataType: 'Float' }
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const animal = {
|
|
88
|
+
MedicalStats: {
|
|
89
|
+
Temps: { CET: 98.6, MaxET: 104.2 }
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
manifest.getValueByHash(animal, 'ComfET'); // 98.6
|
|
94
|
+
manifest.getValueByHash(animal, 'MaxET'); // 104.2
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
If the hash is not found in the descriptor table, manyfest treats it as a direct address and attempts resolution that way. This means `getValueByHash` works even without a schema defined.
|
|
98
|
+
|
|
99
|
+
### checkAddressExists
|
|
100
|
+
|
|
101
|
+
Check whether a value exists at an address without retrieving it:
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
const data = { a: { b: 'value' } };
|
|
105
|
+
|
|
106
|
+
manifest.checkAddressExists(data, 'a.b'); // true
|
|
107
|
+
manifest.checkAddressExists(data, 'a.c'); // false
|
|
108
|
+
manifest.checkAddressExists(data, 'x.y.z'); // false
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### checkAddressExistsByHash
|
|
112
|
+
|
|
113
|
+
The hash-based equivalent:
|
|
114
|
+
|
|
115
|
+
```javascript
|
|
116
|
+
manifest.checkAddressExistsByHash(data, 'ComfET'); // true or false
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Array Access
|
|
120
|
+
|
|
121
|
+
Access array elements with bracket notation:
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
const data = {
|
|
125
|
+
students: [
|
|
126
|
+
{ name: 'Alice', grade: 95 },
|
|
127
|
+
{ name: 'Bob', grade: 88 },
|
|
128
|
+
{ name: 'Carol', grade: 72 }
|
|
129
|
+
]
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
manifest.getValueAtAddress(data, 'students[0]'); // { name: 'Alice', grade: 95 }
|
|
133
|
+
manifest.getValueAtAddress(data, 'students[1].name'); // 'Bob'
|
|
134
|
+
manifest.getValueAtAddress(data, 'students[2].grade'); // 72
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Set Access
|
|
138
|
+
|
|
139
|
+
Empty brackets return the full array, optionally filtered:
|
|
140
|
+
|
|
141
|
+
```javascript
|
|
142
|
+
manifest.getValueAtAddress(data, 'students[]');
|
|
143
|
+
// Returns all student objects
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Boxed Properties
|
|
147
|
+
|
|
148
|
+
Properties with special characters in their keys (dots, spaces, dashes) can be accessed using bracket notation with quotes:
|
|
149
|
+
|
|
150
|
+
```javascript
|
|
151
|
+
const data = {
|
|
152
|
+
'my-special-key': 'value1',
|
|
153
|
+
'another key': 'value2',
|
|
154
|
+
nested: {
|
|
155
|
+
'some.dotted.key': 'value3'
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
manifest.getValueAtAddress(data, '["my-special-key"]'); // 'value1'
|
|
160
|
+
manifest.getValueAtAddress(data, "['another key']"); // 'value2'
|
|
161
|
+
manifest.getValueAtAddress(data, 'nested["some.dotted.key"]'); // 'value3'
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Single quotes, double quotes and backticks are all supported inside brackets.
|
|
165
|
+
|
|
166
|
+
## Back-Navigation
|
|
167
|
+
|
|
168
|
+
Navigate backward through the object hierarchy using `..` sequences:
|
|
169
|
+
|
|
170
|
+
```javascript
|
|
171
|
+
const data = {
|
|
172
|
+
Bundle: {
|
|
173
|
+
Contract: {
|
|
174
|
+
IDContract: 500,
|
|
175
|
+
Project: {
|
|
176
|
+
IDProject: 42
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
// From IDContract, go back up and into Project
|
|
183
|
+
manifest.getValueAtAddress(data, 'Bundle.Contract.IDContract...Project.IDProject');
|
|
184
|
+
// Navigates: IDContract -> back to Contract -> back to Bundle -> Project.IDProject
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Each `.` in the `..` sequence navigates one level up from the current position.
|
|
188
|
+
|
|
189
|
+
## Object Set Access
|
|
190
|
+
|
|
191
|
+
Access properties across all keys of an object using `{}`:
|
|
192
|
+
|
|
193
|
+
```javascript
|
|
194
|
+
const data = {
|
|
195
|
+
departments: {
|
|
196
|
+
engineering: { budget: 50000 },
|
|
197
|
+
marketing: { budget: 30000 },
|
|
198
|
+
sales: { budget: 40000 }
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
manifest.getValueAtAddress(data, 'departments{}.budget');
|
|
203
|
+
// Returns: { 'departments.engineering.budget': 50000, 'departments.marketing.budget': 30000, 'departments.sales.budget': 40000 }
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Function Resolution
|
|
207
|
+
|
|
208
|
+
Address paths can include function calls on the object:
|
|
209
|
+
|
|
210
|
+
```javascript
|
|
211
|
+
const data = {
|
|
212
|
+
items: [3, 1, 4, 1, 5],
|
|
213
|
+
getTotal: function() { return this.items.reduce((a, b) => a + b, 0); }
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
manifest.getValueAtAddress(data, 'getTotal()'); // 14
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Functions can also receive arguments resolved from addresses:
|
|
220
|
+
|
|
221
|
+
```javascript
|
|
222
|
+
const data = {
|
|
223
|
+
multiplier: 10,
|
|
224
|
+
scale: function(value) { return value * this.multiplier; },
|
|
225
|
+
baseValue: 5
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
manifest.getValueAtAddress(data, 'scale(baseValue)'); // 50
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Default Values
|
|
232
|
+
|
|
233
|
+
When a descriptor includes a `Default` property, that value is returned if the address resolves to `undefined`:
|
|
234
|
+
|
|
235
|
+
```javascript
|
|
236
|
+
const manifest = new libManyfest({
|
|
237
|
+
Scope: 'Settings',
|
|
238
|
+
Descriptors: {
|
|
239
|
+
'Theme': { DataType: 'String', Default: 'dark' },
|
|
240
|
+
'FontSize': { DataType: 'Integer', Default: 14 },
|
|
241
|
+
'Language': { DataType: 'String', Default: 'en' }
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
const settings = { Theme: 'light' };
|
|
246
|
+
|
|
247
|
+
manifest.getValueAtAddress(settings, 'Theme'); // 'light' (exists in object)
|
|
248
|
+
manifest.getValueAtAddress(settings, 'FontSize'); // 14 (default)
|
|
249
|
+
manifest.getValueAtAddress(settings, 'Language'); // 'en' (default)
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
When no explicit `Default` is defined but a `DataType` is set, the type's built-in default is used:
|
|
253
|
+
|
|
254
|
+
| DataType | Default Value |
|
|
255
|
+
|----------|--------------|
|
|
256
|
+
| String | `""` |
|
|
257
|
+
| Number | `0` |
|
|
258
|
+
| Integer | `0` |
|
|
259
|
+
| Float | `0.0` |
|
|
260
|
+
| PreciseNumber | `"0.0"` |
|
|
261
|
+
| Boolean | `false` |
|
|
262
|
+
| Binary | `0` |
|
|
263
|
+
| DateTime | `0` |
|
|
264
|
+
| Array | `[]` |
|
|
265
|
+
| Object | `{}` |
|
|
266
|
+
| Null | `null` |
|
|
267
|
+
|
|
268
|
+
## Use Cases
|
|
269
|
+
|
|
270
|
+
### Safe Deep Property Access
|
|
271
|
+
|
|
272
|
+
```javascript
|
|
273
|
+
function getUserCity(userData) {
|
|
274
|
+
const manifest = new libManyfest();
|
|
275
|
+
return manifest.getValueAtAddress(userData, 'profile.address.city');
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// No error even if profile or address is missing
|
|
279
|
+
getUserCity({}); // undefined
|
|
280
|
+
getUserCity({ profile: { address: { city: 'Portland' } } }); // 'Portland'
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Configuration with Fallbacks
|
|
284
|
+
|
|
285
|
+
```javascript
|
|
286
|
+
const configManifest = new libManyfest({
|
|
287
|
+
Scope: 'AppConfig',
|
|
288
|
+
Descriptors: {
|
|
289
|
+
'Server.Port': { DataType: 'Integer', Default: 8080 },
|
|
290
|
+
'Server.Host': { DataType: 'String', Default: 'localhost' },
|
|
291
|
+
'Database.ConnectionString': { DataType: 'String', Default: 'mongodb://localhost/app' }
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
function getConfig(config, key) {
|
|
296
|
+
return configManifest.getValueByHash(config, key);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const config = { Server: { Port: 3000 } };
|
|
300
|
+
getConfig(config, 'Server.Port'); // 3000
|
|
301
|
+
getConfig(config, 'Server.Host'); // 'localhost'
|
|
302
|
+
getConfig(config, 'Database.ConnectionString'); // 'mongodb://localhost/app'
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Data Extraction with Hash Mapping
|
|
306
|
+
|
|
307
|
+
```javascript
|
|
308
|
+
const apiManifest = new libManyfest({
|
|
309
|
+
Scope: 'APIResponse',
|
|
310
|
+
Descriptors: {
|
|
311
|
+
'data.user.display_name': { Hash: 'UserName', DataType: 'String' },
|
|
312
|
+
'data.user.contact.primary_email': { Hash: 'Email', DataType: 'String' },
|
|
313
|
+
'data.metadata.created_at': { Hash: 'Created', DataType: 'DateTime' }
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
const response = {
|
|
318
|
+
data: {
|
|
319
|
+
user: {
|
|
320
|
+
display_name: 'Alice',
|
|
321
|
+
contact: { primary_email: 'alice@example.com' }
|
|
322
|
+
},
|
|
323
|
+
metadata: { created_at: '2024-01-15' }
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
apiManifest.getValueByHash(response, 'UserName'); // 'Alice'
|
|
328
|
+
apiManifest.getValueByHash(response, 'Email'); // 'alice@example.com'
|
|
329
|
+
apiManifest.getValueByHash(response, 'Created'); // '2024-01-15'
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
## Notes
|
|
333
|
+
|
|
334
|
+
- Address paths are case-sensitive
|
|
335
|
+
- Accessing a non-existent path returns `undefined` (no exceptions thrown)
|
|
336
|
+
- Array indices are zero-based
|
|
337
|
+
- `getValueByHash` falls back to treating the hash as a direct address if no mapping is found
|
|
338
|
+
- Back-navigation (`..`) resolves relative to the root object
|
|
339
|
+
- Functions in address paths are called with `apply`, bound to their containing object
|