manyfest 1.0.42 → 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.
Files changed (55) hide show
  1. package/README.md +91 -260
  2. package/dist/manyfest.compatible.js +279 -112
  3. package/dist/manyfest.compatible.js.map +1 -1
  4. package/dist/manyfest.compatible.min.js +1 -1
  5. package/dist/manyfest.compatible.min.js.map +1 -1
  6. package/dist/manyfest.js +280 -112
  7. package/dist/manyfest.js.map +1 -1
  8. package/dist/manyfest.min.js +1 -1
  9. package/dist/manyfest.min.js.map +1 -1
  10. package/docs/.nojekyll +0 -0
  11. package/docs/README.md +108 -0
  12. package/docs/_sidebar.md +17 -0
  13. package/docs/address-notation.md +244 -0
  14. package/docs/cover.md +11 -0
  15. package/docs/hash-translation.md +202 -0
  16. package/docs/index.html +51 -0
  17. package/docs/quickstart.md +203 -0
  18. package/docs/reading.md +339 -0
  19. package/docs/schema-manipulation.md +186 -0
  20. package/docs/schema.md +319 -0
  21. package/docs/validating.md +344 -0
  22. package/docs/writing.md +300 -0
  23. package/package.json +3 -3
  24. package/source/Manyfest-CleanWrapCharacters.js +7 -1
  25. package/source/Manyfest-HashTranslation.js +29 -8
  26. package/source/Manyfest-ObjectAddress-CheckAddressExists.js +31 -17
  27. package/source/Manyfest-ObjectAddress-DeleteValue.js +27 -7
  28. package/source/Manyfest-ObjectAddress-GetValue.js +25 -10
  29. package/source/Manyfest-ObjectAddress-Parser.js +42 -35
  30. package/source/Manyfest-ObjectAddress-SetValue.js +21 -6
  31. package/source/Manyfest-ObjectAddressGeneration.js +23 -12
  32. package/source/Manyfest-ParseConditionals.js +3 -16
  33. package/source/Manyfest-SchemaManipulation.js +44 -21
  34. package/source/Manyfest.js +72 -17
  35. package/test/Manyfest_Performance_tests.js +48 -0
  36. package/types/Manyfest-CleanWrapCharacters.d.ts +7 -1
  37. package/types/Manyfest-CleanWrapCharacters.d.ts.map +1 -1
  38. package/types/Manyfest-HashTranslation.d.ts +34 -7
  39. package/types/Manyfest-HashTranslation.d.ts.map +1 -1
  40. package/types/Manyfest-ObjectAddress-CheckAddressExists.d.ts +23 -4
  41. package/types/Manyfest-ObjectAddress-CheckAddressExists.d.ts.map +1 -1
  42. package/types/Manyfest-ObjectAddress-DeleteValue.d.ts +25 -6
  43. package/types/Manyfest-ObjectAddress-DeleteValue.d.ts.map +1 -1
  44. package/types/Manyfest-ObjectAddress-GetValue.d.ts +26 -6
  45. package/types/Manyfest-ObjectAddress-GetValue.d.ts.map +1 -1
  46. package/types/Manyfest-ObjectAddress-Parser.d.ts +5 -5
  47. package/types/Manyfest-ObjectAddress-Parser.d.ts.map +1 -1
  48. package/types/Manyfest-ObjectAddress-SetValue.d.ts +18 -5
  49. package/types/Manyfest-ObjectAddress-SetValue.d.ts.map +1 -1
  50. package/types/Manyfest-ObjectAddressGeneration.d.ts +25 -4
  51. package/types/Manyfest-ObjectAddressGeneration.d.ts.map +1 -1
  52. package/types/Manyfest-SchemaManipulation.d.ts +47 -6
  53. package/types/Manyfest-SchemaManipulation.d.ts.map +1 -1
  54. package/types/Manyfest.d.ts +35 -12
  55. package/types/Manyfest.d.ts.map +1 -1
package/docs/.nojekyll ADDED
File without changes
package/docs/README.md ADDED
@@ -0,0 +1,108 @@
1
+ # Manyfest
2
+
3
+ > JSON Object Manifest for Data Description and Parsing
4
+
5
+ Manyfest provides a simple pattern to describe, validate, manipulate and interpret data using address-based object navigation. It solves the problem of maintaining context as data crosses boundaries between persistence engines, APIs, and user interfaces.
6
+
7
+ ## Features
8
+
9
+ - **Safe Object Navigation** - Read and write deeply nested properties without exceptions
10
+ - **Schema Definitions** - Describe data elements with types, defaults, names and descriptions
11
+ - **Hash-Based Lookups** - Access complex paths through short, friendly hash identifiers
12
+ - **Validation** - Check objects against schemas for required fields and type conformance
13
+ - **Default Population** - Fill in missing values based on schema definitions
14
+ - **Auto-Structure Creation** - Writing to a nested path automatically creates intermediate objects
15
+ - **Browser & Node.js** - Works seamlessly in both environments
16
+
17
+ ## Quick Start
18
+
19
+ ```javascript
20
+ const libManyfest = require('manyfest');
21
+
22
+ // Define a schema
23
+ const manifest = new libManyfest({
24
+ Scope: 'User',
25
+ Descriptors: {
26
+ 'Name': { DataType: 'String', Required: true },
27
+ 'Email': { DataType: 'String', Required: true },
28
+ 'Profile.Age': { DataType: 'Integer' },
29
+ 'Profile.Bio': { DataType: 'String', Default: '' }
30
+ }
31
+ });
32
+
33
+ // Read safely from nested objects
34
+ const user = { Name: 'Alice', Profile: { Age: 30 } };
35
+ manifest.getValueAtAddress(user, 'Profile.Age'); // 30
36
+ manifest.getValueAtAddress(user, 'Profile.Phone'); // undefined (no error)
37
+
38
+ // Write to any depth -- intermediate objects are created for you
39
+ const newUser = {};
40
+ manifest.setValueAtAddress(newUser, 'Name', 'Bob');
41
+ manifest.setValueAtAddress(newUser, 'Profile.Age', 25);
42
+ // newUser is now: { Name: 'Bob', Profile: { Age: 25 } }
43
+
44
+ // Validate against the schema
45
+ const result = manifest.validate({ Name: 'Carol' });
46
+ // result.Error: true
47
+ // result.Errors: ['Element at address "Email" is flagged REQUIRED but is not set in the object.']
48
+ // result.MissingElements: ['Email', 'Profile.Age', 'Profile.Bio']
49
+ ```
50
+
51
+ ## Installation
52
+
53
+ ```bash
54
+ npm install manyfest
55
+ ```
56
+
57
+ ## How It Works
58
+
59
+ Manyfest uses **addresses** -- dot-notation paths -- to navigate objects:
60
+
61
+ ```javascript
62
+ manifest.getValueAtAddress(data, 'user.profile.name'); // Nested properties
63
+ manifest.getValueAtAddress(data, 'items[0].title'); // Array elements
64
+ manifest.getValueAtAddress(data, '["special-key"]'); // Boxed properties
65
+ manifest.getValueAtAddress(data, 'departments{}.budget'); // Object sets
66
+ ```
67
+
68
+ A **schema** maps these addresses to human-readable metadata:
69
+
70
+ ```javascript
71
+ const manifest = new libManyfest({
72
+ Scope: 'Archive.org',
73
+ Descriptors: {
74
+ 'd1': { Hash: 'Server', Name: 'Server', DataType: 'String' },
75
+ 'metadata.title': { Hash: 'Title', Name: 'Title', DataType: 'String' },
76
+ 'metadata.creator': { Hash: 'Creator', Name: 'Creator', DataType: 'String' }
77
+ }
78
+ });
79
+
80
+ // Now use friendly hashes instead of raw paths
81
+ manifest.getValueByHash(archiveData, 'Title'); // reads metadata.title
82
+ manifest.getValueByHash(archiveData, 'Creator'); // reads metadata.creator
83
+ ```
84
+
85
+ No schema required for basic usage -- manyfest works as a standalone safe-access utility:
86
+
87
+ ```javascript
88
+ const manifest = new libManyfest();
89
+ manifest.getValueAtAddress(anyObject, 'any.nested.path'); // Safe, returns undefined if missing
90
+ manifest.setValueAtAddress(anyObject, 'any.new.path', 42); // Creates structure automatically
91
+ ```
92
+
93
+ ## Documentation
94
+
95
+ - [Quickstart](quickstart.md) - Up and running in five minutes
96
+ - [Reading Values](reading.md) - Full guide to address-based reading
97
+ - [Writing Values](writing.md) - Setting, populating and deleting values
98
+ - [Validating Objects](validating.md) - Schema validation and type checking
99
+ - [Schema Definition](schema.md) - Descriptors, data types and serialization
100
+ - [Address Notation](address-notation.md) - The complete address syntax reference
101
+ - [Hash Translation](hash-translation.md) - Reusing schemas with different mappings
102
+ - [Schema Manipulation](schema-manipulation.md) - Remapping, merging and generating schemas
103
+
104
+ ## Related Packages
105
+
106
+ - [fable](https://github.com/stevenvelozo/fable) - Service dependency injection framework
107
+ - [pict](https://github.com/stevenvelozo/pict) - UI application framework
108
+ - [pict-view](https://github.com/stevenvelozo/pict-view) - View base class for Pict
@@ -0,0 +1,17 @@
1
+ - Getting Started
2
+
3
+ - [Introduction](/)
4
+ - [Quickstart](quickstart.md)
5
+
6
+ - Working with Objects
7
+
8
+ - [Reading Values](reading.md)
9
+ - [Writing Values](writing.md)
10
+ - [Validating Objects](validating.md)
11
+
12
+ - Reference
13
+
14
+ - [Schema Definition](schema.md)
15
+ - [Address Notation](address-notation.md)
16
+ - [Hash Translation](hash-translation.md)
17
+ - [Schema Manipulation](schema-manipulation.md)
@@ -0,0 +1,244 @@
1
+ # Address Notation
2
+
3
+ Addresses are the core of manyfest. They describe locations inside nested JavaScript objects using a compact string syntax. Every read, write, existence check and validation operation resolves through the address system.
4
+
5
+ ## Basic Dot Notation
6
+
7
+ Dots separate levels of nesting:
8
+
9
+ ```javascript
10
+ const manifest = new libManyfest();
11
+
12
+ const data = {
13
+ user: {
14
+ profile: {
15
+ name: 'Alice'
16
+ }
17
+ }
18
+ };
19
+
20
+ manifest.getValueAtAddress(data, 'user'); // { profile: { name: 'Alice' } }
21
+ manifest.getValueAtAddress(data, 'user.profile'); // { name: 'Alice' }
22
+ manifest.getValueAtAddress(data, 'user.profile.name'); // 'Alice'
23
+ ```
24
+
25
+ Paths are case-sensitive. `user.Profile` and `user.profile` resolve to different locations.
26
+
27
+ ## Array Access
28
+
29
+ Square brackets with a numeric index access array elements:
30
+
31
+ ```javascript
32
+ const data = {
33
+ items: ['first', 'second', 'third'],
34
+ users: [
35
+ { name: 'Alice', scores: [95, 88] },
36
+ { name: 'Bob', scores: [72, 91] }
37
+ ]
38
+ };
39
+
40
+ manifest.getValueAtAddress(data, 'items[0]'); // 'first'
41
+ manifest.getValueAtAddress(data, 'items[2]'); // 'third'
42
+ manifest.getValueAtAddress(data, 'users[0].name'); // 'Alice'
43
+ manifest.getValueAtAddress(data, 'users[1].scores[0]'); // 72
44
+ ```
45
+
46
+ Indices are zero-based. Accessing an out-of-bounds index returns `undefined`.
47
+
48
+ ### Set Access
49
+
50
+ Empty brackets access the full array:
51
+
52
+ ```javascript
53
+ manifest.getValueAtAddress(data, 'users[]');
54
+ // Returns all user objects
55
+ ```
56
+
57
+ When combined with further path resolution, this produces an object keyed by each element's full address:
58
+
59
+ ```javascript
60
+ manifest.getValueAtAddress(data, 'users[].name');
61
+ // { 'users[0].name': 'Alice', 'users[1].name': 'Bob' }
62
+ ```
63
+
64
+ ## Boxed Properties
65
+
66
+ Properties with special characters in their keys (dots, spaces, dashes) cannot use dot notation. Wrap them in brackets with quotes instead:
67
+
68
+ ```javascript
69
+ const data = {
70
+ 'my-key': 'value1',
71
+ 'another key': 'value2',
72
+ nested: {
73
+ 'some.dotted.key': 'value3'
74
+ }
75
+ };
76
+
77
+ manifest.getValueAtAddress(data, '["my-key"]'); // 'value1'
78
+ manifest.getValueAtAddress(data, "['another key']"); // 'value2'
79
+ manifest.getValueAtAddress(data, 'nested["some.dotted.key"]'); // 'value3'
80
+ ```
81
+
82
+ Single quotes, double quotes and backticks all work as the wrapping character.
83
+
84
+ ## Object Set Access
85
+
86
+ The `{}` marker enumerates all keys of an object, resolving a sub-path on each:
87
+
88
+ ```javascript
89
+ const data = {
90
+ departments: {
91
+ engineering: { budget: 50000, headcount: 12 },
92
+ marketing: { budget: 30000, headcount: 8 },
93
+ sales: { budget: 40000, headcount: 15 }
94
+ }
95
+ };
96
+
97
+ manifest.getValueAtAddress(data, 'departments{}.budget');
98
+ // {
99
+ // 'departments.engineering.budget': 50000,
100
+ // 'departments.marketing.budget': 30000,
101
+ // 'departments.sales.budget': 40000
102
+ // }
103
+ ```
104
+
105
+ This is useful for extracting a single field across all entries of an object-based collection.
106
+
107
+ ## Back-Navigation
108
+
109
+ Double dots (`..`) navigate upward through the object hierarchy. Each dot beyond the first separator moves one level up from the current position:
110
+
111
+ ```javascript
112
+ const data = {
113
+ Bundle: {
114
+ Contract: {
115
+ IDContract: 500
116
+ },
117
+ Project: {
118
+ IDProject: 42
119
+ }
120
+ }
121
+ };
122
+
123
+ // From IDContract, navigate back up to Bundle, then down into Project
124
+ manifest.getValueAtAddress(data, 'Bundle.Contract.IDContract...Project.IDProject');
125
+ // 42
126
+ ```
127
+
128
+ The address resolves as:
129
+ 1. Navigate to `Bundle.Contract.IDContract`
130
+ 2. `..` means go up -- one dot goes back to `Contract`, the second goes back to `Bundle`
131
+ 3. Continue forward into `Project.IDProject`
132
+
133
+ Back-navigation always resolves relative to the root object.
134
+
135
+ ## Function Calls
136
+
137
+ If a property in the path is a function, it can be called using parentheses:
138
+
139
+ ```javascript
140
+ const data = {
141
+ items: [10, 20, 30],
142
+ getTotal: function() {
143
+ return this.items.reduce((a, b) => a + b, 0);
144
+ }
145
+ };
146
+
147
+ manifest.getValueAtAddress(data, 'getTotal()'); // 60
148
+ ```
149
+
150
+ ### With Arguments
151
+
152
+ Arguments inside the parentheses are resolved as addresses on the root object:
153
+
154
+ ```javascript
155
+ const data = {
156
+ basePrice: 100,
157
+ taxRate: 0.08,
158
+ calculate: function(price, rate) {
159
+ return price + (price * rate);
160
+ }
161
+ };
162
+
163
+ manifest.getValueAtAddress(data, 'calculate(basePrice,taxRate)'); // 108
164
+ ```
165
+
166
+ String literals can be passed by wrapping them in quotes:
167
+
168
+ ```javascript
169
+ const data = {
170
+ greet: function(name) { return 'Hello, ' + name; }
171
+ };
172
+
173
+ manifest.getValueAtAddress(data, 'greet("World")'); // 'Hello, World'
174
+ ```
175
+
176
+ Functions are called with `apply`, bound to their containing object so `this` works as expected.
177
+
178
+ ### Chained Function Calls
179
+
180
+ A function's return value can be navigated further:
181
+
182
+ ```javascript
183
+ const data = {
184
+ getUser: function() {
185
+ return { name: 'Alice', role: 'admin' };
186
+ }
187
+ };
188
+
189
+ manifest.getValueAtAddress(data, 'getUser().name'); // 'Alice'
190
+ ```
191
+
192
+ ## Address Linting
193
+
194
+ Manyfest automatically cleans up common address issues before resolution:
195
+
196
+ - Leading and trailing whitespace is trimmed
197
+ - A trailing single `.` is removed (but `..` for back-navigation is preserved)
198
+
199
+ ```javascript
200
+ manifest.getValueAtAddress(data, ' user.name '); // Works
201
+ manifest.getValueAtAddress(data, 'user.name.'); // Trailing dot removed
202
+ ```
203
+
204
+ ## Writing with Addresses
205
+
206
+ All of the notation above works for write operations too. Manyfest creates intermediate objects as needed:
207
+
208
+ ```javascript
209
+ const data = {};
210
+
211
+ manifest.setValueAtAddress(data, 'user.profile.name', 'Alice');
212
+ // { user: { profile: { name: 'Alice' } } }
213
+
214
+ manifest.setValueAtAddress(data, 'items[0]', 'first');
215
+ // Also creates the items array if needed
216
+
217
+ manifest.setValueAtAddress(data, '["special-key"]', 'value');
218
+ // { 'special-key': 'value', user: { ... }, items: [...] }
219
+ ```
220
+
221
+ ## Address Syntax Summary
222
+
223
+ | Syntax | Example | Description |
224
+ |--------|---------|-------------|
225
+ | `property` | `Name` | Direct property access |
226
+ | `a.b.c` | `user.profile.name` | Nested property access |
227
+ | `a[0]` | `items[0]` | Array element by index |
228
+ | `a[].b` | `users[].name` | Property across all array elements |
229
+ | `a["b"]` | `data["my-key"]` | Boxed property (special characters) |
230
+ | `a{}.b` | `depts{}.budget` | Property across all object keys |
231
+ | `a..b` | `x.y..z` | Back-navigation (up one level) |
232
+ | `a()` | `getTotal()` | Function call |
233
+ | `a(b)` | `calc(price)` | Function call with address argument |
234
+ | `a("b")` | `greet("World")` | Function call with string literal |
235
+
236
+ ## Notes
237
+
238
+ - Addresses are case-sensitive
239
+ - Non-existent paths return `undefined` on read (no exceptions)
240
+ - Non-existent intermediate objects are created on write
241
+ - Array indices are zero-based
242
+ - Function calls require the function to exist on the object at that path
243
+ - Back-navigation resolves from the root object
244
+ - The address system is shared by all operations: get, set, check, delete and validate
package/docs/cover.md ADDED
@@ -0,0 +1,11 @@
1
+ # Manyfest <small>1</small>
2
+
3
+ > JSON Object Manifest for Data Description and Parsing
4
+
5
+ - Safe read and write access to deeply nested objects
6
+ - Schema-driven validation with data type checking
7
+ - Hash-based lookups for friendly access to complex paths
8
+ - Works in both Node.js and browser environments
9
+
10
+ [GitHub](https://github.com/stevenvelozo/manyfest)
11
+ [Get Started](#manyfest)
@@ -0,0 +1,202 @@
1
+ # Hash Translation
2
+
3
+ Hash translation tables let you reuse the same schema structure while resolving hashes to different addresses. This is useful when the same logical data model maps to objects with different property names -- for instance, when two APIs return the same information in different shapes.
4
+
5
+ ## Core Concept
6
+
7
+ Normally, a descriptor's `Hash` property maps to its `Address`:
8
+
9
+ ```javascript
10
+ // Schema: Hash "Title" maps to address "metadata.title"
11
+ manifest.getValueByHash(data, 'Title'); // resolves to data.metadata.title
12
+ ```
13
+
14
+ A translation table adds a layer of indirection. It intercepts hash lookups and redirects them before the normal hash-to-address resolution runs:
15
+
16
+ ```
17
+ Hash Lookup → Translation Table → Descriptor Hash Table → Address → Value
18
+ ```
19
+
20
+ ## Access
21
+
22
+ Translation tables live on the `hashTranslations` property of a manifest instance:
23
+
24
+ ```javascript
25
+ const manifest = new libManyfest({
26
+ Scope: 'Media',
27
+ Descriptors: {
28
+ 'metadata.title': { Hash: 'Title', DataType: 'String' },
29
+ 'metadata.creator': { Hash: 'Creator', DataType: 'String' }
30
+ }
31
+ });
32
+
33
+ // Add translations
34
+ manifest.hashTranslations.addTranslation({
35
+ 'Title': 'info.name',
36
+ 'Creator': 'info.author'
37
+ });
38
+ ```
39
+
40
+ After adding translations, `getValueByHash(data, 'Title')` resolves to `data.info.name` instead of `data.metadata.title`.
41
+
42
+ ## Adding Translations
43
+
44
+ ### addTranslation
45
+
46
+ Pass an object where each key is the source hash and each value is the destination hash or address:
47
+
48
+ ```javascript
49
+ manifest.hashTranslations.addTranslation({
50
+ 'SourceHash': 'DestinationHash',
51
+ 'AnotherSource': 'AnotherDestination'
52
+ });
53
+ ```
54
+
55
+ Multiple calls are additive. Later calls can overwrite earlier translations for the same source hash.
56
+
57
+ ## Removing Translations
58
+
59
+ ### removeTranslation
60
+
61
+ Remove by passing a string (single hash) or an object (multiple hashes):
62
+
63
+ ```javascript
64
+ // Remove a single translation
65
+ manifest.hashTranslations.removeTranslation('Title');
66
+
67
+ // Remove multiple at once
68
+ manifest.hashTranslations.removeTranslation({
69
+ 'Title': 'info.name',
70
+ 'Creator': 'info.author'
71
+ });
72
+ ```
73
+
74
+ When an object is passed, only the keys matter. The values are ignored.
75
+
76
+ ### clearTranslations
77
+
78
+ Remove all translations at once:
79
+
80
+ ```javascript
81
+ manifest.hashTranslations.clearTranslations();
82
+ ```
83
+
84
+ ## Checking the Table
85
+
86
+ ### translationCount
87
+
88
+ ```javascript
89
+ manifest.hashTranslations.translationCount(); // Number of active translations
90
+ ```
91
+
92
+ ### translate
93
+
94
+ Translate a single hash. Returns the original hash if no translation exists:
95
+
96
+ ```javascript
97
+ manifest.hashTranslations.translate('Title'); // 'info.name' (if translated)
98
+ manifest.hashTranslations.translate('Unknown'); // 'Unknown' (passthrough)
99
+ ```
100
+
101
+ ## Resolution Order
102
+
103
+ When `getValueByHash` (or any hash-based method) resolves a hash, the following order is used:
104
+
105
+ 1. **Element hash table only** -- if the hash is in the descriptor table and not in the translation table, resolve normally
106
+ 2. **Translation table then element hash table** -- if the hash is in the translation table and the translated result is in the element hash table, resolve through both
107
+ 3. **Translation table only** -- if the hash is in the translation table but the translated result is not in the element hash table, use the translated value as a direct address
108
+ 4. **Passthrough** -- if the hash is in neither table, treat it as a direct address
109
+
110
+ This means translations can override built-in descriptor hashes.
111
+
112
+ ## Use Cases
113
+
114
+ ### Multiple API Formats
115
+
116
+ When two APIs return the same data in different shapes, one schema handles both:
117
+
118
+ ```javascript
119
+ const mediaSchema = new libManyfest({
120
+ Scope: 'Media',
121
+ Descriptors: {
122
+ 'title': { Hash: 'Title', DataType: 'String' },
123
+ 'author': { Hash: 'Author', DataType: 'String' },
124
+ 'year': { Hash: 'Year', DataType: 'Integer' }
125
+ }
126
+ });
127
+
128
+ // API A returns: { title: '...', author: '...', year: 2024 }
129
+ // Works out of the box:
130
+ mediaSchema.getValueByHash(apiAResponse, 'Title');
131
+
132
+ // API B returns: { metadata: { name: '...', creator: '...' }, info: { published: 2024 } }
133
+ // Add translations for API B's shape:
134
+ mediaSchema.hashTranslations.addTranslation({
135
+ 'Title': 'metadata.name',
136
+ 'Author': 'metadata.creator',
137
+ 'Year': 'info.published'
138
+ });
139
+
140
+ mediaSchema.getValueByHash(apiBResponse, 'Title'); // reads metadata.name
141
+ mediaSchema.getValueByHash(apiBResponse, 'Author'); // reads metadata.creator
142
+ ```
143
+
144
+ ### Locale-Specific Field Names
145
+
146
+ ```javascript
147
+ const formSchema = new libManyfest({
148
+ Scope: 'Form',
149
+ Descriptors: {
150
+ 'firstName': { Hash: 'FirstName', DataType: 'String' },
151
+ 'lastName': { Hash: 'LastName', DataType: 'String' }
152
+ }
153
+ });
154
+
155
+ // Japanese form data uses different field names
156
+ formSchema.hashTranslations.addTranslation({
157
+ 'FirstName': 'mei',
158
+ 'LastName': 'sei'
159
+ });
160
+
161
+ const jpData = { mei: 'Taro', sei: 'Yamada' };
162
+ formSchema.getValueByHash(jpData, 'FirstName'); // 'Taro'
163
+ ```
164
+
165
+ ### Temporary Overrides
166
+
167
+ Apply translations for a specific operation, then clear them:
168
+
169
+ ```javascript
170
+ manifest.hashTranslations.addTranslation({ 'Name': 'display_name' });
171
+
172
+ const displayName = manifest.getValueByHash(record, 'Name');
173
+
174
+ manifest.hashTranslations.clearTranslations();
175
+ // Back to normal resolution
176
+ ```
177
+
178
+ ## Serialization
179
+
180
+ Hash translations are included when you serialize a manifest:
181
+
182
+ ```javascript
183
+ const state = manifest.getManifest();
184
+ // { Scope: '...', Descriptors: {...}, HashTranslations: {...} }
185
+
186
+ const json = manifest.serialize();
187
+ // HashTranslations included in the JSON string
188
+ ```
189
+
190
+ And restored when you clone:
191
+
192
+ ```javascript
193
+ const copy = manifest.clone();
194
+ // copy.hashTranslations contains the same translations
195
+ ```
196
+
197
+ ## Notes
198
+
199
+ - Translations are checked before the built-in hash table, so they can override descriptor hashes
200
+ - If a translation points to a hash that also has a translation, only one level of indirection is resolved
201
+ - Translations work with all hash-based methods: `getValueByHash`, `setValueByHash`, `deleteValueByHash`, `checkAddressExistsByHash`, `getDescriptorByHash`
202
+ - The translation table is a simple `{ source: destination }` object -- no nesting or chaining
@@ -0,0 +1,51 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <title>Manyfest Documentation</title>
6
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
7
+ <meta name="description" content="Documentation for Manyfest - JSON Object Manifest for Data Description and Parsing" />
8
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0" />
9
+ <meta name="keywords" content="manyfest, manifest, json, object, schema, data, description, parsing, javascript" />
10
+ <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css" />
11
+ <style>
12
+ :root {
13
+ --theme-color: #42b983;
14
+ }
15
+ </style>
16
+ </head>
17
+ <body>
18
+ <div id="app"></div>
19
+ <script>
20
+ window.$docsify = {
21
+ name: 'Manyfest',
22
+ repo: 'https://github.com/stevenvelozo/manyfest',
23
+ loadSidebar: '_sidebar.md',
24
+ subMaxLevel: 3,
25
+ auto2top: true,
26
+ coverpage: 'cover.md',
27
+ onlyCover: false,
28
+ search: {
29
+ placeholder: 'Search',
30
+ noData: 'No results found',
31
+ depth: 3
32
+ },
33
+ copyCode: {
34
+ buttonText: 'Copy',
35
+ successText: 'Copied'
36
+ }
37
+ };
38
+ </script>
39
+ <!-- Docsify v4 -->
40
+ <script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
41
+ <!-- Syntax highlighting -->
42
+ <script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-javascript.min.js"></script>
43
+ <script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-json.min.js"></script>
44
+ <script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-bash.min.js"></script>
45
+ <script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-markdown.min.js"></script>
46
+ <!-- Search plugin -->
47
+ <script src="//cdn.jsdelivr.net/npm/docsify@4/lib/plugins/search.min.js"></script>
48
+ <!-- Copy code plugin -->
49
+ <script src="//cdn.jsdelivr.net/npm/docsify-copy-code@2"></script>
50
+ </body>
51
+ </html>