manyfest 1.0.4 → 1.0.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "manyfest",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "JSON Object Manifest for Data Description and Parsing",
5
5
  "main": "source/Manyfest.js",
6
6
  "scripts": {
@@ -107,6 +107,32 @@ class ManyfestSchemaManipulation
107
107
  this.resolveAddressMappings(tmpManyfestSchemaDescriptors, pAddressMapping);
108
108
  return tmpManyfestSchemaDescriptors;
109
109
  }
110
+
111
+ mergeAddressMappings(pManyfestSchemaDescriptorsDestination, pManyfestSchemaDescriptorsSource)
112
+ {
113
+ if ((typeof(pManyfestSchemaDescriptorsSource) != 'object') || (typeof(pManyfestSchemaDescriptorsDestination) != 'object'))
114
+ {
115
+ this.logError(`Attempted to merge two schema descriptors but both were not objects.`);
116
+ return false;
117
+ }
118
+
119
+ let tmpSource = JSON.parse(JSON.stringify(pManyfestSchemaDescriptorsSource));
120
+ let tmpNewManyfestSchemaDescriptors = JSON.parse(JSON.stringify(pManyfestSchemaDescriptorsDestination));
121
+
122
+ // The first passed-in set of descriptors takes precedence.
123
+ let tmpDescriptorAddresses = Object.keys(tmpSource);
124
+
125
+ tmpDescriptorAddresses.forEach(
126
+ (pDescriptorAddress) =>
127
+ {
128
+ if (!tmpNewManyfestSchemaDescriptors.hasOwnProperty(pDescriptorAddress))
129
+ {
130
+ tmpNewManyfestSchemaDescriptors[pDescriptorAddress] = tmpSource[pDescriptorAddress];
131
+ }
132
+ });
133
+
134
+ return tmpNewManyfestSchemaDescriptors;
135
+ }
110
136
  }
111
137
 
112
138
  module.exports = ManyfestSchemaManipulation;
@@ -71,6 +71,19 @@ class Manyfest
71
71
  this.elementDescriptors = {};
72
72
  }
73
73
 
74
+ clone()
75
+ {
76
+ // Make a copy of the options in-place
77
+ let tmpNewOptions = JSON.parse(JSON.stringify(this.options));
78
+
79
+ let tmpNewManyfest = new Manyfest(this.getManifest(), this.logInfo, this.logError, tmpNewOptions);
80
+
81
+ // Import the hash translations
82
+ tmpNewManyfest.hashTranslations.addTranslation(this.hashTranslations.translationTable);
83
+
84
+ return tmpNewManyfest;
85
+ }
86
+
74
87
  // Deserialize a Manifest from a string
75
88
  deserialize(pManifestString)
76
89
  {
@@ -125,6 +138,7 @@ class Manyfest
125
138
  }
126
139
 
127
140
  // Serialize the Manifest to a string
141
+ // TODO: Should this also serialize the translation table?
128
142
  serialize()
129
143
  {
130
144
  return JSON.stringify(this.getManifest());
@@ -132,7 +146,7 @@ class Manyfest
132
146
 
133
147
  getManifest()
134
148
  {
135
- let tmpManifest = (
149
+ return (
136
150
  {
137
151
  Scope: this.scope,
138
152
  Descriptors: JSON.parse(JSON.stringify(this.elementDescriptors))
@@ -183,15 +197,7 @@ class Manyfest
183
197
 
184
198
  getDescriptorByHash(pHash)
185
199
  {
186
- if (this.elementHashes.hasOwnProperty(pHash) || this.hashTranslations.translationTable.hasOwnProperty(pHash))
187
- {
188
- return this.getDescriptor(this.elementHashes[this.hashTranslations.translate(pHash)]);
189
- }
190
- else
191
- {
192
- this.logError(`(${this.scope}) Error in getDescriptorByHash; the Hash ${pHash} doesn't exist in the schema.`);
193
- return undefined;
194
- }
200
+ return this.getDescriptor(this.resolveHashAddress(pHash));
195
201
  }
196
202
 
197
203
  getDescriptor(pAddress)
@@ -205,15 +211,7 @@ class Manyfest
205
211
  // Check if an element exists by its hash
206
212
  checkAddressExistsByHash (pObject, pHash)
207
213
  {
208
- if (this.elementHashes.hasOwnProperty(pHash) || this.hashTranslations.translationTable.hasOwnProperty(pHash))
209
- {
210
- return this.checkAddressExists(pObject, this.elementHashes[this.hashTranslations.translate(pHash)]);
211
- }
212
- else
213
- {
214
- this.logError(`(${this.scope}) Error in checkAddressExistsByHash; the Hash ${pHash} doesn't exist in the schema.`);
215
- return undefined;
216
- }
214
+ return this.checkAddressExists(pObject,this.resolveHashAddress(pHash));
217
215
  }
218
216
 
219
217
  // Check if an element exists at an address
@@ -222,19 +220,43 @@ class Manyfest
222
220
  return this.objectAddressResolver.checkAddressExists(pObject, pAddress);
223
221
  }
224
222
 
225
-
226
- // Get the value of an element by its hash
227
- getValueByHash (pObject, pHash)
223
+ // Turn a hash into an address, factoring in the translation table.
224
+ resolveHashAddress(pHash)
228
225
  {
229
- if (this.elementHashes.hasOwnProperty(pHash) || this.hashTranslations.translationTable.hasOwnProperty(pHash))
226
+ let tmpAddress = undefined;
227
+
228
+ let tmpInElementHashTable = this.elementHashes.hasOwnProperty(pHash);
229
+ let tmpInTranslationTable = this.hashTranslations.translationTable.hasOwnProperty(pHash);
230
+
231
+ // The most straightforward: the hash exists, no translations.
232
+ if (tmpInElementHashTable && !tmpInTranslationTable)
233
+ {
234
+ tmpAddress = this.elementHashes[pHash];
235
+ }
236
+ // There is a translation from one hash to another, and, the elementHashes contains the pointer end
237
+ else if (tmpInTranslationTable && this.elementHashes.hasOwnProperty(this.hashTranslations.translate(pHash)))
230
238
  {
231
- return this.getValueAtAddress(pObject, this.elementHashes[this.hashTranslations.translate(pHash)]);
239
+ tmpAddress = this.elementHashes[this.hashTranslations.translate(pHash)];
232
240
  }
241
+ // Use the level of indirection only in the Translation Table
242
+ else if (tmpInTranslationTable)
243
+ {
244
+ tmpAddress = this.hashTranslations.translate(pHash);
245
+ }
246
+ // Just treat the hash as an address.
247
+ // TODO: Discuss this ... it is magic but controversial
233
248
  else
234
249
  {
235
- this.logError(`(${this.scope}) Error in getValueByHash; the Hash ${pHash} doesn't exist in the schema.`);
236
- return undefined;
250
+ tmpAddress = pHash;
237
251
  }
252
+
253
+ return tmpAddress;
254
+ }
255
+
256
+ // Get the value of an element by its hash
257
+ getValueByHash (pObject, pHash)
258
+ {
259
+ return this.getValueAtAddress(pObject, this.resolveHashAddress(pHash));
238
260
  }
239
261
 
240
262
  // Get the value of an element at an address
@@ -246,15 +268,7 @@ class Manyfest
246
268
  // Set the value of an element by its hash
247
269
  setValueByHash(pObject, pHash, pValue)
248
270
  {
249
- if (this.elementHashes.hasOwnProperty(pHash) || this.hashTranslations.translationTable.hasOwnProperty(pHash))
250
- {
251
- return this.setValueAtAddress(pObject, this.elementHashes[this.hashTranslations.translate(pHash)], pValue);
252
- }
253
- else
254
- {
255
- this.logError(`(${this.scope}) Error in setValueByHash; the Hash ${pHash} doesn't exist in the schema. Value ${pValue} will not be written!`);
256
- return undefined;
257
- }
271
+ return this.setValueAtAddress(pObject, this.resolveHashAddress(pHash), pValue);
258
272
  }
259
273
 
260
274
 
@@ -147,6 +147,22 @@ suite
147
147
  }
148
148
  );
149
149
  test
150
+ (
151
+ 'Translate to a value not in the hashes, falling back to address.',
152
+ (fTestComplete)=>
153
+ {
154
+ let _Manyfest = new libManyfest({ Scope:'Archive.org', Descriptors: {'metadata.creator': {Name:'Creator', Hash:'Creator'}}});
155
+ // Create a translation between "Creator" and "metadata.identifier", which isn't in the manifest in any way
156
+ _Manyfest.hashTranslations.addTranslation({"Creator":"metadata.identifier"});
157
+ // This address is not in the descriptor address list or the hash list
158
+ Expect(_Manyfest.getValueAtAddress(_SampleDataArchiveOrgFrankenberry, 'metadata.identifier')).to.equal('FrankenberryCountChoculaTevevisionCommercial1971');
159
+ // But now we've pointed the Creator hash to it!
160
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Creator')).to.equal('FrankenberryCountChoculaTevevisionCommercial1971');
161
+
162
+ fTestComplete();
163
+ }
164
+ );
165
+ test
150
166
  (
151
167
  'Add a bogus translation.',
152
168
  (fTestComplete)=>
@@ -84,6 +84,116 @@ suite
84
84
  Expect(tmpNewSchemaDescriptors.CarrotCost.Hash).to.equal('a');
85
85
  Expect(tmpNewSchemaDescriptors.AppleCost.Hash).to.equal('b');
86
86
 
87
+ fTestComplete();
88
+ }
89
+ );
90
+ test
91
+ (
92
+ 'We should be able to merge properties safely.',
93
+ (fTestComplete)=>
94
+ {
95
+ let tmpSchemaDescriptors = (
96
+ {
97
+ "a": { "Hash": "a", "Type": "Number" },
98
+ "b": { "Hash": "b", "Type": "Number" }
99
+ });
100
+
101
+ let tmpSchemaDescriptorsToMerge = (
102
+ {
103
+ "c": { "Hash": "c" },
104
+ "d": { "Hash": "d" },
105
+ "e": { "Hash": "e" },
106
+ "a": { "Hash": "ARBUCKLE", "Type": "Number" }
107
+ });
108
+
109
+ Expect(tmpSchemaDescriptors.a.Hash).to.equal('a');
110
+
111
+ let _Manyfest = new libManyfest();
112
+ // Now remap the schema (in-place)
113
+ let tmpNewSchemaDescriptors = _Manyfest.schemaManipulations.mergeAddressMappings(tmpSchemaDescriptors, tmpSchemaDescriptorsToMerge);
114
+
115
+ // The schema should be safe
116
+ Expect(tmpNewSchemaDescriptors.a.Hash).to.equal('a');
117
+ // And a new schema should have been created with the alterations
118
+ Expect(tmpNewSchemaDescriptors.b.Hash).to.equal('b');
119
+ Expect(tmpNewSchemaDescriptors.c.Hash).to.equal('c');
120
+
121
+ fTestComplete();
122
+ }
123
+ );
124
+ test
125
+ (
126
+ 'Cloning should work.',
127
+ (fTestComplete)=>
128
+ {
129
+ let tmpSchemaDescriptors = (
130
+ {
131
+ "a": { "Hash": "a", "Type": "Number" },
132
+ "b": { "Hash": "b", "Type": "Number" }
133
+ });
134
+
135
+ let tmpTranslationTable = (
136
+ {
137
+ "a": "CarrotCost",
138
+ "b": "AppleCost"
139
+ });
140
+
141
+ let _Manyfest = new libManyfest({ Scope:'Archive.org', Descriptors: {'metadata.creator': {Name:'Creator', Hash:'Creator'}}});
142
+ // Property not schema, accessed by hash:
143
+ let tmpCreator = _Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Creator');
144
+ Expect(tmpCreator).to.equal('General Mills');
145
+ let _ClonedManyfest = _Manyfest.clone();
146
+ Expect(_ClonedManyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Creator')).to.equal('General Mills');
147
+
148
+ fTestComplete();
149
+ }
150
+ );
151
+ test
152
+ (
153
+ 'Cloning should take into account translation.',
154
+ (fTestComplete)=>
155
+ {
156
+ let tmpSchemaDescriptors = (
157
+ {
158
+ "a": { "Hash": "a", "Type": "Number" },
159
+ "b": { "Hash": "b", "Type": "Number" }
160
+ });
161
+
162
+ let tmpTranslationTable = (
163
+ {
164
+ "a": "CarrotCost",
165
+ "b": "AppleCost"
166
+ });
167
+
168
+ let _Manyfest = new libManyfest({ Scope:'Archive.org', Descriptors: {'metadata.creator': {Name:'Creator', Hash:'Creator'}}});
169
+ // Property not schema, accessed by hash:
170
+ let tmpCreator = _Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Creator');
171
+ Expect(tmpCreator).to.equal('General Mills');
172
+ // Create a translation between "Creator" and "Director" as well as "Author"
173
+ _Manyfest.hashTranslations.addTranslation({"Director":"Creator", "Author":"Creator", "Songwriter":"Creator"});
174
+ Expect(tmpCreator).to.equal('General Mills');
175
+ // Director should also work
176
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Director')).to.equal('General Mills');
177
+ // And Author!
178
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Author')).to.equal('General Mills');
179
+ // Now remove Director
180
+ _Manyfest.hashTranslations.clearTranslations();
181
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Author')).to.equal(undefined);
182
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Director')).to.equal(undefined);
183
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Songwriter')).to.equal(undefined);
184
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Creator')).to.equal('General Mills');
185
+
186
+ let _ClonedManyfest = _Manyfest.clone();
187
+ Expect(_ClonedManyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Author')).to.equal(undefined);
188
+ Expect(_ClonedManyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Director')).to.equal(undefined);
189
+ Expect(_ClonedManyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Songwriter')).to.equal(undefined);
190
+ Expect(_ClonedManyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Creator')).to.equal('General Mills');
191
+
192
+ // New translations should not affect the old manyfest
193
+ _ClonedManyfest.hashTranslations.addTranslation({"Director":"Creator", "Author":"Creator", "Songwriter":"Creator"});
194
+ Expect(_ClonedManyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Director')).to.equal('General Mills');
195
+ Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Director')).to.equal(undefined);
196
+
87
197
  fTestComplete();
88
198
  }
89
199
  );