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/dist/fable.js +26 -15
- package/dist/fable.js.map +1 -1
- package/dist/fable.min.js +1 -1
- package/dist/fable.min.js.map +1 -1
- package/package.json +1 -1
- package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-FunctionMap.json +5 -0
- package/source/services/Fable-Service-Math.js +4 -2
- package/source/services/Fable-Service-MetaTemplate/MetaTemplate-StringParser.js +28 -17
- package/source/services/Fable-Service-MetaTemplate.js +3 -2
- package/source/services/Fable-Service-Utility.js +14 -0
- package/test/ExpressionParser_tests.js +25 -0
- package/test/Utility_tests.js +17 -0
package/package.json
CHANGED
|
@@ -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
|
-
|
|
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);
|
package/test/Utility_tests.js
CHANGED
|
@@ -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
|
}
|