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
|
@@ -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;
|
package/source/Manyfest.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
227
|
-
getValueByHash (pObject, pHash)
|
|
223
|
+
// Turn a hash into an address, factoring in the translation table.
|
|
224
|
+
resolveHashAddress(pHash)
|
|
228
225
|
{
|
|
229
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
);
|