manyfest 1.0.3 → 1.0.4

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.
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "optOut": false,
3
- "lastUpdateCheck": 1665680610935
3
+ "lastUpdateCheck": 1665932798321
4
4
  }
package/README.md CHANGED
@@ -75,13 +75,15 @@ Scope | The scope of this representation; generally the clustered or parent reco
75
75
  Schema | The stateful representation of an object's structural definition.
76
76
  Element | A defined element of data in an object.
77
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.
78
79
  Descriptor | A description of an element including data such as Name, NameShort, Hash, Description, and other important properties.
79
80
  Name | The name of the element. Meant to be the most succinct human readable name possible.
80
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.
81
82
  Description | A description for the element. Very useful when consuming other APIs with their own terse naming standards (or no naming standards)!
82
- Hash | A unique within this scope string-based key for this element. Used for easy access of data.
83
83
  Required | Set to true if this element is required.
84
84
 
85
+ 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
+
85
87
  ## A More Advanced Schema Example
86
88
 
87
89
  Addresses are meant to be kinda magic. They describe locations in nested JSON just as well as simple objects. Further, they can allow us to manipulate and read JSON values at specific addresses.
@@ -205,6 +207,10 @@ console.log(animalManyfest.getValueByHash(favAnimal,'ComfET'));
205
207
 
206
208
  For any elements that haven't defined a Hash, the Address is used. This allows code to gracefully fall back.
207
209
 
210
+ ## Hash Translation Tables
211
+
212
+ Sometimes we want to reuse the structure of a schema, but look up values by hash using translations.
213
+
208
214
  ## Programmatically Defining a Schema
209
215
 
210
216
  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:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "manyfest",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "JSON Object Manifest for Data Description and Parsing",
5
5
  "main": "source/Manyfest.js",
6
6
  "scripts": {
@@ -0,0 +1,118 @@
1
+ /**
2
+ * @license MIT
3
+ * @author <steven@velozo.com>
4
+ */
5
+ let libSimpleLog = require('./Manyfest-LogToConsole.js');
6
+
7
+ /**
8
+ * Hash Translation
9
+ *
10
+ * This is a very simple translation table for hashes, which allows the same schema to resolve
11
+ * differently based on a loaded translation table.
12
+ *
13
+ * This is to prevent the requirement for mutating schemas over and over again when we want to
14
+ * reuse the structure but look up data elements by different addresses.
15
+ *
16
+ * One side-effect of this is that a translation table can "override" the built-in hashes, since
17
+ * this is always used to resolve hashes before any of the functionCallByHash(pHash, ...) perform
18
+ * their lookups by hash.
19
+ *
20
+ * @class ManyfestHashTranslation
21
+ */
22
+ class ManyfestHashTranslation
23
+ {
24
+ constructor(pInfoLog, pErrorLog)
25
+ {
26
+ // Wire in logging
27
+ this.logInfo = (typeof(pInfoLog) === 'function') ? pInfoLog : libSimpleLog;
28
+ this.logError = (typeof(pErrorLog) === 'function') ? pErrorLog : libSimpleLog;
29
+
30
+ this.translationTable = {};
31
+ }
32
+
33
+ translationCount()
34
+ {
35
+ return Object.keys(this.translationTable).length;
36
+ }
37
+
38
+ addTranslation(pTranslation)
39
+ {
40
+ // This adds a translation in the form of:
41
+ // { "SourceHash": "DestinationHash", "SecondSourceHash":"SecondDestinationHash" }
42
+ if (typeof(pTranslation) != 'object')
43
+ {
44
+ this.logError(`Hash translation addTranslation expected a translation be type object but was passed in ${typeof(pTranslation)}`);
45
+ return false;
46
+ }
47
+
48
+ let tmpTranslationSources = Object.keys(pTranslation)
49
+
50
+ tmpTranslationSources.forEach(
51
+ (pTranslationSource) =>
52
+ {
53
+ if (typeof(pTranslation[pTranslationSource]) != 'string')
54
+ {
55
+ this.logError(`Hash translation addTranslation expected a translation destination hash for [${pTranslationSource}] to be a string but the referrant was a ${typeof(pTranslation[pTranslationSource])}`);
56
+ }
57
+ else
58
+ {
59
+ this.translationTable[pTranslationSource] = pTranslation[pTranslationSource];
60
+ }
61
+ });
62
+ }
63
+
64
+ removeTranslationHash(pTranslationHash)
65
+ {
66
+ if (this.translationTable.hasOwnProperty(pTranslationHash))
67
+ {
68
+ delete this.translationTable[pTranslationHash];
69
+ }
70
+ }
71
+
72
+ // This removes translations.
73
+ // If passed a string, just removes the single one.
74
+ // If passed an object, it does all the source keys.
75
+ removeTranslation(pTranslation)
76
+ {
77
+ if (typeof(pTranslation) == 'string')
78
+ {
79
+ this.removeTranslationHash(pTranslation);
80
+ return true;
81
+ }
82
+ else if (typeof(pTranslation) == 'object')
83
+ {
84
+ let tmpTranslationSources = Object.keys(pTranslation)
85
+
86
+ tmpTranslationSources.forEach(
87
+ (pTranslationSource) =>
88
+ {
89
+ this.removeTranslation(pTranslationSource);
90
+ });
91
+ return true;
92
+ }
93
+ else
94
+ {
95
+ this.logError(`Hash translation removeTranslation expected either a string or an object but the passed-in translation was type ${typeof(pTranslation)}`);
96
+ return false;
97
+ }
98
+ }
99
+
100
+ clearTranslations()
101
+ {
102
+ this.translationTable = {};
103
+ }
104
+
105
+ translate(pTranslation)
106
+ {
107
+ if (this.translationTable.hasOwnProperty(pTranslation))
108
+ {
109
+ return this.translationTable[pTranslation];
110
+ }
111
+ else
112
+ {
113
+ return pTranslation;
114
+ }
115
+ }
116
+ }
117
+
118
+ module.exports = ManyfestHashTranslation;
@@ -27,8 +27,8 @@ class ManyfestObjectAddressResolver
27
27
  constructor(pInfoLog, pErrorLog)
28
28
  {
29
29
  // Wire in logging
30
- this.logInfo = (typeof(pInfoLog) === 'function') ? pInfoLog : libSimpleLog;
31
- this.logError = (typeof(pErrorLog) === 'function') ? pErrorLog : libSimpleLog;
30
+ this.logInfo = (typeof(pInfoLog) == 'function') ? pInfoLog : libSimpleLog;
31
+ this.logError = (typeof(pErrorLog) == 'function') ? pErrorLog : libSimpleLog;
32
32
  }
33
33
 
34
34
  // When a boxed property is passed in, it should have quotes of some
@@ -67,15 +67,15 @@ class ManyfestObjectAddressResolver
67
67
  {
68
68
  // TODO: Should these throw an error?
69
69
  // Make sure pObject is an object
70
- if (!typeof(pObject) === 'object') return false;
70
+ if (typeof(pObject) != 'object') return false;
71
71
  // Make sure pAddress is a string
72
- if (!typeof(pAddress) === 'string') return false;
72
+ if (typeof(pAddress) != 'string') return false;
73
73
 
74
74
  // TODO: Make this work for things like SomeRootObject.Metadata["Some.People.Use.Bad.Object.Property.Names"]
75
75
  let tmpSeparatorIndex = pAddress.indexOf('.');
76
76
 
77
77
  // This is the terminal address string (no more dots so the RECUSION ENDS IN HERE somehow)
78
- if (tmpSeparatorIndex === -1)
78
+ if (tmpSeparatorIndex == -1)
79
79
  {
80
80
  // Check if the address refers to a boxed property
81
81
  let tmpBracketStartIndex = pAddress.indexOf('[');
@@ -240,15 +240,15 @@ class ManyfestObjectAddressResolver
240
240
  getValueAtAddress (pObject, pAddress)
241
241
  {
242
242
  // Make sure pObject is an object
243
- if (!typeof(pObject) === 'object') return undefined;
243
+ if (typeof(pObject) != 'object') return undefined;
244
244
  // Make sure pAddress is a string
245
- if (!typeof(pAddress) === 'string') return undefined;
245
+ if (typeof(pAddress) != 'string') return undefined;
246
246
 
247
247
  // TODO: Make this work for things like SomeRootObject.Metadata["Some.People.Use.Bad.Object.Property.Names"]
248
248
  let tmpSeparatorIndex = pAddress.indexOf('.');
249
249
 
250
250
  // This is the terminal address string (no more dots so the RECUSION ENDS IN HERE somehow)
251
- if (tmpSeparatorIndex === -1)
251
+ if (tmpSeparatorIndex == -1)
252
252
  {
253
253
  // Check if the address refers to a boxed property
254
254
  let tmpBracketStartIndex = pAddress.indexOf('[');
@@ -410,13 +410,13 @@ class ManyfestObjectAddressResolver
410
410
  setValueAtAddress (pObject, pAddress, pValue)
411
411
  {
412
412
  // Make sure pObject is an object
413
- if (!typeof(pObject) === 'object') return false;
413
+ if (typeof(pObject) != 'object') return false;
414
414
  // Make sure pAddress is a string
415
- if (!typeof(pAddress) === 'string') return false;
415
+ if (typeof(pAddress) != 'string') return false;
416
416
 
417
417
  let tmpSeparatorIndex = pAddress.indexOf('.');
418
418
 
419
- if (tmpSeparatorIndex === -1)
419
+ if (tmpSeparatorIndex == -1)
420
420
  {
421
421
  // Check if it's a boxed property
422
422
  let tmpBracketStartIndex = pAddress.indexOf('[');
@@ -0,0 +1,112 @@
1
+ /**
2
+ * @license MIT
3
+ * @author <steven@velozo.com>
4
+ */
5
+ let libSimpleLog = require('./Manyfest-LogToConsole.js');
6
+
7
+ /**
8
+ * Schema Manipulation Functions
9
+ *
10
+ * @class ManyfestSchemaManipulation
11
+ */
12
+ class ManyfestSchemaManipulation
13
+ {
14
+ constructor(pInfoLog, pErrorLog)
15
+ {
16
+ // Wire in logging
17
+ this.logInfo = (typeof(pInfoLog) === 'function') ? pInfoLog : libSimpleLog;
18
+ this.logError = (typeof(pErrorLog) === 'function') ? pErrorLog : libSimpleLog;
19
+ }
20
+
21
+ // This translates the default address mappings to something different.
22
+ //
23
+ // For instance you can pass in manyfest schema descriptor object:
24
+ // {
25
+ // "Address.Of.a": { "Hash": "a", "Type": "Number" },
26
+ // "Address.Of.b": { "Hash": "b", "Type": "Number" }
27
+ // }
28
+ //
29
+ //
30
+ // And then an address mapping (basically a Hash->Address map)
31
+ // {
32
+ // "a": "New.Address.Of.a",
33
+ // "b": "New.Address.Of.b"
34
+ // }
35
+ //
36
+ // NOTE: This mutates the schema object permanently, altering the base hash.
37
+ // If there is a collision with an existing address, it can lead to overwrites.
38
+ // TODO: Discuss what should happen on collisions.
39
+ resolveAddressMappings(pManyfestSchemaDescriptors, pAddressMapping)
40
+ {
41
+ if (typeof(pManyfestSchemaDescriptors) != 'object')
42
+ {
43
+ this.logError(`Attempted to resolve address mapping but the descriptor was not an object.`);
44
+ return false;
45
+ }
46
+
47
+ if (typeof(pAddressMapping) != 'object')
48
+ {
49
+ // No mappings were passed in
50
+ return true;
51
+ }
52
+
53
+ // Get the arrays of both the schema definition and the hash mapping
54
+ let tmpManyfestAddresses = Object.keys(pManyfestSchemaDescriptors);
55
+ let tmpHashMapping = {};
56
+ tmpManyfestAddresses.forEach(
57
+ (pAddress) =>
58
+ {
59
+ if (pManyfestSchemaDescriptors[pAddress].hasOwnProperty('Hash'))
60
+ {
61
+ tmpHashMapping[pManyfestSchemaDescriptors[pAddress].Hash] = pAddress;
62
+ }
63
+ });
64
+
65
+ let tmpAddressMappingSet = Object.keys(pAddressMapping);
66
+
67
+ tmpAddressMappingSet.forEach(
68
+ (pInputAddress) =>
69
+ {
70
+ let tmpNewDescriptorAddress = pAddressMapping[pInputAddress];
71
+ let tmpOldDescriptorAddress = false;
72
+ let tmpDescriptor = false;
73
+
74
+ // See if there is a matching descriptor either by Address directly or Hash
75
+ if (pManyfestSchemaDescriptors.hasOwnProperty(pInputAddress))
76
+ {
77
+ tmpOldDescriptorAddress = pInputAddress;
78
+ }
79
+ else if (tmpHashMapping.hasOwnProperty(pInputAddress))
80
+ {
81
+ tmpOldDescriptorAddress = tmpHashMapping[pInputAddress];
82
+ }
83
+
84
+ // If there was a matching descriptor in the manifest, store it in the temporary descriptor
85
+ if (tmpOldDescriptorAddress)
86
+ {
87
+ tmpDescriptor = pManyfestSchemaDescriptors[tmpOldDescriptorAddress];
88
+ delete pManyfestSchemaDescriptors[tmpOldDescriptorAddress];
89
+ }
90
+ else
91
+ {
92
+ // Create a new descriptor! Map it to the input address.
93
+ tmpDescriptor = { Hash:pInputAddress };
94
+ }
95
+
96
+ // Now re-add the descriptor to the manyfest schema
97
+ pManyfestSchemaDescriptors[tmpNewDescriptorAddress] = tmpDescriptor;
98
+ });
99
+
100
+ return true;
101
+ }
102
+
103
+ safeResolveAddressMappings(pManyfestSchemaDescriptors, pAddressMapping)
104
+ {
105
+ // This returns the descriptors as a new object, safely remapping without mutating the original schema Descriptors
106
+ let tmpManyfestSchemaDescriptors = JSON.parse(JSON.stringify(pManyfestSchemaDescriptors));
107
+ this.resolveAddressMappings(tmpManyfestSchemaDescriptors, pAddressMapping);
108
+ return tmpManyfestSchemaDescriptors;
109
+ }
110
+ }
111
+
112
+ module.exports = ManyfestSchemaManipulation;
@@ -4,6 +4,8 @@
4
4
  */
5
5
  let libSimpleLog = require('./Manyfest-LogToConsole.js');
6
6
  let libObjectAddressResolver = require('./Manyfest-ObjectAddressResolver.js');
7
+ let libHashTranslation = require('./Manyfest-HashTranslation.js');
8
+ let libSchemaManipulation = require('./Manyfest-SchemaManipulation.js');
7
9
 
8
10
  /**
9
11
  * Manyfest object address-based descriptions and manipulations.
@@ -50,6 +52,10 @@ class Manyfest
50
52
  {
51
53
  this.loadManifest(pManifest);
52
54
  }
55
+
56
+ this.schemaManipulations = new libSchemaManipulation(this.logInfo, this.logError);
57
+
58
+ this.hashTranslations = new libHashTranslation(this.logInfo, this.logError);
53
59
  }
54
60
 
55
61
  /*************************************************************************
@@ -153,14 +159,18 @@ class Manyfest
153
159
  this.elementDescriptors[pAddress] = pDescriptor;
154
160
 
155
161
  // Always add the address as a hash
156
- // TODO: Check if this is a good idea or not.
157
- // Collisions are bound to happen with both representations of the address/hash in here.
158
162
  this.elementHashes[pAddress] = pAddress;
159
163
 
160
164
  if (pDescriptor.hasOwnProperty('Hash'))
161
165
  {
166
+ // TODO: Check if this is a good idea or not..
167
+ // Collisions are bound to happen with both representations of the address/hash in here and developers being able to create their own hashes.
162
168
  this.elementHashes[pDescriptor.Hash] = pAddress;
163
169
  }
170
+ else
171
+ {
172
+ pDescriptor.Hash = pAddress;
173
+ }
164
174
 
165
175
  return true;
166
176
  }
@@ -173,9 +183,9 @@ class Manyfest
173
183
 
174
184
  getDescriptorByHash(pHash)
175
185
  {
176
- if (this.elementHashes.hasOwnProperty(pHash))
186
+ if (this.elementHashes.hasOwnProperty(pHash) || this.hashTranslations.translationTable.hasOwnProperty(pHash))
177
187
  {
178
- return this.getDescriptor(this.elementHashes[pHash]);
188
+ return this.getDescriptor(this.elementHashes[this.hashTranslations.translate(pHash)]);
179
189
  }
180
190
  else
181
191
  {
@@ -195,9 +205,9 @@ class Manyfest
195
205
  // Check if an element exists by its hash
196
206
  checkAddressExistsByHash (pObject, pHash)
197
207
  {
198
- if (this.elementHashes.hasOwnProperty(pHash))
208
+ if (this.elementHashes.hasOwnProperty(pHash) || this.hashTranslations.translationTable.hasOwnProperty(pHash))
199
209
  {
200
- return this.checkAddressExists(pObject, this.elementHashes[pHash]);
210
+ return this.checkAddressExists(pObject, this.elementHashes[this.hashTranslations.translate(pHash)]);
201
211
  }
202
212
  else
203
213
  {
@@ -216,9 +226,9 @@ class Manyfest
216
226
  // Get the value of an element by its hash
217
227
  getValueByHash (pObject, pHash)
218
228
  {
219
- if (this.elementHashes.hasOwnProperty(pHash))
229
+ if (this.elementHashes.hasOwnProperty(pHash) || this.hashTranslations.translationTable.hasOwnProperty(pHash))
220
230
  {
221
- return this.getValueAtAddress(pObject, this.elementHashes[pHash]);
231
+ return this.getValueAtAddress(pObject, this.elementHashes[this.hashTranslations.translate(pHash)]);
222
232
  }
223
233
  else
224
234
  {
@@ -236,9 +246,9 @@ class Manyfest
236
246
  // Set the value of an element by its hash
237
247
  setValueByHash(pObject, pHash, pValue)
238
248
  {
239
- if (this.elementHashes.hasOwnProperty(pHash))
249
+ if (this.elementHashes.hasOwnProperty(pHash) || this.hashTranslations.translationTable.hasOwnProperty(pHash))
240
250
  {
241
- return this.setValueAtAddress(pObject, this.elementHashes[pHash], pValue);
251
+ return this.setValueAtAddress(pObject, this.elementHashes[this.hashTranslations.translate(pHash)], pValue);
242
252
  }
243
253
  else
244
254
  {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Unit tests for Meadow
2
+ * Unit tests for Manyfest
3
3
  *
4
4
  * @license MIT
5
5
  *
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Unit tests for Manyfest
3
+ *
4
+ * @license MIT
5
+ *
6
+ * @author Steven Velozo <steven@velozo.com>
7
+ */
8
+
9
+ var Chai = require("chai");
10
+ var Expect = Chai.expect;
11
+
12
+ let libManyfest = require('../source/Manyfest.js');
13
+
14
+ let _SampleDataArchiveOrgFrankenberry = require('./Data-Archive-org-Frankenberry.json');
15
+
16
+ suite
17
+ (
18
+ 'Manyfest Hash Translations',
19
+ function()
20
+ {
21
+ setup (()=> {} );
22
+
23
+ suite
24
+ (
25
+ 'Translation Operations',
26
+ ()=>
27
+ {
28
+ test
29
+ (
30
+ 'A simple hash translation.',
31
+ (fTestComplete)=>
32
+ {
33
+ let _Manyfest = new libManyfest({ Scope:'Archive.org', Descriptors: {'metadata.creator': {Name:'Creator', Hash:'Creator'}}});
34
+ // Property not schema, accessed by hash:
35
+ let tmpCreator = _Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Creator');
36
+ Expect(tmpCreator)
37
+ .to.equal('General Mills');
38
+ // Create a translation between "Creator" and "Director"
39
+ _Manyfest.hashTranslations.addTranslation({"Director":"Creator"});
40
+ // Creator should still work
41
+ tmpCreator = _Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Creator');
42
+ Expect(tmpCreator)
43
+ .to.equal('General Mills');
44
+ // Director should also work
45
+ tmpCreator = _Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Director');
46
+ Expect(tmpCreator)
47
+ .to.equal('General Mills');
48
+
49
+ fTestComplete();
50
+ }
51
+ );
52
+ test
53
+ (
54
+ 'Multiple translations.',
55
+ (fTestComplete)=>
56
+ {
57
+ let _Manyfest = new libManyfest({ Scope:'Archive.org', Descriptors: {'metadata.creator': {Name:'Creator', Hash:'Creator'}}});
58
+ // Property not schema, accessed by hash:
59
+ let tmpCreator = _Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Creator');
60
+ Expect(tmpCreator).to.equal('General Mills');
61
+ // Create a translation between "Creator" and "Director" as well as "Author"
62
+ _Manyfest.hashTranslations.addTranslation({"Director":"Creator", "Author":"Creator"});
63
+ // Creator should still work
64
+ tmpCreator = _Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Creator');
65
+ Expect(tmpCreator).to.equal('General Mills');
66
+ // Director should also work
67
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Director')).to.equal('General Mills');
68
+ // And Author!
69
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Author')).to.equal('General Mills');
70
+
71
+ fTestComplete();
72
+ }
73
+ );
74
+ test
75
+ (
76
+ 'Remove a translation.',
77
+ (fTestComplete)=>
78
+ {
79
+ let _Manyfest = new libManyfest({ Scope:'Archive.org', Descriptors: {'metadata.creator': {Name:'Creator', Hash:'Creator'}}});
80
+ // Property not schema, accessed by hash:
81
+ let tmpCreator = _Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Creator');
82
+ Expect(tmpCreator).to.equal('General Mills');
83
+ // Create a translation between "Creator" and "Director" as well as "Author"
84
+ _Manyfest.hashTranslations.addTranslation({"Director":"Creator", "Author":"Creator"});
85
+ Expect(tmpCreator).to.equal('General Mills');
86
+ // Director should also work
87
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Director')).to.equal('General Mills');
88
+ // And Author!
89
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Author')).to.equal('General Mills');
90
+ // Now remove Director
91
+ _Manyfest.hashTranslations.removeTranslation('Director');
92
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Author')).to.equal('General Mills');
93
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Director')).to.equal(undefined);
94
+
95
+ fTestComplete();
96
+ }
97
+ );
98
+ test
99
+ (
100
+ 'Remove multiple translations.',
101
+ (fTestComplete)=>
102
+ {
103
+ let _Manyfest = new libManyfest({ Scope:'Archive.org', Descriptors: {'metadata.creator': {Name:'Creator', Hash:'Creator'}}});
104
+ // Property not schema, accessed by hash:
105
+ let tmpCreator = _Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Creator');
106
+ Expect(tmpCreator).to.equal('General Mills');
107
+ // Create a translation between "Creator" and "Director" as well as "Author"
108
+ _Manyfest.hashTranslations.addTranslation({"Director":"Creator", "Author":"Creator", "Songwriter":"Creator"});
109
+ Expect(tmpCreator).to.equal('General Mills');
110
+ // Director should also work
111
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Director')).to.equal('General Mills');
112
+ // And Author!
113
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Author')).to.equal('General Mills');
114
+ // Now remove Director
115
+ _Manyfest.hashTranslations.removeTranslation({'Director':true,'Author':'TheseValuesDontMatter'});
116
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Author')).to.equal(undefined);
117
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Director')).to.equal(undefined);
118
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Songwriter')).to.equal('General Mills');
119
+
120
+ fTestComplete();
121
+ }
122
+ );
123
+ test
124
+ (
125
+ 'Remove all translations.',
126
+ (fTestComplete)=>
127
+ {
128
+ let _Manyfest = new libManyfest({ Scope:'Archive.org', Descriptors: {'metadata.creator': {Name:'Creator', Hash:'Creator'}}});
129
+ // Property not schema, accessed by hash:
130
+ let tmpCreator = _Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Creator');
131
+ Expect(tmpCreator).to.equal('General Mills');
132
+ // Create a translation between "Creator" and "Director" as well as "Author"
133
+ _Manyfest.hashTranslations.addTranslation({"Director":"Creator", "Author":"Creator", "Songwriter":"Creator"});
134
+ Expect(tmpCreator).to.equal('General Mills');
135
+ // Director should also work
136
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Director')).to.equal('General Mills');
137
+ // And Author!
138
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Author')).to.equal('General Mills');
139
+ // Now remove Director
140
+ _Manyfest.hashTranslations.clearTranslations();
141
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Author')).to.equal(undefined);
142
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Director')).to.equal(undefined);
143
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Songwriter')).to.equal(undefined);
144
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Creator')).to.equal('General Mills');
145
+
146
+ fTestComplete();
147
+ }
148
+ );
149
+ test
150
+ (
151
+ 'Add a bogus translation.',
152
+ (fTestComplete)=>
153
+ {
154
+ let _Manyfest = new libManyfest({ Scope:'Archive.org', Descriptors: {'metadata.creator': {Name:'Creator', Hash:'Creator'}}});
155
+
156
+ Expect(_Manyfest.hashTranslations.addTranslation('THIS SHOULD BE AN OBJECT')).to.equal(false);
157
+
158
+ Expect(_Manyfest.hashTranslations.translationCount()).to.equal(0);
159
+
160
+ fTestComplete();
161
+ }
162
+ );
163
+ }
164
+ );
165
+ }
166
+ );
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Unit tests for Meadow
2
+ * Unit tests for Manyfest
3
3
  *
4
4
  * @license MIT
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Unit tests for Meadow
2
+ * Unit tests for Manyfest
3
3
  *
4
4
  * @license MIT
5
5
  *
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Unit tests for Manyfest
3
+ *
4
+ * @license MIT
5
+ *
6
+ * @author Steven Velozo <steven@velozo.com>
7
+ */
8
+
9
+ var Chai = require("chai");
10
+ var Expect = Chai.expect;
11
+
12
+ let libManyfest = require('../source/Manyfest.js');
13
+
14
+ let _SampleDataArchiveOrgFrankenberry = require('./Data-Archive-org-Frankenberry.json');
15
+
16
+ suite
17
+ (
18
+ 'Manyfest Schema Manipulation',
19
+ function()
20
+ {
21
+ setup (()=> {} );
22
+
23
+ suite
24
+ (
25
+ 'Address Mapping Resolution',
26
+ ()=>
27
+ {
28
+ test
29
+ (
30
+ 'We should be able to remap properties in place.',
31
+ (fTestComplete)=>
32
+ {
33
+ let tmpSchemaDescriptors = (
34
+ {
35
+ "a": { "Hash": "a", "Type": "Number" },
36
+ "b": { "Hash": "b", "Type": "Number" }
37
+ });
38
+
39
+ let tmpTranslationTable = (
40
+ {
41
+ "a": "CarrotCost",
42
+ "b": "AppleCost"
43
+ });
44
+
45
+ Expect(tmpSchemaDescriptors.a.Hash).to.equal('a');
46
+
47
+ let _Manyfest = new libManyfest();
48
+ // Now remap the schema (in-place)
49
+ _Manyfest.schemaManipulations.resolveAddressMappings(tmpSchemaDescriptors, tmpTranslationTable);
50
+
51
+ // The schema should be fundamentally altered to point these addresses to the old hashes
52
+ Expect(tmpSchemaDescriptors.CarrotCost.Hash).to.equal('a');
53
+ Expect(tmpSchemaDescriptors.AppleCost.Hash).to.equal('b');
54
+
55
+ fTestComplete();
56
+ }
57
+ );
58
+ test
59
+ (
60
+ 'We should be able to remap properties safely.',
61
+ (fTestComplete)=>
62
+ {
63
+ let tmpSchemaDescriptors = (
64
+ {
65
+ "a": { "Hash": "a", "Type": "Number" },
66
+ "b": { "Hash": "b", "Type": "Number" }
67
+ });
68
+
69
+ let tmpTranslationTable = (
70
+ {
71
+ "a": "CarrotCost",
72
+ "b": "AppleCost"
73
+ });
74
+
75
+ Expect(tmpSchemaDescriptors.a.Hash).to.equal('a');
76
+
77
+ let _Manyfest = new libManyfest();
78
+ // Now remap the schema (in-place)
79
+ let tmpNewSchemaDescriptors = _Manyfest.schemaManipulations.safeResolveAddressMappings(tmpSchemaDescriptors, tmpTranslationTable);
80
+
81
+ // The schema should be safe
82
+ Expect(tmpSchemaDescriptors.a.Hash).to.equal('a');
83
+ // And a new schema should have been created with the alterations
84
+ Expect(tmpNewSchemaDescriptors.CarrotCost.Hash).to.equal('a');
85
+ Expect(tmpNewSchemaDescriptors.AppleCost.Hash).to.equal('b');
86
+
87
+ fTestComplete();
88
+ }
89
+ );
90
+ }
91
+ );
92
+ }
93
+ );
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Unit tests for Meadow
2
+ * Unit tests for Manyfest
3
3
  *
4
4
  * @license MIT
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Unit tests for Meadow
2
+ * Unit tests for Manyfest
3
3
  *
4
4
  * @license MIT
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Unit tests for Meadow
2
+ * Unit tests for Manyfest
3
3
  *
4
4
  * @license MIT
5
5
  *