manyfest 1.0.7 → 1.0.8

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
  bind-addr: 127.0.0.1:8080
2
2
  auth: password
3
- password: luxury
3
+ password: retold
4
4
  cert: false
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "manyfest",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "JSON Object Manifest for Data Description and Parsing",
5
5
  "main": "source/Manyfest.js",
6
6
  "scripts": {
@@ -0,0 +1,123 @@
1
+ /**
2
+ * @license MIT
3
+ * @author <steven@velozo.com>
4
+ */
5
+ let libSimpleLog = require('./Manyfest-LogToConsole.js');
6
+
7
+ /**
8
+ * Object Address Generation
9
+ *
10
+ * Automagically generate addresses and properties based on a passed-in object,
11
+ * to be used for easy creation of schemas. Meant to simplify the lives of
12
+ * developers wanting to create schemas without typing a bunch of stuff.
13
+ *
14
+ * IMPORTANT NOTE: This code is intentionally more verbose than necessary, to
15
+ * be extremely clear what is going on in the recursion for
16
+ * each of the three address resolution functions.
17
+ *
18
+ * Although there is some opportunity to repeat ourselves a
19
+ * bit less in this codebase (e.g. with detection of arrays
20
+ * versus objects versus direct properties), it can make
21
+ * debugging.. challenging. The minified version of the code
22
+ * optimizes out almost anything repeated in here. So please
23
+ * be kind and rewind... meaning please keep the codebase less
24
+ * terse and more verbose so humans can comprehend it.
25
+ *
26
+ *
27
+ * @class ManyfestObjectAddressGeneration
28
+ */
29
+ class ManyfestObjectAddressGeneration
30
+ {
31
+ constructor(pInfoLog, pErrorLog)
32
+ {
33
+ // Wire in logging
34
+ this.logInfo = (typeof(pInfoLog) == 'function') ? pInfoLog : libSimpleLog;
35
+ this.logError = (typeof(pErrorLog) == 'function') ? pErrorLog : libSimpleLog;
36
+ }
37
+
38
+ // generateAddressses
39
+ //
40
+ // This flattens an object into a set of key:value pairs for *EVERY SINGLE
41
+ // POSSIBLE ADDRESS* in the object. It can get ... really insane really
42
+ // quickly. This is not meant to be used directly to generate schemas, but
43
+ // instead as a starting point for scripts or UIs.
44
+ //
45
+ // This will return a mega set of key:value pairs with all possible schema
46
+ // permutations and default values (when not an object) and everything else.
47
+ generateAddressses (pObject, pBaseAddress, pSchema)
48
+ {
49
+ let tmpBaseAddress = (typeof(pBaseAddress) == 'string') ? pBaseAddress : '';
50
+ let tmpSchema = (typeof(pSchema) == 'object') ? pSchema : {};
51
+
52
+ let tmpObjectType = typeof(pObject);
53
+
54
+ let tmpSchemaObjectEntry = (
55
+ {
56
+ Address: tmpBaseAddress,
57
+ Hash: tmpBaseAddress,
58
+ Name: tmpBaseAddress,
59
+ // This is so scripts and UI controls can force a developer to opt-in.
60
+ InSchema: false
61
+ }
62
+ )
63
+
64
+ switch(tmpObjectType)
65
+ {
66
+ case 'string':
67
+ tmpSchemaObjectEntry.DataType = 'String';
68
+ tmpSchemaObjectEntry.Default = pObject;
69
+ tmpSchema[tmpBaseAddress] = tmpSchemaObjectEntry;
70
+ break;
71
+ case 'number':
72
+ case 'bigint':
73
+ tmpSchemaObjectEntry.DataType = 'Number';
74
+ tmpSchemaObjectEntry.Default = pObject;
75
+ tmpSchema[tmpBaseAddress] = tmpSchemaObjectEntry;
76
+ break;
77
+ case 'undefined':
78
+ tmpSchemaObjectEntry.DataType = 'Any';
79
+ tmpSchemaObjectEntry.Default = pObject;
80
+ tmpSchema[tmpBaseAddress] = tmpSchemaObjectEntry;
81
+ break;
82
+ case 'object':
83
+ if (Array.isArray(pObject))
84
+ {
85
+ tmpSchemaObjectEntry.DataType = 'Array';
86
+ if (tmpBaseAddress != '')
87
+ {
88
+ tmpSchema[tmpBaseAddress] = tmpSchemaObjectEntry;
89
+ }
90
+
91
+ for (let i = 0; i < pObject.length; i++)
92
+ {
93
+ this.generateAddressses(pObject[i], `${tmpBaseAddress}[${i}]`, tmpSchema);
94
+ }
95
+ }
96
+ else
97
+ {
98
+ tmpSchemaObjectEntry.DataType = 'Object';
99
+ if (tmpBaseAddress != '')
100
+ {
101
+ tmpSchema[tmpBaseAddress] = tmpSchemaObjectEntry;
102
+ tmpBaseAddress += '.';
103
+ }
104
+
105
+ let tmpObjectProperties = Object.keys(pObject);
106
+
107
+ for (let i = 0; i < tmpObjectProperties.length; i++)
108
+ {
109
+ this.generateAddressses(pObject[tmpObjectProperties[i]], `${tmpBaseAddress}${tmpObjectProperties[i]}`, tmpSchema);
110
+ }
111
+ }
112
+ break;
113
+ case 'symbol':
114
+ case 'function':
115
+ // Symbols and functions neither recurse nor get added to the schema
116
+ break;
117
+ }
118
+
119
+ return tmpSchema;
120
+ }
121
+ };
122
+
123
+ module.exports = ManyfestObjectAddressGeneration;
@@ -3,10 +3,13 @@
3
3
  * @author <steven@velozo.com>
4
4
  */
5
5
  let libSimpleLog = require('./Manyfest-LogToConsole.js');
6
- let libObjectAddressResolver = require('./Manyfest-ObjectAddressResolver.js');
6
+
7
7
  let libHashTranslation = require('./Manyfest-HashTranslation.js');
8
+ let libObjectAddressResolver = require('./Manyfest-ObjectAddressResolver.js');
9
+ let libObjectAddressGeneration = require('./Manyfest-ObjectAddressGeneration.js');
8
10
  let libSchemaManipulation = require('./Manyfest-SchemaManipulation.js');
9
11
 
12
+
10
13
  /**
11
14
  * Manyfest object address-based descriptions and manipulations.
12
15
  *
@@ -54,6 +57,7 @@ class Manyfest
54
57
  }
55
58
 
56
59
  this.schemaManipulations = new libSchemaManipulation(this.logInfo, this.logError);
60
+ this.objectAddressGeneration = new libObjectAddressGeneration(this.logInfo, this.logError);
57
61
 
58
62
  this.hashTranslations = new libHashTranslation(this.logInfo, this.logError);
59
63
  }
@@ -256,13 +260,29 @@ class Manyfest
256
260
  // Get the value of an element by its hash
257
261
  getValueByHash (pObject, pHash)
258
262
  {
259
- return this.getValueAtAddress(pObject, this.resolveHashAddress(pHash));
263
+ let tmpValue = this.getValueAtAddress(pObject, this.resolveHashAddress(pHash));
264
+
265
+ if (typeof(tmpValue) == 'undefined')
266
+ {
267
+ // Try to get a default if it exists
268
+ tmpValue = this.getDefaultValue(this.getDescriptorByHash(pHash));
269
+ }
270
+
271
+ return tmpValue;
260
272
  }
261
273
 
262
274
  // Get the value of an element at an address
263
275
  getValueAtAddress (pObject, pAddress)
264
276
  {
265
- return this.objectAddressResolver.getValueAtAddress(pObject, pAddress);
277
+ let tmpValue = this.objectAddressResolver.getValueAtAddress(pObject, pAddress);
278
+
279
+ if (typeof(tmpValue) == 'undefined')
280
+ {
281
+ // Try to get a default if it exists
282
+ tmpValue = this.getDefaultValue(this.getDescriptor(pAddress));
283
+ }
284
+
285
+ return tmpValue;
266
286
  }
267
287
 
268
288
  // Set the value of an element by its hash
@@ -304,9 +324,10 @@ class Manyfest
304
324
  for (let i = 0; i < this.elementAddresses.length; i++)
305
325
  {
306
326
  let tmpDescriptor = this.getDescriptor(this.elementAddresses[i]);
327
+ let tmpValueExists = this.checkAddressExists(pObject, tmpDescriptor.Address);
307
328
  let tmpValue = this.getValueAtAddress(pObject, tmpDescriptor.Address);
308
329
 
309
- if (typeof(tmpValue) == 'undefined')
330
+ if ((typeof(tmpValue) == 'undefined') || !tmpValueExists)
310
331
  {
311
332
  // This will technically mean that `Object.Some.Value = undefined` will end up showing as "missing"
312
333
  // TODO: Do we want to do a different message based on if the property exists but is undefined?
@@ -385,6 +406,11 @@ class Manyfest
385
406
  // Returns a default value, or, the default value for the data type (which is overridable with configuration)
386
407
  getDefaultValue(pDescriptor)
387
408
  {
409
+ if (typeof(pDescriptor) != 'object')
410
+ {
411
+ return undefined;
412
+ }
413
+
388
414
  if (pDescriptor.hasOwnProperty('Default'))
389
415
  {
390
416
  return pDescriptor.Default;
@@ -57,7 +57,7 @@ suite
57
57
  );
58
58
  test
59
59
  (
60
- 'Exercise more hash accesss scenarios..',
60
+ 'Return default values when none are supplied.',
61
61
  (fTestComplete)=>
62
62
  {
63
63
  let animalManyfest = new libManyfest(
@@ -79,13 +79,19 @@ suite
79
79
  "Name":"Comfortable Environmental Temperature",
80
80
  "NameShort":"Comf Env Temp",
81
81
  "Hash":"ComfET",
82
- "Description":"The most comfortable temperature for this animal to survive in."
82
+ "Description":"The most comfortable temperature for this animal to survive in.",
83
+ "Default": "96.8"
83
84
  }
84
85
  }
85
86
  });
86
87
 
87
- Expect(animalManyfest.getValueByHash({MedicalStats: { Temps: { CET:200 }},Name:'Froggy'}, 'ComfET'))
88
- .to.equal(200);
88
+ Expect(animalManyfest.getValueByHash({MedicalStats: { Temps: { CET:200 }},Name:'Froggy'}, 'ComfET')).to.equal(200);
89
+ Expect(animalManyfest.getValueByHash({MedicalStats: { Temps: { MinET:200 }},Name:'Froggy'}, 'ComfET')).to.equal('96.8');
90
+ Expect(animalManyfest.getValueByHash({MedicalStats: { Temps: { MinET:200 }},Name:'Froggy'}, 'CurrentTemperature')).to.equal(undefined);
91
+
92
+ Expect(animalManyfest.getValueAtAddress({MedicalStats: { Temps: { CET:200 }},Name:'Froggy'}, 'MedicalStats.Temps.CET')).to.equal(200);
93
+ Expect(animalManyfest.getValueAtAddress({MedicalStats: { Temps: { MinET:200 }},Name:'Froggy'}, 'MedicalStats.Temps.CET')).to.equal('96.8');
94
+ Expect(animalManyfest.getValueAtAddress({MedicalStats: { Temps: { MinET:200 }},Name:'Froggy'}, 'MedicalStats.Temps.HighET')).to.equal(undefined);
89
95
 
90
96
  fTestComplete();
91
97
  }
@@ -194,6 +194,52 @@ suite
194
194
  Expect(_ClonedManyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Director')).to.equal('General Mills');
195
195
  Expect(_Manyfest.getValueByHash(_SampleDataArchiveOrgFrankenberry, 'Director')).to.equal(undefined);
196
196
 
197
+ fTestComplete();
198
+ }
199
+ );
200
+ test
201
+ (
202
+ 'Schema definition prototypes should be able to be generated from any JSON object shape.',
203
+ (fTestComplete)=>
204
+ {
205
+ let tmpSchemaDescriptors = (
206
+ {
207
+ "a": { "Hash": "a", "Type": "Number" },
208
+ "b": { "Hash": "b", "Type": "Number" },
209
+ "TranslationTable":
210
+ {
211
+ "a": "CarrotCost",
212
+ "b": "AppleCost"
213
+ }
214
+ });
215
+
216
+ let _Manyfest = new libManyfest();
217
+ // Now remap the schema (in-place)
218
+ let tmpSchemaPrototype = _Manyfest.objectAddressGeneration.generateAddressses(tmpSchemaDescriptors);
219
+
220
+ // The schema should be fundamentally altered to point these addresses to the old hashes
221
+ Expect(tmpSchemaPrototype).to.be.an('object');
222
+
223
+ Expect(tmpSchemaPrototype['TranslationTable.a'].DataType).to.equal('String');
224
+
225
+ fTestComplete();
226
+ }
227
+ );
228
+ test
229
+ (
230
+ 'Make a much bigger schema prototype.',
231
+ (fTestComplete)=>
232
+ {
233
+ let _Manyfest = new libManyfest();
234
+ // Now remap the schema (in-place)
235
+ let tmpSchemaPrototype = _Manyfest.objectAddressGeneration.generateAddressses(_SampleDataArchiveOrgFrankenberry);
236
+
237
+ // The schema should be fundamentally altered to point these addresses to the old hashes
238
+ Expect(tmpSchemaPrototype).to.be.an('object');
239
+
240
+ Expect(tmpSchemaPrototype['files_count'].Default).to.equal(17);
241
+ Expect(tmpSchemaPrototype['files_count'].DataType).to.equal('Number');
242
+
197
243
  fTestComplete();
198
244
  }
199
245
  );