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 CHANGED
@@ -17,11 +17,56 @@ Manyfest's purpose is to solve this problem by creating a simple pattern to desc
17
17
 
18
18
  _Man-E-Faces approves of Manyfest!_
19
19
 
20
+ ## Quick Example
21
+
22
+ ```javascript
23
+ const libManyfest = require('manyfest');
24
+
25
+ // Define a schema
26
+ const manifest = new libManyfest({
27
+ Scope: 'User',
28
+ Descriptors: {
29
+ 'Name': { DataType: 'String', Required: true },
30
+ 'Email': { DataType: 'String', Required: true },
31
+ 'Profile.Age': { DataType: 'Integer' },
32
+ 'Profile.Bio': { DataType: 'String', Default: '' }
33
+ }
34
+ });
35
+
36
+ // Read safely from nested objects (no exceptions on missing paths)
37
+ const user = { Name: 'Alice', Profile: { Age: 30 } };
38
+ manifest.getValueAtAddress(user, 'Profile.Age'); // 30
39
+ manifest.getValueAtAddress(user, 'Profile.Phone'); // undefined
40
+
41
+ // Write to any depth (intermediate objects are created automatically)
42
+ const newUser = {};
43
+ manifest.setValueAtAddress(newUser, 'Name', 'Bob');
44
+ manifest.setValueAtAddress(newUser, 'Profile.Age', 25);
45
+ // newUser is now: { Name: 'Bob', Profile: { Age: 25 } }
46
+
47
+ // Validate against the schema
48
+ const result = manifest.validate({ Name: 'Carol' });
49
+ // result.Errors: ['Element at address "Email" is flagged REQUIRED but is not set in the object.']
50
+ ```
51
+
52
+ ## Documentation
53
+
54
+ | Guide | Description |
55
+ | ----- | ----------- |
56
+ | [Quickstart](docs/quickstart.md) | Installation, first schema, and basic operations in under five minutes. |
57
+ | [Reading Values](docs/reading.md) | `getValueAtAddress`, `getValueByHash`, array access, boxed properties, back-navigation, function resolution and defaults. |
58
+ | [Writing Values](docs/writing.md) | `setValueAtAddress`, `setValueByHash`, auto-creation of nested structures, populating defaults and deleting values. |
59
+ | [Validating Objects](docs/validating.md) | Required fields, strict mode, data type checking and the validation result structure. |
60
+ | [Schema Definition](docs/schema.md) | Descriptors, data types, scope, serialization, cloning and programmatic schema building. |
61
+ | [Address Notation](docs/address-notation.md) | The complete address syntax: dot notation, arrays, boxed properties, object sets, back-navigation and function calls. |
62
+ | [Hash Translation](docs/hash-translation.md) | Reusing schemas with different hash mappings for multiple API shapes. |
63
+ | [Schema Manipulation](docs/schema-manipulation.md) | Remapping addresses, merging schemas and auto-generating schemas from sample data. |
64
+
20
65
  ## Where Does this Run
21
66
 
22
- Either of a stand-alone library in node.js software, or, a dependency-free browser library.
67
+ Either as a stand-alone library in node.js software, or, a dependency-free browser library.
23
68
 
24
- ### Compatiblity
69
+ ### Compatibility
25
70
 
26
71
  This library is tested for node.js versions 8 through 16, and will likely work in future versions. It is implemented as a simple set of es6 classes.
27
72
 
@@ -32,13 +77,13 @@ The browser version has been packaged into a minified as well as an expanded deb
32
77
  For use within node.js, run the following in the folder with your `package.json` file:
33
78
 
34
79
  ```
35
- npm install --save Manyfest
80
+ npm install --save manyfest
36
81
  ```
37
82
 
38
83
  Then, you can include it in your source code as follows:
39
84
 
40
85
  ```javascript
41
- const libManyfest = require('Manyfest');
86
+ const libManyfest = require('manyfest');
42
87
 
43
88
  // Construct a Manyfest with a few defined columns
44
89
  let animalManyfest = new libManyfest(
@@ -71,16 +116,16 @@ Below is a lexicon of terms used throughout this documentation. If you see anyt
71
116
 
72
117
  | Term | Description |
73
118
  | ---- | ----------- |
74
- Scope | The scope of this representation; generally the clustered or parent record name (e.g. Animal, User, Transaction, etc.) -- does not have functional purpose; only for information and logging.
75
- Schema | The stateful representation of an object's structural definition.
76
- Element | A defined element of data in an object.
77
- Address | The address where that data lies in the object.
78
- Hash | A unique within this scope string-based key for this element. Used for easy access of data.
79
- Descriptor | A description of an element including data such as Name, NameShort, Hash, Description, and other important properties.
80
- Name | The name of the element. Meant to be the most succinct human readable name possible.
81
- NameShort | A shorter name for the element. Meant to be useful enough to identify the property in log lines, tabular views, graphs and anywhere where we don't always want to see the full name.
82
- Description | A description for the element. Very useful when consuming other APIs with their own terse naming standards (or no naming standards)!
83
- Required | Set to true if this element is required.
119
+ | Scope | The scope of this representation; generally the clustered or parent record name (e.g. Animal, User, Transaction, etc.) -- does not have functional purpose; only for information and logging. |
120
+ | Schema | The stateful representation of an object's structural definition. |
121
+ | Element | A defined element of data in an object. |
122
+ | Address | The address where that data lies in the object. |
123
+ | Hash | A unique within this scope string-based key for this element. Used for easy access of data. |
124
+ | Descriptor | A description of an element including data such as Name, NameShort, Hash, Description, and other important properties. |
125
+ | Name | The name of the element. Meant to be the most succinct human readable name possible. |
126
+ | NameShort | A shorter name for the element. Meant to be useful enough to identify the property in log lines, tabular views, graphs and anywhere where we don't always want to see the full name. |
127
+ | Description | A description for the element. Very useful when consuming other APIs with their own terse naming standards (or no naming standards)! |
128
+ | Required | Set to true if this element is required. |
84
129
 
85
130
  Okay so these are a lot of crazy words. The important two are *Address* and *Hash*. Every element in a schema must have an address. Having a hash just multiplies the usefulness of these addresses.
86
131
 
@@ -100,7 +145,7 @@ let animalManyfest = new libManyfest(
100
145
  "IDAnimal": { "Name":"Database ID", "Description":"The unique integer-based database identifier for an Animal record.", "DataType":"Integer" },
101
146
  "Name": { "Description":"The animal's colloquial species name (e.g. Rabbit, Dog, Bear, Mongoose)." },
102
147
  "Type": { "Description":"Whether or not the animal is wild, domesticated, agricultural, in a research lab or a part of a zoo.." },
103
- "MedicalStats":
148
+ "MedicalStats":
104
149
  {
105
150
  "Name":"Medical Statistics", "Description":"Basic medical statistics for this animal"
106
151
  },
@@ -126,19 +171,19 @@ To aid in this discovery, reference and such, we've given it a NameShort (for us
126
171
 
127
172
  | Type | Description |
128
173
  | ---- | ----------- |
129
- String | A pretty basic string
130
- Integer | An integer number
131
- Float | A floating point number; does not require a decimal point
132
- Number | A number of any type
133
- PreciseNumber | An arbitrary precision number, stored in a string
134
- Boolean | A boolean value represented by the JSON true or false
135
- Binary | A boolean value represented as 1 or 0
136
- YesNo | A boolean value represented as Y or N
137
- DateTime | A javascript date
138
- Key | A two-part Key with an Identifier and Globally Unique Identifier (ID and GUID)
139
- Array | A plain old javascript array
140
- Object | A plain old javascript object
141
- Null | A null value
174
+ | String | A pretty basic string |
175
+ | Integer | An integer number |
176
+ | Float | A floating point number; does not require a decimal point |
177
+ | Number | A number of any type |
178
+ | PreciseNumber | An arbitrary precision number, stored in a string |
179
+ | Boolean | A boolean value represented by the JSON true or false |
180
+ | Binary | A boolean value represented as 1 or 0 |
181
+ | YesNo | A boolean value represented as Y or N |
182
+ | DateTime | A javascript date |
183
+ | Key | A two-part Key with an Identifier and Globally Unique Identifier (ID and GUID) |
184
+ | Array | A plain old javascript array |
185
+ | Object | A plain old javascript object |
186
+ | Null | A null value |
142
187
 
143
188
  #### Keys
144
189
 
@@ -215,14 +260,14 @@ For any elements that haven't defined a Hash, the Address is used. This allows
215
260
 
216
261
  ## Hash Translation Tables
217
262
 
218
- Sometimes we want to reuse the structure of a schema, but look up values by hash using translations.
263
+ Sometimes we want to reuse the structure of a schema, but look up values by hash using translations. See the [Hash Translation](docs/hash-translation.md) documentation for the full guide.
219
264
 
220
265
  ## Programmatically Defining a Schema
221
266
 
222
267
  Sometimes we don't have schemas, and want to define object element structure on the fly. This can be done programmatically. As a refresher, here is how we loaded our simplest schema manifest above:
223
268
 
224
269
  ```javascript
225
- const libManyfest = require('Manyfest');
270
+ const libManyfest = require('manyfest');
226
271
 
227
272
  // Construct a Manyfest with a few defined columns
228
273
  let animalManyfest = new libManyfest(
@@ -240,13 +285,13 @@ let animalManyfest = new libManyfest(
240
285
  The programmatic equivalent is the following code:
241
286
 
242
287
  ```javascript
243
- const libManyfest = require('Manyfest');
288
+ const libManyfest = require('manyfest');
244
289
 
245
290
  // Construct a Manyfest with a few defined columns
246
291
  let animalManyfest = new libManyfest();
247
292
 
248
293
  // Set the Scope
249
- animalManyfest.Scope = "Animal";
294
+ animalManyfest.scope = "Animal";
250
295
 
251
296
  // Add descriptors
252
297
  animalManyfest.addDescriptor("IDAnimal", { "Name":"Database ID", "Description":"The unique integer-based database identifier for an Animal record.", "DataType":"Integer" });
@@ -268,10 +313,13 @@ With manyfest, you can easily create a description for each API and code against
268
313
 
269
314
  Modern APIs are super complicated. And worse, they change. Let's take a real example. [Archive.org](https://archive.org/) is a wonderful resource for downloading awesome content gathered from the web and such.
270
315
 
271
- There is an API to access their data. It's ... really messy, the data you get back. below is the JSON for a single video (a rad Count Chocula commercial from 1971) -- it takes quite a bit of scroll to get down to the bottom.
316
+ There is an API to access their data. It's ... really messy, the data you get back. Below is the JSON for a single video (a rad Count Chocula commercial from 1971) -- it takes quite a bit of scroll to get down to the bottom.
272
317
 
273
318
  ![Count Chocula will Rise Again](http://ia800202.us.archive.org/7/items/FrankenberryCountChoculaTevevisionCommercial1971/frankerberry_countchockula_1971.0001.gif)
274
319
 
320
+ <details>
321
+ <summary>Archive.org JSON response (click to expand)</summary>
322
+
275
323
  ```JSON
276
324
  {
277
325
  "created": 1664830085,
@@ -290,131 +338,6 @@ There is an API to access their data. It's ... really messy, the data you get b
290
338
  "crc32": "165c668b",
291
339
  "sha1": "383303d9546c381267569ad4e33aff691f0bb8c7"
292
340
  },
293
- {
294
- "name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000004.jpg",
295
- "source": "derivative",
296
- "format": "Thumbnail",
297
- "original": "frankerberry_countchockula_1971.0001.mpg",
298
- "mtime": "1296336957",
299
- "size": "6843",
300
- "md5": "c93fa52000ab4665e69b25c403e11aff",
301
- "crc32": "9444e6f6",
302
- "sha1": "716b4f9950b8147f51d3265f9c62ff86451308d5"
303
- },
304
- {
305
- "name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000009.jpg",
306
- "source": "derivative",
307
- "format": "Thumbnail",
308
- "original": "frankerberry_countchockula_1971.0001.mpg",
309
- "mtime": "1296336957",
310
- "size": "8388",
311
- "md5": "30eb3eb4cbbdfa08d531a0a74da7c000",
312
- "crc32": "be874a9e",
313
- "sha1": "0c392d777609e967b6022be27edad678c5ae74e2"
314
- },
315
- {
316
- "name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000014.jpg",
317
- "source": "derivative",
318
- "format": "Thumbnail",
319
- "original": "frankerberry_countchockula_1971.0001.mpg",
320
- "mtime": "1296336958",
321
- "size": "5993",
322
- "md5": "4e9ebc3d076bec8cf7dfe76795f8c769",
323
- "crc32": "912ec98c",
324
- "sha1": "01dc49c852e1bbb421199450dd902935c62b06de"
325
- },
326
- {
327
- "name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000019.jpg",
328
- "source": "derivative",
329
- "format": "Thumbnail",
330
- "original": "frankerberry_countchockula_1971.0001.mpg",
331
- "mtime": "1296336958",
332
- "size": "4951",
333
- "md5": "59f190f0c5b0a048415b26412860b6dd",
334
- "crc32": "a70a30b1",
335
- "sha1": "a284af9757cb24d28f96ec88ec1b1c23a8cea9fe"
336
- },
337
- {
338
- "name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000024.jpg",
339
- "source": "derivative",
340
- "format": "Thumbnail",
341
- "original": "frankerberry_countchockula_1971.0001.mpg",
342
- "mtime": "1296336959",
343
- "size": "3383",
344
- "md5": "be2a908acd563b896e7758b598295148",
345
- "crc32": "ed467831",
346
- "sha1": "94c001e72ebc86d837a78c61a004db9ab9d597bd"
347
- },
348
- {
349
- "name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000029.jpg",
350
- "source": "derivative",
351
- "format": "Thumbnail",
352
- "original": "frankerberry_countchockula_1971.0001.mpg",
353
- "mtime": "1296336960",
354
- "size": "3503",
355
- "md5": "c82199d09be07633000fd07b363dd8a3",
356
- "crc32": "a1fd79cb",
357
- "sha1": "2bc8e761edb24a441fa5906dda1c424e1f98a47a"
358
- },
359
- {
360
- "name": "FrankenberryCountChoculaTevevisionCommercial1971_archive.torrent",
361
- "source": "metadata",
362
- "btih": "de6b371e7cc3c83db1cc08150500753eae533409",
363
- "mtime": "1542761794",
364
- "size": "4093",
365
- "md5": "a275d3b4028cccb5bea8b47a88c838af",
366
- "crc32": "5ffa7334",
367
- "sha1": "af8222637b574cba1360d0ea77e231640ffd43c4",
368
- "format": "Archive BitTorrent"
369
- },
370
- {
371
- "name": "FrankenberryCountChoculaTevevisionCommercial1971_files.xml",
372
- "source": "metadata",
373
- "format": "Metadata",
374
- "md5": "3a7e87b08bed1e203a5858b31352c110"
375
- },
376
- {
377
- "name": "FrankenberryCountChoculaTevevisionCommercial1971_meta.xml",
378
- "source": "metadata",
379
- "format": "Metadata",
380
- "mtime": "1542761793",
381
- "size": "1371",
382
- "md5": "0b9c9bf21b9a26aea43a2f735b404624",
383
- "crc32": "41077288",
384
- "sha1": "22e6f2c73bf63072f671d846355da2785db51dbd"
385
- },
386
- {
387
- "name": "FrankenberryCountChoculaTevevisionCommercial1971_reviews.xml",
388
- "source": "original",
389
- "mtime": "1466898697",
390
- "size": "620",
391
- "md5": "260bfba5d696772445dcc7ff6e6d5bdb",
392
- "crc32": "25ea3229",
393
- "sha1": "7d541f18fcd5ad9c6e593afe5a80f18771f23b32",
394
- "format": "Metadata"
395
- },
396
- {
397
- "name": "__ia_thumb.jpg",
398
- "source": "original",
399
- "mtime": "1539115881",
400
- "size": "7481",
401
- "md5": "8cec324fa0016fd77cc04e6a4b2ebb00",
402
- "crc32": "d9e1b316",
403
- "sha1": "4dab42952fe0405a3b7f80146636b33d7b1bd01e",
404
- "format": "Item Tile",
405
- "rotation": "0"
406
- },
407
- {
408
- "name": "frankerberry_countchockula_1971.0001.gif",
409
- "source": "derivative",
410
- "format": "Animated GIF",
411
- "original": "frankerberry_countchockula_1971.0001.mpg",
412
- "mtime": "1296336965",
413
- "size": "101114",
414
- "md5": "b78a13094030f104900eb996bafe2b7d",
415
- "crc32": "6650cd8",
416
- "sha1": "669798c037205cac14f70592deef6f7831b3d4a1"
417
- },
418
341
  {
419
342
  "name": "frankerberry_countchockula_1971.0001.mpg",
420
343
  "source": "original",
@@ -427,45 +350,6 @@ There is an API to access their data. It's ... really messy, the data you get b
427
350
  "length": "31.14",
428
351
  "height": "480",
429
352
  "width": "640"
430
- },
431
- {
432
- "name": "frankerberry_countchockula_1971.0001.mpg.idx",
433
- "source": "derivative",
434
- "format": "Video Index",
435
- "original": "frankerberry_countchockula_1971.0001.mpg",
436
- "mtime": "1296336956",
437
- "size": "31141",
438
- "md5": "49423e072726e4ea3cdd8ebdd26c7dfc",
439
- "crc32": "ae969a68",
440
- "sha1": "805782cd2d0f9002555816daadf3b8607e621f79"
441
- },
442
- {
443
- "name": "frankerberry_countchockula_1971.0001.ogv",
444
- "source": "derivative",
445
- "format": "Ogg Video",
446
- "original": "frankerberry_countchockula_1971.0001.mpg",
447
- "mtime": "1296336994",
448
- "size": "2248166",
449
- "md5": "f1b933e97ce63594fb28a0a019ff3436",
450
- "crc32": "a2a0e5e9",
451
- "sha1": "a6bf0aec9f006baeca37c03f586686ebe685d59b",
452
- "length": "31.15",
453
- "height": "300",
454
- "width": "400"
455
- },
456
- {
457
- "name": "frankerberry_countchockula_1971.0001_512kb.mp4",
458
- "source": "derivative",
459
- "format": "512Kb MPEG4",
460
- "original": "frankerberry_countchockula_1971.0001.mpg",
461
- "mtime": "1296336977",
462
- "size": "2378677",
463
- "md5": "a7750839519c61ba3bb99fc66b32011d",
464
- "crc32": "4dbd37c8",
465
- "sha1": "3929314c192dec006fac2739bcb4730788e8c068",
466
- "length": "31.13",
467
- "height": "240",
468
- "width": "320"
469
353
  }
470
354
  ],
471
355
  "files_count": 17,
@@ -476,31 +360,8 @@ There is an API to access their data. It's ... really messy, the data you get b
476
360
  "title": "Franken Berry / Count Chocula : Tevevision Commercial 1971",
477
361
  "creator": "General Mills",
478
362
  "mediatype": "movies",
479
- "collection": [
480
- "classic_tv_commercials",
481
- "television"
482
- ],
483
- "description": "Count Chocula and Franken Berry were both introduced in 1971. Boo Berry Cereal appeared in 1973 followed by Fruit Brute in 1974. Yummy Mummy appeared more than a decade later in 1988 - completing the the group known as the General Mills Monster Cereals.",
484
- "subject": "Third Eye Cinema; Classic Television Commercials; animation; cartoons;General Mills",
485
- "licenseurl": "http://creativecommons.org/publicdomain/mark/1.0/",
486
- "publicdate": "2011-01-29 21:36:42",
487
- "addeddate": "2011-01-29 21:35:38",
488
- "uploader": "bolexman@msn.com",
489
- "updater": [
490
- "Bolexman",
491
- "Bolexman",
492
- "Jeff Kaplan"
493
- ],
494
- "updatedate": [
495
- "2011-01-29 21:45:38",
496
- "2011-01-29 21:55:46",
497
- "2011-01-29 23:04:55"
498
- ],
499
- "sound": "sound",
500
- "color": "color",
501
- "runtime": "0:31",
502
- "backup_location": "ia903608_22",
503
- "ia_orig__runtime": "31 seconds"
363
+ "collection": ["classic_tv_commercials", "television"],
364
+ "description": "Count Chocula and Franken Berry were both introduced in 1971. Boo Berry Cereal appeared in 1973 followed by Fruit Brute in 1974. Yummy Mummy appeared more than a decade later in 1988 - completing the the group known as the General Mills Monster Cereals."
504
365
  },
505
366
  "reviews": [
506
367
  {
@@ -508,19 +369,15 @@ There is an API to access their data. It's ... really messy, the data you get b
508
369
  "reviewtitle": "pre booberry",
509
370
  "reviewer": "outofthebox",
510
371
  "reviewdate": "2016-06-25 23:51:36",
511
- "createdate": "2016-06-25 23:51:36",
512
372
  "stars": "4"
513
373
  }
514
374
  ],
515
- "server": "ia800202.us.archive.org",
516
- "uniq": 1957612749,
517
- "workable_servers": [
518
- "ia800202.us.archive.org",
519
- "ia600202.us.archive.org"
520
- ]
375
+ "server": "ia800202.us.archive.org"
521
376
  }
522
377
  ```
523
378
 
379
+ </details>
380
+
524
381
  ### A Manyfest Schema for Count Chocula to Thrive In
525
382
 
526
383
  With just a small number of element descriptors, we can make this huge blob of JSON very usable for a developer.
@@ -577,7 +434,7 @@ With just a small number of element descriptors, we can make this huge blob of J
577
434
 
578
435
  These two JSON files are in the [examples/chocula](https://github.com/stevenvelozo/manyfest/tree/main/examples/chocula) folder along with a javascript file `Chocula.js` you can try out yourself and hack on.
579
436
 
580
- ```
437
+ ```javascript
581
438
  let libManyfest = require('../../source/Manyfest.js');
582
439
 
583
440
  let dataArchiveOrg = require(`./Data-Archive-org-Frankenberry.json`);
@@ -588,7 +445,7 @@ let _Schema = new libManyfest(schemaArchiveOrg);
588
445
  console.log(`The URL for "${_Schema.getValueByHash(dataArchiveOrg,'Title')}" is: ${_Schema.getValueByHash(dataArchiveOrg,'Server')}${_Schema.getValueByHash(dataArchiveOrg,'Path')}`);
589
446
  ```
590
447
 
591
- ### A Manyfest Schema for Book records
448
+ ### A Manyfest Schema for Book Records
592
449
 
593
450
  This shows a book record with an Author Key as well.
594
451
 
@@ -624,12 +481,12 @@ This shows a book record with an Author Key as well.
624
481
  "KeyRepresentation": "ID",
625
482
  "GUIDAddress": "GUIDAuthor",
626
483
  "IDAddress": "IDAuthor"
627
- },
484
+ }
628
485
  }
629
486
  }
630
487
  ```
631
488
 
632
- Because we expect only one scope to be the controlling scope for a particular key pair, we can use the key pair presence as a mechnism for resolution of IDs to GUIDs when they aren't natural.
489
+ Because we expect only one scope to be the controlling scope for a particular key pair, we can use the key pair presence as a mechanism for resolution of IDs to GUIDs when they aren't natural.
633
490
 
634
491
  What does this mean in practice?
635
492
 
@@ -653,36 +510,10 @@ And the following Author record:
653
510
  }
654
511
  ```
655
512
 
656
-
657
513
  #### This gives rise to the need for a "Key" data type which is a tuple
658
514
 
659
515
  The tuple will be a GUID or ID, but will represent both. As long as only one entity in the controlling scope (the Book table for instance) to have *both* the ID and the GUID, this can be used to make that the source of record for the Key. This allows lookups back and forth between GUID and ID.
660
516
 
661
- 1. Author is the cannonical source for finding the GUIDAuthor->IDAuthor connection, and vice versa. Because it is the only record shape in the model space that contains both.
517
+ 1. Author is the canonical source for finding the GUIDAuthor->IDAuthor connection, and vice versa. Because it is the only record shape in the model space that contains both.
662
518
  2. GUIDAuthor is not in the Descriptors as a secondary address, but IDAuthor is. GUIDAuthor is, though, resolvable from the IDAuthor GUIDAddress property.
663
519
  3. This means we want to treat the "GUIDAuthor"/"IDAuthor" pairing as a single entry in a manyfest, which is a departure from how the rest of them operate.
664
-
665
- ## BELOW WILL BE IN Pict
666
-
667
- ## Record "Sieve"s
668
-
669
- Sometimes we want to take a record from a source shape, and translate it into a destination shape. This can be done with an implicit sieve or an explicit sieve.
670
-
671
- ### Handy Assertions for Working with a Sieve
672
-
673
- * A record is a single object without loops.
674
- * A record is part of a RecordSet.
675
- * A record has an RecordSet key (e.g. "Users", "Projects", "Books", etc.).
676
- * A record may have an Entity key (e.g. "Users", "Projects", "Books", etc.).
677
- * The difference between RecordSet and Entity is that an Entity is a Record associated with a Key is expected to be stored in an Entity Storage System of some kind whereas a RecordSet Record might be abstract.
678
- * A Record has a Key which represents a GUID and Identifier.
679
- * GUIDs are RecordSet scoped strings that are unique to a Record.
680
- * Identifiers are RecordSet Storage scoped strings or numbers that are unique to a Record.
681
- * There is only one cannonical provider of each Record Entity
682
- * When creating a sieve instance, we are going to migrate sets of records from one schema to another.
683
-
684
- ### Implicit Sieve
685
-
686
- An implicit sieve embeds the configuration for Projection(s) within the current recordset. There is a Projection array, each of which has an entry for basic record projections. This should be good enough for simple transformation operations.
687
-
688
- Each of these Projections come as a simple record shape with templated expressions.
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)