fable 3.1.17 → 3.1.19

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": "fable",
3
- "version": "3.1.17",
3
+ "version": "3.1.19",
4
4
  "description": "A service dependency injection, configuration and logging library.",
5
5
  "main": "source/Fable.js",
6
6
  "scripts": {
@@ -129,6 +129,11 @@
129
129
  "Address": "fable.Utility.getInternalValueByHash"
130
130
  },
131
131
 
132
+ "createarrayfromabsolutevalues": {
133
+ "Name": "Create Array from Absolute Values",
134
+ "Address": "fable.Utility.createArrayFromAbsoluteValues"
135
+ },
136
+
132
137
  "flatten": {
133
138
  "Name": "flatten an array of values",
134
139
  "Address": "fable.Utility.flattenArrayOfSolverInputs"
@@ -668,8 +668,10 @@ class FableServiceMath extends libFableServiceBase
668
668
  return tmpSortedHistogram;
669
669
  }
670
670
 
671
- cleanValueArray(pValueArray)
671
+ cleanValueArray(pValueArray, pRemoveZeroes)
672
672
  {
673
+ let tmpRemoveZeroes = (typeof (pRemoveZeroes) === 'undefined') ? false : pRemoveZeroes;
674
+
673
675
  if (!Array.isArray(pValueArray))
674
676
  {
675
677
  return [];
@@ -679,7 +681,7 @@ class FableServiceMath extends libFableServiceBase
679
681
  for (let i = 0; i < pValueArray.length; i++)
680
682
  {
681
683
  let tmpValue = this.parsePrecise(pValueArray[i], NaN);
682
- if (!isNaN(tmpValue))
684
+ if (!isNaN(tmpValue) && (!tmpRemoveZeroes || (tmpValue != "0")))
683
685
  {
684
686
  tmpCleanedArray.push(tmpValue);
685
687
  }
@@ -84,11 +84,12 @@ class StringParser
84
84
  * @param {string} pCharacter - The character to append
85
85
  * @param {Object} pParserState - The state object for the current parsing task
86
86
  * @param {any} pData - The data available to the template
87
- * @param {any} pDataContext - The history of data objects/context already passed in
87
+ * @param {Array<any>} pDataContext - The history of data objects/context already passed in
88
88
  * @param {any} [pScope] - A sticky scope that can be used to carry state and simplify template
89
+ * @param {any} [pState] - A catchall state object for plumbing data through template processing.
89
90
  * @private
90
91
  */
91
- parseCharacter (pCharacter, pParserState, pData, pDataContext, pScope)
92
+ parseCharacter (pCharacter, pParserState, pData, pDataContext, pScope, pState)
92
93
  {
93
94
  // If we are already in a pattern match traversal
94
95
  if (pParserState.PatternMatch)
@@ -112,11 +113,11 @@ class StringParser
112
113
  let tmpFunctionContext = ('ParserContext' in pParserState.Pattern) ? pParserState.Pattern.ParserContext : false;
113
114
  if (tmpFunctionContext)
114
115
  {
115
- pParserState.OutputBuffer = pParserState.Pattern.Parse.call(tmpFunctionContext, pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData, pDataContext, pScope);
116
+ pParserState.OutputBuffer = pParserState.Pattern.Parse.call(tmpFunctionContext, pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData, pDataContext, pScope, pState);
116
117
  }
117
118
  else
118
119
  {
119
- pParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData, pDataContext, pScope);
120
+ pParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData, pDataContext, pScope, pState);
120
121
  }
121
122
  return this.resetOutputBuffer(pParserState);
122
123
  }
@@ -155,11 +156,11 @@ class StringParser
155
156
  let tmpFunctionContext = ('ParserContext' in pParserState.Pattern) ? pParserState.Pattern.ParserContext : false;
156
157
  if (tmpFunctionContext)
157
158
  {
158
- pParserState.OutputBuffer = pParserState.Pattern.Parse.call(tmpFunctionContext, pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData, pDataContext, pScope);
159
+ pParserState.OutputBuffer = pParserState.Pattern.Parse.call(tmpFunctionContext, pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData, pDataContext, pScope, pState);
159
160
  }
160
161
  else
161
162
  {
162
- pParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData, pDataContext, pScope);
163
+ pParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData, pDataContext, pScope, pState);
163
164
  }
164
165
  return this.resetOutputBuffer(pParserState);
165
166
  }
@@ -192,7 +193,15 @@ class StringParser
192
193
  return false;
193
194
  }
194
195
 
195
- executePatternAsync(pParserState, pData, fCallback, pDataContext, pScope)
196
+ /**
197
+ * @param {Object} pParserState - The state object for the current parsing task
198
+ * @param {Object} pData - The data to pass to the function as a second parameter
199
+ * @param {function} fCallback - The callback function to call when the parse is complete
200
+ * @param {array} pDataContext - The history of data objects/context already passed in
201
+ * @param {any} [pScope] - A sticky scope that can be used to carry state and simplify template
202
+ * @param {any} [pState] - A catchall state object for plumbing data through template processing.
203
+ */
204
+ executePatternAsync(pParserState, pData, fCallback, pDataContext, pScope, pState)
196
205
  {
197
206
  // ... this is the end of a pattern, cut off the end tag and parse it.
198
207
  // Trim the start and end tags off the output buffer now
@@ -213,7 +222,7 @@ class StringParser
213
222
  pParserState.OutputBuffer = pAsyncOutput;
214
223
  this.resetOutputBuffer(pParserState);
215
224
  return fCallback();
216
- }, pDataContext, pScope);
225
+ }, pDataContext, pScope, pState);
217
226
  }
218
227
  else
219
228
  {
@@ -228,7 +237,7 @@ class StringParser
228
237
  pParserState.OutputBuffer = pAsyncOutput;
229
238
  this.resetOutputBuffer(pParserState);
230
239
  return fCallback();
231
- }, pDataContext, pScope);
240
+ }, pDataContext, pScope, pState);
232
241
  }
233
242
  }
234
243
  else
@@ -237,11 +246,11 @@ class StringParser
237
246
  let tmpFunctionContext = ('ParserContext' in pParserState.Pattern) ? pParserState.Pattern.ParserContext : false;
238
247
  if (tmpFunctionContext)
239
248
  {
240
- pParserState.OutputBuffer = pParserState.Pattern.Parse.call(tmpFunctionContext, pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData, pDataContext, pScope);
249
+ pParserState.OutputBuffer = pParserState.Pattern.Parse.call(tmpFunctionContext, pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData, pDataContext, pScope, pState);
241
250
  }
242
251
  else
243
252
  {
244
- pParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData, pDataContext, pScope);
253
+ pParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStartString.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStartString.length+pParserState.Pattern.PatternEndString.length)), pData, pDataContext, pScope, pState);
245
254
  }
246
255
  this.resetOutputBuffer(pParserState);
247
256
  return fCallback();
@@ -258,9 +267,10 @@ class StringParser
258
267
  * @param {function} fCallback - The callback function to call when the parse is complete
259
268
  * @param {array} pDataContext - The history of data objects/context already passed in
260
269
  * @param {any} [pScope] - A sticky scope that can be used to carry state and simplify template
270
+ * @param {any} [pState] - A catchall state object for plumbing data through template processing.
261
271
  * @private
262
272
  */
263
- parseCharacterAsync (pCharacter, pParserState, pData, fCallback, pDataContext, pScope)
273
+ parseCharacterAsync (pCharacter, pParserState, pData, fCallback, pDataContext, pScope, pState)
264
274
  {
265
275
  // If we are already in a pattern match traversal
266
276
  if (pParserState.PatternMatch)
@@ -282,7 +292,7 @@ class StringParser
282
292
  // If this last character is the end of the pattern, parse it.
283
293
  if ('Parse' in pParserState.Pattern)
284
294
  {
285
- return this.executePatternAsync(pParserState, pData, fCallback, pDataContext, pScope);
295
+ return this.executePatternAsync(pParserState, pData, fCallback, pDataContext, pScope, pState);
286
296
  }
287
297
  }
288
298
  else if (pCharacter in pParserState.PatternStartNode.PatternEnd)
@@ -316,7 +326,7 @@ class StringParser
316
326
  // If this last character is the end of the pattern, parse it.
317
327
  if ('Parse' in pParserState.Pattern)
318
328
  {
319
- return this.executePatternAsync(pParserState, pData, fCallback, pDataContext, pScope);
329
+ return this.executePatternAsync(pParserState, pData, fCallback, pDataContext, pScope, pState);
320
330
  }
321
331
  }
322
332
  }
@@ -357,8 +367,9 @@ class StringParser
357
367
  * @param {function} fCallback - The callback function to call when the parse is complete
358
368
  * @param {array} pDataContext - The history of data objects/context already passed in
359
369
  * @param {any} [pScope] - A sticky scope that can be used to carry state and simplify template
370
+ * @param {any} [pState] - A catchall state object for plumbing data through template processing.
360
371
  */
361
- parseString (pString, pParseTree, pData, fCallback, pDataContext, pScope)
372
+ parseString (pString, pParseTree, pData, fCallback, pDataContext, pScope, pState)
362
373
  {
363
374
  // TODO: There is danger here if a template function attempts to functionally recurse and doesn't pass this in.
364
375
  let tmpPreviousDataContext = (Array.isArray(pDataContext)) ? pDataContext : [];
@@ -372,7 +383,7 @@ class StringParser
372
383
  for (var i = 0; i < pString.length; i++)
373
384
  {
374
385
  // TODO: This is not fast.
375
- this.parseCharacter(pString[i], tmpParserState, pData, tmpDataContext, pScope);
386
+ this.parseCharacter(pString[i], tmpParserState, pData, tmpDataContext, pScope, pState);
376
387
  }
377
388
 
378
389
  this.flushOutputBuffer(tmpParserState);
@@ -392,7 +403,7 @@ class StringParser
392
403
  tmpAnticipate.anticipate(
393
404
  (fCallback) =>
394
405
  {
395
- this.parseCharacterAsync(pString[i], tmpParserState, pData, fCallback, tmpDataContext, pScope);
406
+ this.parseCharacterAsync(pString[i], tmpParserState, pData, fCallback, tmpDataContext, pScope, pState);
396
407
  });
397
408
  }
398
409
 
@@ -43,15 +43,16 @@ class FableServiceMetaTemplate extends libFableServiceBase
43
43
  * @param {function} fCallback - The callback function to call when a pattern is matched
44
44
  * @param {array} pDataContext - The history of data objects already passed in
45
45
  * @param {any} [pScope] - A sticky scope that can be used to carry state and simplify template
46
+ * @param {any} [pState] - A catchall state object for plumbing data through template processing.
46
47
  * @return {string} The result from the parser
47
48
  */
48
- parseString(pString, pData, fCallback, pDataContext, pScope)
49
+ parseString(pString, pData, fCallback, pDataContext, pScope, pState)
49
50
  {
50
51
  if (this.LogNoisiness > 4)
51
52
  {
52
53
  this.fable.log.trace(`Metatemplate parsing template string [${pString}] where the callback is a ${typeof(fCallback)}`, {TemplateData:pData});
53
54
  }
54
- return this.StringParser.parseString(pString, this.ParseTree, pData, fCallback, pDataContext, pScope);
55
+ return this.StringParser.parseString(pString, this.ParseTree, pData, fCallback, pDataContext, pScope, pState);
55
56
  }
56
57
  }
57
58
 
@@ -486,6 +486,20 @@ class FableServiceUtility extends libFableServiceBase
486
486
  };
487
487
  return pInputArray.flatMap(tmpArrayFlattener);
488
488
  }
489
+
490
+ /**
491
+ * Take a set of arbitrary parameters and build an array from them
492
+ * @returns {Array} - An array built from the absolute values of the parameters
493
+ */
494
+ createArrayFromAbsoluteValues()
495
+ {
496
+ let tmpArray = [];
497
+ for (let i = 0; i < arguments.length; i++)
498
+ {
499
+ tmpArray.push(arguments[i]);
500
+ }
501
+ return tmpArray;
502
+ }
489
503
  }
490
504
 
491
505
  module.exports = FableServiceUtility;
@@ -398,6 +398,13 @@ suite
398
398
  // Now through the solver
399
399
 
400
400
  let _Parser = testFable.instantiateServiceProviderIfNotExists('ExpressionParser');
401
+
402
+ testFable.AppData.Value1 = "100"; // Comment
403
+ testFable.AppData.Value2 = "-80.5"; // Comment
404
+ testFable.AppData.Value3 = "10000"; // Comment
405
+ testFable.AppData.Value4 = "-333.333"; // Comment
406
+ testFable.AppData.Value5 = "0"; // Comment
407
+
401
408
  let tmpResultsObject = {};
402
409
  let tmpDestinationObject = {};
403
410
 
@@ -405,6 +412,24 @@ suite
405
412
  _Parser.solve('AggregationResult = aggregationHistogram("AppData.Cities", "state", "population")', testFable, tmpResultsObject, false, tmpDestinationObject);
406
413
  _Parser.solve('PopSum = sum(flatten(AppData.Cities[].population, AppData.Cities[].latitude))', testFable, tmpResultsObject, false, tmpDestinationObject);
407
414
 
415
+ //_Parser.solve('MadeUpValueArray = ROUND(AVG(createarrayfromabsolutevalues(100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100)),2)', testFable, tmpResultsObject, false, tmpDestinationObject);
416
+ //Expect(tmpDestinationObject.MadeUpValueArray).to.equal('600');
417
+ _Parser.solve('MadeUpValueArray = ROUND(AVG(createarrayfromabsolutevalues(AppData.Value1, AppData.Value2, AppData.Value3, AppData.Value4, AppData.Value5)),2)', testFable, tmpResultsObject, false, tmpDestinationObject);
418
+ Expect(tmpDestinationObject.MadeUpValueArray).to.equal('1937.23');
419
+
420
+ _Parser.solve('MadeUpValueArray = ROUND(AVG(cleanvaluearray(createarrayfromabsolutevalues(AppData.Value1, AppData.Value2, AppData.Value3, AppData.Value4, AppData.Value5), 1)),2)', testFable, tmpResultsObject, false, tmpDestinationObject);
421
+ Expect(tmpDestinationObject.MadeUpValueArray).to.equal('2421.54');
422
+
423
+ // _Parser.solve('MadeUpValueArray = ROUND(AVG(createarrayfromabsolutevalues(100, -80.5, 10000, -333.333, 0)),2)', testFable, tmpResultsObject, false, tmpDestinationObject);
424
+ // Expect(tmpDestinationObject.MadeUpValueArray).to.equal('600');
425
+
426
+
427
+ _Parser.solve('MadeUpValueArray = ROUND(AVG(createarrayfromabsolutevalues(100, 10, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100)),2)', testFable, tmpResultsObject, false, tmpDestinationObject);
428
+ Expect(tmpDestinationObject.MadeUpValueArray).to.equal('550.83');
429
+
430
+ // _Parser.solve('MadeUpValueArray = ROUND(AVG(createarrayfromabsolutevalues(-5, 5, 0, -10, 10, -25, 25, -50, 50)),2)', testFable, tmpResultsObject, false, tmpDestinationObject);
431
+ // Expect(tmpDestinationObject.MadeUpValueArray).to.equal('25');
432
+
408
433
 
409
434
  Expect(tmpDestinationObject.DistributionResult.Alabama).to.equal(12);
410
435
  Expect(tmpDestinationObject.DistributionResult.Colorado).to.equal(21);
@@ -411,6 +411,23 @@ suite
411
411
  return fDone();
412
412
  }
413
413
  );
414
+ test
415
+ (
416
+ 'createArrayFromAbsoluteValues works as expected',
417
+ function(fDone)
418
+ {
419
+ testFable = new libFable();
420
+
421
+ let tmpResult = testFable.services.Utility.createArrayFromAbsoluteValues(0,3,5,9);
422
+ Expect(tmpResult).to.be.an('array');
423
+ Expect(tmpResult.length).to.equal(4);
424
+ Expect(tmpResult[0]).to.equal(0);
425
+ Expect(tmpResult[1]).to.equal(3);
426
+ Expect(tmpResult[2]).to.equal(5);
427
+ Expect(tmpResult[3]).to.equal(9);
428
+ return fDone();
429
+ }
430
+ )
414
431
  }
415
432
  );
416
433
  }