fable 3.0.128 → 3.0.129
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/debug/Harness.js +13 -18
- package/dist/fable.compatible.js +93 -92
- package/dist/fable.compatible.min.js +2 -2
- package/dist/fable.compatible.min.js.map +1 -1
- package/dist/fable.js +93 -92
- package/dist/fable.min.js +2 -2
- package/dist/fable.min.js.map +1 -1
- package/package.json +5 -5
- package/source/Fable-Browser-Shim.js +1 -1
- package/source/Fable.js +11 -11
- package/source/services/Fable-Service-DataFormat.js +6 -6
- package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-Base.js +2 -2
- package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-ExpressionTokenizer.js +1 -1
- package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-Linter.js +2 -2
- package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-Postfix.js +4 -4
- package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-SolvePostfixedExpression.js +3 -3
- package/source/services/Fable-Service-FilePersistence.js +2 -2
- package/source/services/Fable-Service-MetaTemplate/MetaTemplate-StringParser.js +16 -16
- package/source/services/Fable-Service-MetaTemplate/MetaTemplate-WordTree.js +3 -3
- package/source/services/Fable-Service-Operation.js +1 -1
- package/source/services/Fable-Service-ProgressTime.js +7 -7
- package/source/services/Fable-Service-ProgressTrackerSet.js +11 -11
- package/source/services/Fable-Service-RestClient.js +4 -4
- package/source/services/Fable-Service-Utility.js +1 -1
package/dist/fable.js
CHANGED
|
@@ -634,8 +634,8 @@ return true;}}module.exports=BaseLogger;},{"fable-serviceproviderbase":51}],46:[
|
|
|
634
634
|
*
|
|
635
635
|
* @author Steven Velozo <steven@velozo.com>
|
|
636
636
|
*/ // Return the providers that are available without extensions loaded
|
|
637
|
-
var getDefaultProviders=()=>{let tmpDefaultProviders={};tmpDefaultProviders.console=require('./Fable-Log-Logger-Console.js');tmpDefaultProviders.default=tmpDefaultProviders.console;return tmpDefaultProviders;};module.exports=getDefaultProviders();},{"./Fable-Log-Logger-Console.js":48}],47:[function(require,module,exports){module.exports=[{"loggertype":"console","streamtype":"console","level":"trace"}];},{}],48:[function(require,module,exports){let libBaseLogger=require('./Fable-Log-BaseLogger.js');class ConsoleLogger extends libBaseLogger{constructor(pLogStreamSettings,pFableLog){super(pLogStreamSettings);this._ShowTimeStamps=this._Settings
|
|
638
|
-
this._OutputLogLinesToConsole=this._Settings
|
|
637
|
+
var getDefaultProviders=()=>{let tmpDefaultProviders={};tmpDefaultProviders.console=require('./Fable-Log-Logger-Console.js');tmpDefaultProviders.default=tmpDefaultProviders.console;return tmpDefaultProviders;};module.exports=getDefaultProviders();},{"./Fable-Log-Logger-Console.js":48}],47:[function(require,module,exports){module.exports=[{"loggertype":"console","streamtype":"console","level":"trace"}];},{}],48:[function(require,module,exports){let libBaseLogger=require('./Fable-Log-BaseLogger.js');class ConsoleLogger extends libBaseLogger{constructor(pLogStreamSettings,pFableLog){super(pLogStreamSettings);this._ShowTimeStamps='showtimestamps'in this._Settings?this._Settings.showtimestamps==true:true;this._FormattedTimeStamps='formattedtimestamps'in this._Settings?this._Settings.formattedtimestamps==true:true;this._ContextMessage='Context'in this._Settings?"(".concat(this._Settings.Context,")"):'Product'in pFableLog._Settings?"(".concat(pFableLog._Settings.Product,")"):'Unnamed_Log_Context';// Allow the user to decide what gets output to the console
|
|
638
|
+
this._OutputLogLinesToConsole='outputloglinestoconsole'in this._Settings?this._Settings.outputloglinestoconsole:true;this._OutputObjectsToConsole='outputobjectstoconsole'in this._Settings?this._Settings.outputobjectstoconsole:true;// Precompute the prefix for each level
|
|
639
639
|
this.prefixCache={};for(let i=0;i<=this.levels.length;i++){this.prefixCache[this.levels[i]]="[".concat(this.levels[i],"] ").concat(this._ContextMessage,": ");if(this._ShowTimeStamps){// If there is a timestamp we need a to prepend space before the prefixcache string, since the timestamp comes first
|
|
640
640
|
this.prefixCache[this.levels[i]]=' '+this.prefixCache[this.levels[i]];}}}write(pLevel,pLogText,pObject){let tmpTimeStamp='';if(this._ShowTimeStamps&&this._FormattedTimeStamps){tmpTimeStamp=new Date().toISOString();}else if(this._ShowTimeStamps){tmpTimeStamp=+new Date();}let tmpLogLine="".concat(tmpTimeStamp).concat(this.prefixCache[pLevel]).concat(pLogText);if(this._OutputLogLinesToConsole){console.log(tmpLogLine);}// Write out the object on a separate line if it is passed in
|
|
641
641
|
if(this._OutputObjectsToConsole&&typeof pObject!=='undefined'){console.log(JSON.stringify(pObject,null,2));}// Provide an easy way to be overridden and be consistent
|
|
@@ -650,14 +650,14 @@ this.fileWriter.once('drain',this.completeBufferFlushToLogFile.bind(this,tmpFlus
|
|
|
650
650
|
this.logLineStrings.push(tmpLogLine);// Write out the object on a separate line if it is passed in
|
|
651
651
|
if(typeof pObject!=='undefined'){this.logObjectStrings.push(JSON.stringify(pObject,null,4));}else{this.logObjectStrings.push(false);}this.flushBufferToLogFile();}}module.exports=SimpleFlatFileLogger;},{"./Fable-Log-Logger-Console.js":48,"fs":19,"path":83}],50:[function(require,module,exports){/**
|
|
652
652
|
* Fable Logging Service
|
|
653
|
-
*/const libFableServiceProviderBase=require('fable-serviceproviderbase').CoreServiceProviderBase;class FableLog extends libFableServiceProviderBase{constructor(pSettings,pServiceHash){super(pSettings,pServiceHash);this.serviceType='Logging';let tmpSettings=typeof pSettings==='object'?pSettings:{};this._Settings=tmpSettings;this._Providers=require('./Fable-Log-DefaultProviders-Node.js');this._StreamDefinitions=
|
|
653
|
+
*/const libFableServiceProviderBase=require('fable-serviceproviderbase').CoreServiceProviderBase;class FableLog extends libFableServiceProviderBase{constructor(pSettings,pServiceHash){super(pSettings,pServiceHash);this.serviceType='Logging';let tmpSettings=typeof pSettings==='object'?pSettings:{};this._Settings=tmpSettings;this._Providers=require('./Fable-Log-DefaultProviders-Node.js');this._StreamDefinitions='LogStreams'in tmpSettings?tmpSettings.LogStreams:require('./Fable-Log-DefaultStreams.json');this.logStreams=[];// This object gets decorated for one-time instantiated providers that
|
|
654
654
|
// have multiple outputs, such as bunyan.
|
|
655
655
|
this.logProviders={};// A hash list of the GUIDs for each log stream, so they can't be added to the set more than one time
|
|
656
656
|
this.activeLogStreams={};this.logStreamsTrace=[];this.logStreamsDebug=[];this.logStreamsInfo=[];this.logStreamsWarn=[];this.logStreamsError=[];this.logStreamsFatal=[];this.datumDecorator=pDatum=>pDatum;this.uuid=typeof tmpSettings.Product==='string'?tmpSettings.Product:'Default';}addLogger(pLogger,pLevel){// Bail out if we've already created one.
|
|
657
|
-
if(this.activeLogStreams
|
|
657
|
+
if(pLogger.loggerUUID in this.activeLogStreams){return false;}// Add it to the streams and to the mutex
|
|
658
658
|
this.logStreams.push(pLogger);this.activeLogStreams[pLogger.loggerUUID]=true;// Make sure a kosher level was passed in
|
|
659
659
|
switch(pLevel){case'trace':this.logStreamsTrace.push(pLogger);case'debug':this.logStreamsDebug.push(pLogger);case'info':this.logStreamsInfo.push(pLogger);case'warn':this.logStreamsWarn.push(pLogger);case'error':this.logStreamsError.push(pLogger);case'fatal':this.logStreamsFatal.push(pLogger);break;}return true;}setDatumDecorator(fDatumDecorator){if(typeof fDatumDecorator==='function'){this.datumDecorator=fDatumDecorator;}else{this.datumDecorator=pDatum=>pDatum;}}trace(pMessage,pDatum){const tmpDecoratedDatum=this.datumDecorator(pDatum);for(let i=0;i<this.logStreamsTrace.length;i++){this.logStreamsTrace[i].trace(pMessage,tmpDecoratedDatum);}}debug(pMessage,pDatum){const tmpDecoratedDatum=this.datumDecorator(pDatum);for(let i=0;i<this.logStreamsDebug.length;i++){this.logStreamsDebug[i].debug(pMessage,tmpDecoratedDatum);}}info(pMessage,pDatum){const tmpDecoratedDatum=this.datumDecorator(pDatum);for(let i=0;i<this.logStreamsInfo.length;i++){this.logStreamsInfo[i].info(pMessage,tmpDecoratedDatum);}}warn(pMessage,pDatum){const tmpDecoratedDatum=this.datumDecorator(pDatum);for(let i=0;i<this.logStreamsWarn.length;i++){this.logStreamsWarn[i].warn(pMessage,tmpDecoratedDatum);}}error(pMessage,pDatum){const tmpDecoratedDatum=this.datumDecorator(pDatum);for(let i=0;i<this.logStreamsError.length;i++){this.logStreamsError[i].error(pMessage,tmpDecoratedDatum);}}fatal(pMessage,pDatum){const tmpDecoratedDatum=this.datumDecorator(pDatum);for(let i=0;i<this.logStreamsFatal.length;i++){this.logStreamsFatal[i].fatal(pMessage,tmpDecoratedDatum);}}initialize(){// "initialize" each logger as defined in the logging parameters
|
|
660
|
-
for(let i=0;i<this._StreamDefinitions.length;i++){let tmpStreamDefinition=Object.assign({loggertype:'default',streamtype:'console',level:'info'},this._StreamDefinitions[i]);if(!
|
|
660
|
+
for(let i=0;i<this._StreamDefinitions.length;i++){let tmpStreamDefinition=Object.assign({loggertype:'default',streamtype:'console',level:'info'},this._StreamDefinitions[i]);if(!(tmpStreamDefinition.loggertype in this._Providers)){console.log("Error initializing log stream: bad loggertype in stream definition ".concat(JSON.stringify(tmpStreamDefinition)));}else{this.addLogger(new this._Providers[tmpStreamDefinition.loggertype](tmpStreamDefinition,this),tmpStreamDefinition.level);}}// Now initialize each one.
|
|
661
661
|
for(let i=0;i<this.logStreams.length;i++){this.logStreams[i].initialize();}}logTime(pMessage,pDatum){let tmpMessage=typeof pMessage!=='undefined'?pMessage:'Time';let tmpTime=new Date();this.info("".concat(tmpMessage," ").concat(tmpTime," (epoch ").concat(+tmpTime,")"),pDatum);}// Get a timestamp
|
|
662
662
|
getTimeStamp(){return+new Date();}getTimeDelta(pTimeStamp){let tmpEndTime=+new Date();return tmpEndTime-pTimeStamp;}// Log the delta between a timestamp, and now with a message
|
|
663
663
|
logTimeDelta(pTimeDelta,pMessage,pDatum){let tmpMessage=typeof pMessage!=='undefined'?pMessage:'Time Measurement';let tmpDatum=typeof pDatum==='object'?pDatum:{};let tmpEndTime=+new Date();this.info("".concat(tmpMessage," logged at (epoch ").concat(+tmpEndTime,") took (").concat(pTimeDelta,"ms)"),pDatum);}logTimeDeltaHuman(pTimeDelta,pMessage,pDatum){let tmpMessage=typeof pMessage!=='undefined'?pMessage:'Time Measurement';let tmpEndTime=+new Date();let tmpMs=parseInt(pTimeDelta%1000);let tmpSeconds=parseInt(pTimeDelta/1000%60);let tmpMinutes=parseInt(pTimeDelta/(1000*60)%60);let tmpHours=parseInt(pTimeDelta/(1000*60*60));tmpMs=tmpMs<10?"00"+tmpMs:tmpMs<100?"0"+tmpMs:tmpMs;tmpSeconds=tmpSeconds<10?"0"+tmpSeconds:tmpSeconds;tmpMinutes=tmpMinutes<10?"0"+tmpMinutes:tmpMinutes;tmpHours=tmpHours<10?"0"+tmpHours:tmpHours;this.info("".concat(tmpMessage," logged at (epoch ").concat(+tmpEndTime,") took (").concat(pTimeDelta,"ms) or (").concat(tmpHours,":").concat(tmpMinutes,":").concat(tmpSeconds,".").concat(tmpMs,")"),pDatum);}logTimeDeltaRelative(pStartTime,pMessage,pDatum){this.logTimeDelta(this.getTimeDelta(pStartTime),pMessage,pDatum);}logTimeDeltaRelativeHuman(pStartTime,pMessage,pDatum){this.logTimeDeltaHuman(this.getTimeDelta(pStartTime),pMessage,pDatum);}}module.exports=FableLog;module.exports.LogProviderBase=require('./Fable-Log-BaseLogger.js');module.exports.LogProviderConsole=require('./Fable-Log-Logger-Console.js');module.exports.LogProviderFlatfile=require('./Fable-Log-Logger-SimpleFlatFile.js');},{"./Fable-Log-BaseLogger.js":45,"./Fable-Log-DefaultProviders-Node.js":46,"./Fable-Log-DefaultStreams.json":47,"./Fable-Log-Logger-Console.js":48,"./Fable-Log-Logger-SimpleFlatFile.js":49,"fable-serviceproviderbase":51}],51:[function(require,module,exports){/**
|
|
@@ -683,7 +683,7 @@ module.exports.CoreServiceProviderBase=FableServiceProviderBase;},{}],52:[functi
|
|
|
683
683
|
* @module Fable Settings
|
|
684
684
|
*/const libPrecedent=require('precedent');class FableSettingsTemplateProcessor{constructor(pDependencies){// Use a no-dependencies templating engine to parse out environment variables
|
|
685
685
|
this.templateProcessor=new libPrecedent();// TODO: Make the environment variable wrap expression demarcation characters configurable?
|
|
686
|
-
this.templateProcessor.addPattern('${','}',pTemplateValue=>{let tmpTemplateValue=pTemplateValue.trim();let tmpSeparatorIndex=tmpTemplateValue.indexOf('|');const tmpDefaultValue=tmpSeparatorIndex>=0?tmpTemplateValue.substring(tmpSeparatorIndex+1):'';let tmpEnvironmentVariableName=tmpSeparatorIndex>-1?tmpTemplateValue.substring(0,tmpSeparatorIndex):tmpTemplateValue;if(process.env
|
|
686
|
+
this.templateProcessor.addPattern('${','}',pTemplateValue=>{let tmpTemplateValue=pTemplateValue.trim();let tmpSeparatorIndex=tmpTemplateValue.indexOf('|');const tmpDefaultValue=tmpSeparatorIndex>=0?tmpTemplateValue.substring(tmpSeparatorIndex+1):'';let tmpEnvironmentVariableName=tmpSeparatorIndex>-1?tmpTemplateValue.substring(0,tmpSeparatorIndex):tmpTemplateValue;if(tmpEnvironmentVariableName in process.env){return process.env[tmpEnvironmentVariableName];}else{return tmpDefaultValue;}});}parseSetting(pString){return this.templateProcessor.parseString(pString);}}module.exports=FableSettingsTemplateProcessor;}).call(this);}).call(this,require('_process'));},{"_process":87,"precedent":84}],54:[function(require,module,exports){/**
|
|
687
687
|
* Fable Settings Add-on
|
|
688
688
|
*
|
|
689
689
|
*
|
|
@@ -739,10 +739,10 @@ for(let i=0,tmpValue;i<16;i++){if((i&0x03)===0){tmpValue=Math.random()*0x1000000
|
|
|
739
739
|
* Fable UUID Generator
|
|
740
740
|
*/const libFableServiceProviderBase=require('fable-serviceproviderbase').CoreServiceProviderBase;0;const libRandomByteGenerator=require('./Fable-UUID-Random.js');class FableUUID extends libFableServiceProviderBase{constructor(pSettings,pServiceHash){super(pSettings,pServiceHash);this.serviceType='UUID';// Determine if the module is in "Random UUID Mode" which means just use the random character function rather than the v4 random UUID spec.
|
|
741
741
|
// Note this allows UUIDs of various lengths (including very short ones) although guaranteed uniqueness goes downhill fast.
|
|
742
|
-
this._UUIDModeRandom=typeof pSettings==='object'&&
|
|
742
|
+
this._UUIDModeRandom=typeof pSettings==='object'&&'UUIDModeRandom'in pSettings?pSettings.UUIDModeRandom==true:false;// These two properties are only useful if we are in Random mode. Otherwise it generates a v4 spec
|
|
743
743
|
// Length for "Random UUID Mode" is set -- if not set it to 8
|
|
744
|
-
this._UUIDLength=typeof pSettings==='object'&&
|
|
745
|
-
this._UUIDRandomDictionary=typeof pSettings==='object'&&
|
|
744
|
+
this._UUIDLength=typeof pSettings==='object'&&'UUIDLength'in pSettings?pSettings.UUIDLength+0:8;// Dictionary for "Random UUID Mode"
|
|
745
|
+
this._UUIDRandomDictionary=typeof pSettings==='object'&&'UUIDDictionary'in pSettings?pSettings.UUIDDictionary+0:'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';this.randomByteGenerator=new libRandomByteGenerator();// Lookup table for hex codes
|
|
746
746
|
this._HexLookup=[];for(let i=0;i<256;++i){this._HexLookup[i]=(i+0x100).toString(16).substr(1);}}// Adapted from node-uuid (https://github.com/kelektiv/node-uuid)
|
|
747
747
|
bytesToUUID(pBuffer){let i=0;// join used to fix memory issue caused by concatenation: https://bugs.chromium.org/p/v8/issues/detail?id=3175#c4
|
|
748
748
|
return[this._HexLookup[pBuffer[i++]],this._HexLookup[pBuffer[i++]],this._HexLookup[pBuffer[i++]],this._HexLookup[pBuffer[i++]],'-',this._HexLookup[pBuffer[i++]],this._HexLookup[pBuffer[i++]],'-',this._HexLookup[pBuffer[i++]],this._HexLookup[pBuffer[i++]],'-',this._HexLookup[pBuffer[i++]],this._HexLookup[pBuffer[i++]],'-',this._HexLookup[pBuffer[i++]],this._HexLookup[pBuffer[i++]],this._HexLookup[pBuffer[i++]],this._HexLookup[pBuffer[i++]],this._HexLookup[pBuffer[i++]],this._HexLookup[pBuffer[i++]]].join('');}// Adapted from node-uuid (https://github.com/kelektiv/node-uuid)
|
|
@@ -813,10 +813,10 @@ const cleanWrapCharacters=(pCharacter,pString)=>{if(pString.startsWith(pCharacte
|
|
|
813
813
|
*/class ManyfestHashTranslation{constructor(pInfoLog,pErrorLog){// Wire in logging
|
|
814
814
|
this.logInfo=typeof pInfoLog==='function'?pInfoLog:libSimpleLog;this.logError=typeof pErrorLog==='function'?pErrorLog:libSimpleLog;this.translationTable={};}translationCount(){return Object.keys(this.translationTable).length;}addTranslation(pTranslation){// This adds a translation in the form of:
|
|
815
815
|
// { "SourceHash": "DestinationHash", "SecondSourceHash":"SecondDestinationHash" }
|
|
816
|
-
if(typeof pTranslation!='object'){this.logError("Hash translation addTranslation expected a translation be type object but was passed in ".concat(typeof pTranslation));return false;}let tmpTranslationSources=Object.keys(pTranslation);tmpTranslationSources.forEach(pTranslationSource=>{if(typeof pTranslation[pTranslationSource]!='string'){this.logError("Hash translation addTranslation expected a translation destination hash for [".concat(pTranslationSource,"] to be a string but the referrant was a ").concat(typeof pTranslation[pTranslationSource]));}else{this.translationTable[pTranslationSource]=pTranslation[pTranslationSource];}});}removeTranslationHash(pTranslationHash){if(this.translationTable
|
|
816
|
+
if(typeof pTranslation!='object'){this.logError("Hash translation addTranslation expected a translation be type object but was passed in ".concat(typeof pTranslation));return false;}let tmpTranslationSources=Object.keys(pTranslation);tmpTranslationSources.forEach(pTranslationSource=>{if(typeof pTranslation[pTranslationSource]!='string'){this.logError("Hash translation addTranslation expected a translation destination hash for [".concat(pTranslationSource,"] to be a string but the referrant was a ").concat(typeof pTranslation[pTranslationSource]));}else{this.translationTable[pTranslationSource]=pTranslation[pTranslationSource];}});}removeTranslationHash(pTranslationHash){if(pTranslationHash in this.translationTable){delete this.translationTable[pTranslationHash];}}// This removes translations.
|
|
817
817
|
// If passed a string, just removes the single one.
|
|
818
818
|
// If passed an object, it does all the source keys.
|
|
819
|
-
removeTranslation(pTranslation){if(typeof pTranslation=='string'){this.removeTranslationHash(pTranslation);return true;}else if(typeof pTranslation=='object'){let tmpTranslationSources=Object.keys(pTranslation);tmpTranslationSources.forEach(pTranslationSource=>{this.removeTranslation(pTranslationSource);});return true;}else{this.logError("Hash translation removeTranslation expected either a string or an object but the passed-in translation was type ".concat(typeof pTranslation));return false;}}clearTranslations(){this.translationTable={};}translate(pTranslation){if(this.translationTable
|
|
819
|
+
removeTranslation(pTranslation){if(typeof pTranslation=='string'){this.removeTranslationHash(pTranslation);return true;}else if(typeof pTranslation=='object'){let tmpTranslationSources=Object.keys(pTranslation);tmpTranslationSources.forEach(pTranslationSource=>{this.removeTranslation(pTranslationSource);});return true;}else{this.logError("Hash translation removeTranslation expected either a string or an object but the passed-in translation was type ".concat(typeof pTranslation));return false;}}clearTranslations(){this.translationTable={};}translate(pTranslation){if(pTranslation in this.translationTable){return this.translationTable[pTranslation];}else{return pTranslation;}}}module.exports=ManyfestHashTranslation;},{"./Manyfest-LogToConsole.js":71}],71:[function(require,module,exports){/**
|
|
820
820
|
* @author <steven@velozo.com>
|
|
821
821
|
*/ /**
|
|
822
822
|
* Manyfest simple logging shim (for browser and dependency-free running)
|
|
@@ -869,7 +869,7 @@ let tmpFunctionStartIndex=pAddress.indexOf('(');// NOTE THAT FUNCTIONS MUST RESO
|
|
|
869
869
|
// The requirements to detect a function are:
|
|
870
870
|
// 1) The start bracket is after character 0
|
|
871
871
|
if(tmpFunctionStartIndex>0// 2) The end bracket is after the start bracket
|
|
872
|
-
&&_MockFable.DataFormat.stringCountEnclosures(pAddress)>0){let tmpFunctionAddress=pAddress.substring(0,tmpFunctionStartIndex).trim();if(pObject
|
|
872
|
+
&&_MockFable.DataFormat.stringCountEnclosures(pAddress)>0){let tmpFunctionAddress=pAddress.substring(0,tmpFunctionStartIndex).trim();if(tmpFunctionAddress in pObject&&typeof pObject[tmpFunctionAddress]=='function'){return true;}else{// The address suggests it is a function, but it is not.
|
|
873
873
|
return false;}}// Boxed elements look like this:
|
|
874
874
|
// MyValues[10]
|
|
875
875
|
// MyValues['Name']
|
|
@@ -896,9 +896,9 @@ if(Array.isArray(pObject[tmpBoxedPropertyName])==isNaN(tmpBoxedPropertyNumber)){
|
|
|
896
896
|
if(isNaN(tmpBoxedPropertyNumber)){// This isn't a number ... let's treat it as a dynamic object property.
|
|
897
897
|
// We would expect the property to be wrapped in some kind of quotes so strip them
|
|
898
898
|
tmpBoxedPropertyReference=this.cleanWrapCharacters('"',tmpBoxedPropertyReference);tmpBoxedPropertyReference=this.cleanWrapCharacters('`',tmpBoxedPropertyReference);tmpBoxedPropertyReference=this.cleanWrapCharacters("'",tmpBoxedPropertyReference);// Check if the property exists.
|
|
899
|
-
return pObject[tmpBoxedPropertyName]
|
|
899
|
+
return tmpBoxedPropertyReference in pObject[tmpBoxedPropertyName];}else{// Use the new in operator to see if the element is in the array
|
|
900
900
|
return tmpBoxedPropertyNumber in pObject[tmpBoxedPropertyName];}}else{// Check if the property exists
|
|
901
|
-
return pObject
|
|
901
|
+
return pAddress in pObject;}}else{let tmpSubObjectName=tmpAddressPartBeginning;let tmpNewAddress=pAddress.substring(tmpAddressPartBeginning.length+1);// Test if the tmpNewAddress is an array or object
|
|
902
902
|
// Check if it's a boxed property
|
|
903
903
|
let tmpBracketStartIndex=tmpSubObjectName.indexOf('[');let tmpBracketStopIndex=tmpSubObjectName.indexOf(']');// Check if there is a function somewhere in the address... parenthesis start should only be in a function
|
|
904
904
|
let tmpFunctionStartIndex=tmpSubObjectName.indexOf('(');// NOTE THAT FUNCTIONS MUST RESOLVE FIRST
|
|
@@ -957,7 +957,7 @@ tmpBoxedPropertyReference=this.cleanWrapCharacters('"',tmpBoxedPropertyReference
|
|
|
957
957
|
return this.checkAddressExists(pObject[tmpBoxedPropertyName][tmpBoxedPropertyReference],tmpNewAddress,tmpRootObject);}else{// We parsed a valid number out of the boxed property name, so recurse into the array
|
|
958
958
|
return this.checkAddressExists(pObject[tmpBoxedPropertyName][tmpBoxedPropertyNumber],tmpNewAddress,tmpRootObject);}}// If there is an object property already named for the sub object, but it isn't an object
|
|
959
959
|
// then the system can't set the value in there. Error and abort!
|
|
960
|
-
if(pObject
|
|
960
|
+
if(tmpSubObjectName in pObject&&typeof pObject[tmpSubObjectName]!=='object'){return false;}else if(tmpSubObjectName in pObject){// If there is already a subobject pass that to the recursive thingy
|
|
961
961
|
return this.checkAddressExists(pObject[tmpSubObjectName],tmpNewAddress,tmpRootObject);}else{// Create a subobject and then pass that
|
|
962
962
|
pObject[tmpSubObjectName]={};return this.checkAddressExists(pObject[tmpSubObjectName],tmpNewAddress,tmpRootObject);}}}};module.exports=ManyfestObjectAddressResolverCheckAddressExists;},{"./Manyfest-LogToConsole.js":71,"./Manyfest-ObjectAddress-GetValue.js":74,"./Manyfest-ObjectAddress-Parser.js":75}],73:[function(require,module,exports){/**
|
|
963
963
|
* @author <steven@velozo.com>
|
|
@@ -1082,7 +1082,7 @@ tmpParentAddress="".concat(tmpParentAddress).concat(tmpParentAddress.length>0?'.
|
|
|
1082
1082
|
let tmpContainerObject={};for(let i=0;i<tmpObjectPropertyKeys.length;i++){let tmpPropertyParentAddress="".concat(tmpParentAddress,".").concat(tmpObjectPropertyKeys[i]);let tmpValue=this.deleteValueAtAddress(pObject[tmpObjectPropertyName][tmpObjectPropertyKeys[i]],tmpNewAddress,tmpPropertyParentAddress);// The filtering is complex but allows config-based metaprogramming directly from schema
|
|
1083
1083
|
let tmpKeepRecord=this.checkRecordFilters(pAddress,tmpValue);if(tmpKeepRecord){tmpContainerObject["".concat(tmpPropertyParentAddress,".").concat(tmpNewAddress)]=tmpValue;}}return tmpContainerObject;}// If there is an object property already named for the sub object, but it isn't an object
|
|
1084
1084
|
// then the system can't set the value in there. Error and abort!
|
|
1085
|
-
if(pObject
|
|
1085
|
+
if(tmpSubObjectName in pObject&&typeof pObject[tmpSubObjectName]!=='object'){return undefined;}else if(tmpSubObjectName in pObject){// If there is already a subobject pass that to the recursive thingy
|
|
1086
1086
|
// Continue to manage the parent address for recursion
|
|
1087
1087
|
tmpParentAddress="".concat(tmpParentAddress).concat(tmpParentAddress.length>0?'.':'').concat(tmpSubObjectName);return this.deleteValueAtAddress(pObject[tmpSubObjectName],tmpNewAddress,tmpParentAddress);}else{// Create a subobject and then pass that
|
|
1088
1088
|
// Continue to manage the parent address for recursion
|
|
@@ -1148,7 +1148,8 @@ return false;}// Now see if the function has arguments.
|
|
|
1148
1148
|
// Implementation notes: * ARGUMENTS MUST SHARE THE SAME ROOT OBJECT CONTEXT *
|
|
1149
1149
|
let tmpFunctionArguments=_MockFable.DataFormat.stringGetSegments(_MockFable.DataFormat.stringGetEnclosureValueByIndex(pAddress.substring(tmpFunctionAddress.length),0),',');if(tmpFunctionArguments.length==0||tmpFunctionArguments[0]==''){// No arguments... just call the function (bound to the scope of the object it is contained withing)
|
|
1150
1150
|
return pObject[tmpFunctionAddress].apply(pObject);}else{let tmpArgumentValues=[];let tmpRootObject=typeof pRootObject=='undefined'?pObject:pRootObject;// Now get the value for each argument
|
|
1151
|
-
for(let i=0;i<tmpFunctionArguments.length;i++){
|
|
1151
|
+
for(let i=0;i<tmpFunctionArguments.length;i++){// Resolve the values for each subsequent entry
|
|
1152
|
+
tmpArgumentValues.push(this.getValueAtAddress(tmpRootObject,tmpFunctionArguments[i]));}return pObject[tmpFunctionAddress].apply(pObject,tmpArgumentValues);}}// Boxed elements look like this:
|
|
1152
1153
|
// MyValues[10]
|
|
1153
1154
|
// MyValues['Name']
|
|
1154
1155
|
// MyValues["Age"]
|
|
@@ -1259,7 +1260,7 @@ tmpParentAddress="".concat(tmpParentAddress).concat(tmpParentAddress.length>0?'.
|
|
|
1259
1260
|
let tmpContainerObject={};for(let i=0;i<tmpObjectPropertyKeys.length;i++){let tmpPropertyParentAddress="".concat(tmpParentAddress,".").concat(tmpObjectPropertyKeys[i]);let tmpValue=this.getValueAtAddress(pObject[tmpObjectPropertyName][tmpObjectPropertyKeys[i]],tmpNewAddress,tmpPropertyParentAddress,tmpRootObject);// The filtering is complex but allows config-based metaprogramming directly from schema
|
|
1260
1261
|
let tmpKeepRecord=this.checkRecordFilters(pAddress,tmpValue);if(tmpKeepRecord){tmpContainerObject["".concat(tmpPropertyParentAddress,".").concat(tmpNewAddress)]=tmpValue;}}return tmpContainerObject;}// If there is an object property already named for the sub object, but it isn't an object
|
|
1261
1262
|
// then the system can't set the value in there. Error and abort!
|
|
1262
|
-
if(pObject
|
|
1263
|
+
if(tmpSubObjectName in pObject&&typeof pObject[tmpSubObjectName]!=='object'){return undefined;}else if(tmpSubObjectName in pObject){// If there is already a subobject pass that to the recursive thingy
|
|
1263
1264
|
// Continue to manage the parent address for recursion
|
|
1264
1265
|
tmpParentAddress="".concat(tmpParentAddress).concat(tmpParentAddress.length>0?'.':'').concat(tmpSubObjectName);return this.getValueAtAddress(pObject[tmpSubObjectName],tmpNewAddress,tmpParentAddress,tmpRootObject);}else{// Create a subobject and then pass that
|
|
1265
1266
|
// Continue to manage the parent address for recursion
|
|
@@ -1281,9 +1282,9 @@ module.exports={/**
|
|
|
1281
1282
|
if(tmpString[i]==tmpSeparator// AND we are not in a nested portion of the string
|
|
1282
1283
|
&&tmpEnclosureStack.length==0){// Increment the segment count
|
|
1283
1284
|
tmpSegmentCount++;}// IF This is the start of an enclosure
|
|
1284
|
-
else if(
|
|
1285
|
+
else if(tmpString[i]in tmpEnclosureStartSymbolMap){// Add it to the stack!
|
|
1285
1286
|
tmpEnclosureStack.push(tmpEnclosureStartSymbolMap[tmpString[i]]);}// IF This is the end of an enclosure
|
|
1286
|
-
else if(
|
|
1287
|
+
else if(tmpString[i]in tmpEnclosureEndSymbolMap// AND it matches the current nest level symbol
|
|
1287
1288
|
&&tmpEnclosureEndSymbolMap[tmpString[i]]==tmpEnclosureStack[tmpEnclosureStack.length-1]){// Pop it off the stack!
|
|
1288
1289
|
tmpEnclosureStack.pop();}}return tmpSegmentCount;},/**
|
|
1289
1290
|
* Get the first segment in a string, respecting enclosures
|
|
@@ -1297,9 +1298,9 @@ tmpEnclosureStack.pop();}}return tmpSegmentCount;},/**
|
|
|
1297
1298
|
if(tmpString[i]==tmpSeparator// AND we are not in a nested portion of the string
|
|
1298
1299
|
&&tmpEnclosureStack.length==0){// Return the segment
|
|
1299
1300
|
return tmpString.substring(0,i);}// IF This is the start of an enclosure
|
|
1300
|
-
else if(
|
|
1301
|
+
else if(tmpString[i]in tmpEnclosureStartSymbolMap){// Add it to the stack!
|
|
1301
1302
|
tmpEnclosureStack.push(tmpEnclosureStartSymbolMap[tmpString[i]]);}// IF This is the end of an enclosure
|
|
1302
|
-
else if(
|
|
1303
|
+
else if(tmpString[i]in tmpEnclosureEndSymbolMap// AND it matches the current nest level symbol
|
|
1303
1304
|
&&tmpEnclosureEndSymbolMap[tmpString[i]]==tmpEnclosureStack[tmpEnclosureStack.length-1]){// Pop it off the stack!
|
|
1304
1305
|
tmpEnclosureStack.pop();}}return tmpString;},/**
|
|
1305
1306
|
* Get all segments in a string, respecting enclosures
|
|
@@ -1313,9 +1314,9 @@ tmpEnclosureStack.pop();}}return tmpString;},/**
|
|
|
1313
1314
|
if(tmpString[i]==tmpSeparator// AND we are not in a nested portion of the string
|
|
1314
1315
|
&&tmpEnclosureStack.length==0){// Return the segment
|
|
1315
1316
|
tmpSegmentList.push(tmpString.substring(tmpCurrentSegmentStart,i));tmpCurrentSegmentStart=i+1;}// IF This is the start of an enclosure
|
|
1316
|
-
else if(
|
|
1317
|
+
else if(tmpString[i]in tmpEnclosureStartSymbolMap){// Add it to the stack!
|
|
1317
1318
|
tmpEnclosureStack.push(tmpEnclosureStartSymbolMap[tmpString[i]]);}// IF This is the end of an enclosure
|
|
1318
|
-
else if(
|
|
1319
|
+
else if(tmpString[i]in tmpEnclosureEndSymbolMap// AND it matches the current nest level symbol
|
|
1319
1320
|
&&tmpEnclosureEndSymbolMap[tmpString[i]]==tmpEnclosureStack[tmpEnclosureStack.length-1]){// Pop it off the stack!
|
|
1320
1321
|
tmpEnclosureStack.pop();}}if(tmpCurrentSegmentStart<tmpString.length){tmpSegmentList.push(tmpString.substring(tmpCurrentSegmentStart));}return tmpSegmentList;},/**
|
|
1321
1322
|
* Count the number of enclosures in a string based on the start and end characters.
|
|
@@ -1429,8 +1430,8 @@ tmpBoxedPropertyReference=this.cleanWrapCharacters('"',tmpBoxedPropertyReference
|
|
|
1429
1430
|
return this.setValueAtAddress(pObject[tmpBoxedPropertyName][tmpBoxedPropertyReference],tmpNewAddress,pValue);}else{// We parsed a valid number out of the boxed property name, so recurse into the array
|
|
1430
1431
|
return this.setValueAtAddress(pObject[tmpBoxedPropertyName][tmpBoxedPropertyNumber],tmpNewAddress,pValue);}}// If there is an object property already named for the sub object, but it isn't an object
|
|
1431
1432
|
// then the system can't set the value in there. Error and abort!
|
|
1432
|
-
if(pObject
|
|
1433
|
-
pObject['__ERROR'][pAddress]=pValue;return false;}else if(pObject
|
|
1433
|
+
if(tmpSubObjectName in pObject&&typeof pObject[tmpSubObjectName]!=='object'){if(!('__ERROR'in pObject))pObject['__ERROR']={};// Put it in an error object so data isn't lost
|
|
1434
|
+
pObject['__ERROR'][pAddress]=pValue;return false;}else if(tmpSubObjectName in pObject){// If there is already a subobject pass that to the recursive thingy
|
|
1434
1435
|
return this.setValueAtAddress(pObject[tmpSubObjectName],tmpNewAddress,pValue);}else{// Create a subobject and then pass that
|
|
1435
1436
|
pObject[tmpSubObjectName]={};return this.setValueAtAddress(pObject[tmpSubObjectName],tmpNewAddress,pValue);}}}};module.exports=ManyfestObjectAddressSetValue;},{"./Manyfest-CleanWrapCharacters.js":69,"./Manyfest-LogToConsole.js":71}],77:[function(require,module,exports){/**
|
|
1436
1437
|
* @author <steven@velozo.com>
|
|
@@ -1528,13 +1529,13 @@ this.logInfo=typeof pInfoLog==='function'?pInfoLog:libSimpleLog;this.logError=ty
|
|
|
1528
1529
|
// TODO: Discuss what should happen on collisions.
|
|
1529
1530
|
resolveAddressMappings(pManyfestSchemaDescriptors,pAddressMapping){if(typeof pManyfestSchemaDescriptors!='object'){this.logError("Attempted to resolve address mapping but the descriptor was not an object.");return false;}if(typeof pAddressMapping!='object'){// No mappings were passed in
|
|
1530
1531
|
return true;}// Get the arrays of both the schema definition and the hash mapping
|
|
1531
|
-
let tmpManyfestAddresses=Object.keys(pManyfestSchemaDescriptors);let tmpHashMapping={};tmpManyfestAddresses.forEach(pAddress=>{if(pManyfestSchemaDescriptors[pAddress]
|
|
1532
|
-
if(pManyfestSchemaDescriptors
|
|
1532
|
+
let tmpManyfestAddresses=Object.keys(pManyfestSchemaDescriptors);let tmpHashMapping={};tmpManyfestAddresses.forEach(pAddress=>{if('Hash'in pManyfestSchemaDescriptors[pAddress]){tmpHashMapping[pManyfestSchemaDescriptors[pAddress].Hash]=pAddress;}});let tmpAddressMappingSet=Object.keys(pAddressMapping);tmpAddressMappingSet.forEach(pInputAddress=>{let tmpNewDescriptorAddress=pAddressMapping[pInputAddress];let tmpOldDescriptorAddress=false;let tmpDescriptor=false;// See if there is a matching descriptor either by Address directly or Hash
|
|
1533
|
+
if(pInputAddress in pManyfestSchemaDescriptors){tmpOldDescriptorAddress=pInputAddress;}else if(pInputAddress in tmpHashMapping){tmpOldDescriptorAddress=tmpHashMapping[pInputAddress];}// If there was a matching descriptor in the manifest, store it in the temporary descriptor
|
|
1533
1534
|
if(tmpOldDescriptorAddress){tmpDescriptor=pManyfestSchemaDescriptors[tmpOldDescriptorAddress];delete pManyfestSchemaDescriptors[tmpOldDescriptorAddress];}else{// Create a new descriptor! Map it to the input address.
|
|
1534
1535
|
tmpDescriptor={Hash:pInputAddress};}// Now re-add the descriptor to the manyfest schema
|
|
1535
1536
|
pManyfestSchemaDescriptors[tmpNewDescriptorAddress]=tmpDescriptor;});return true;}safeResolveAddressMappings(pManyfestSchemaDescriptors,pAddressMapping){// This returns the descriptors as a new object, safely remapping without mutating the original schema Descriptors
|
|
1536
1537
|
let tmpManyfestSchemaDescriptors=JSON.parse(JSON.stringify(pManyfestSchemaDescriptors));this.resolveAddressMappings(tmpManyfestSchemaDescriptors,pAddressMapping);return tmpManyfestSchemaDescriptors;}mergeAddressMappings(pManyfestSchemaDescriptorsDestination,pManyfestSchemaDescriptorsSource){if(typeof pManyfestSchemaDescriptorsSource!='object'||typeof pManyfestSchemaDescriptorsDestination!='object'){this.logError("Attempted to merge two schema descriptors but both were not objects.");return false;}let tmpSource=JSON.parse(JSON.stringify(pManyfestSchemaDescriptorsSource));let tmpNewManyfestSchemaDescriptors=JSON.parse(JSON.stringify(pManyfestSchemaDescriptorsDestination));// The first passed-in set of descriptors takes precedence.
|
|
1537
|
-
let tmpDescriptorAddresses=Object.keys(tmpSource);tmpDescriptorAddresses.forEach(pDescriptorAddress=>{if(!
|
|
1538
|
+
let tmpDescriptorAddresses=Object.keys(tmpSource);tmpDescriptorAddresses.forEach(pDescriptorAddress=>{if(!(pDescriptorAddress in tmpNewManyfestSchemaDescriptors)){tmpNewManyfestSchemaDescriptors[pDescriptorAddress]=tmpSource[pDescriptorAddress];}});return tmpNewManyfestSchemaDescriptors;}}module.exports=ManyfestSchemaManipulation;},{"./Manyfest-LogToConsole.js":71}],80:[function(require,module,exports){/**
|
|
1538
1539
|
* @author <steven@velozo.com>
|
|
1539
1540
|
*/const libFableServiceProviderBase=require('fable-serviceproviderbase');let libSimpleLog=require('./Manyfest-LogToConsole.js');let libHashTranslation=require('./Manyfest-HashTranslation.js');let libObjectAddressCheckAddressExists=require('./Manyfest-ObjectAddress-CheckAddressExists.js');let libObjectAddressGetValue=require('./Manyfest-ObjectAddress-GetValue.js');let libObjectAddressSetValue=require('./Manyfest-ObjectAddress-SetValue.js');let libObjectAddressDeleteValue=require('./Manyfest-ObjectAddress-DeleteValue.js');let libObjectAddressGeneration=require('./Manyfest-ObjectAddressGeneration.js');let libSchemaManipulation=require('./Manyfest-SchemaManipulation.js');const _DefaultConfiguration={Scope:'DEFAULT',Descriptors:{}};/**
|
|
1540
1541
|
* Manyfest object address-based descriptions and manipulations.
|
|
@@ -1542,7 +1543,7 @@ let tmpDescriptorAddresses=Object.keys(tmpSource);tmpDescriptorAddresses.forEach
|
|
|
1542
1543
|
* @class Manyfest
|
|
1543
1544
|
*/class Manyfest extends libFableServiceProviderBase{constructor(pFable,pManifest,pServiceHash){if(pFable===undefined){super({});}else{super(pFable,pManifest,pServiceHash);}this.serviceType='Manifest';// Wire in logging
|
|
1544
1545
|
this.logInfo=libSimpleLog;this.logError=libSimpleLog;// Create an object address resolver and map in the functions
|
|
1545
|
-
this.objectAddressCheckAddressExists=new libObjectAddressCheckAddressExists(this.logInfo,this.logError);this.objectAddressGetValue=new libObjectAddressGetValue(this.logInfo,this.logError);this.objectAddressSetValue=new libObjectAddressSetValue(this.logInfo,this.logError);this.objectAddressDeleteValue=new libObjectAddressDeleteValue(this.logInfo,this.logError);if(!
|
|
1546
|
+
this.objectAddressCheckAddressExists=new libObjectAddressCheckAddressExists(this.logInfo,this.logError);this.objectAddressGetValue=new libObjectAddressGetValue(this.logInfo,this.logError);this.objectAddressSetValue=new libObjectAddressSetValue(this.logInfo,this.logError);this.objectAddressDeleteValue=new libObjectAddressDeleteValue(this.logInfo,this.logError);if(!('defaultValues'in this.options)){this.options.defaultValues={"String":"","Number":0,"Float":0.0,"Integer":0,"Boolean":false,"Binary":0,"DateTime":0,"Array":[],"Object":{},"Null":null};}if(!('strict'in this.options)){this.options.strict=false;}this.scope=undefined;this.elementAddresses=undefined;this.elementHashes=undefined;this.elementDescriptors=undefined;this.reset();if(typeof this.options==='object'){this.loadManifest(this.options);}this.schemaManipulations=new libSchemaManipulation(this.logInfo,this.logError);this.objectAddressGeneration=new libObjectAddressGeneration(this.logInfo,this.logError);this.hashTranslations=new libHashTranslation(this.logInfo,this.logError);}/*************************************************************************
|
|
1546
1547
|
* Schema Manifest Loading, Reading, Manipulation and Serialization Functions
|
|
1547
1548
|
*/ // Reset critical manifest properties
|
|
1548
1549
|
reset(){this.scope='DEFAULT';this.elementAddresses=[];this.elementHashes={};this.elementDescriptors={};}clone(){// Make a copy of the options in-place
|
|
@@ -1550,13 +1551,13 @@ let tmpNewOptions=JSON.parse(JSON.stringify(this.options));let tmpNewManyfest=ne
|
|
|
1550
1551
|
tmpNewManyfest.hashTranslations.addTranslation(this.hashTranslations.translationTable);return tmpNewManyfest;}// Deserialize a Manifest from a string
|
|
1551
1552
|
deserialize(pManifestString){// TODO: Add guards for bad manifest string
|
|
1552
1553
|
return this.loadManifest(JSON.parse(pManifestString));}// Load a manifest from an object
|
|
1553
|
-
loadManifest(pManifest){if(typeof pManifest!=='object'){this.logError("(".concat(this.scope,") Error loading manifest; expecting an object but parameter was type ").concat(typeof pManifest,"."));}let tmpManifest=typeof pManifest=='object'?pManifest:{};let tmpDescriptorKeys=Object.keys(_DefaultConfiguration);for(let i=0;i<tmpDescriptorKeys.length;i++){if(!
|
|
1554
|
+
loadManifest(pManifest){if(typeof pManifest!=='object'){this.logError("(".concat(this.scope,") Error loading manifest; expecting an object but parameter was type ").concat(typeof pManifest,"."));}let tmpManifest=typeof pManifest=='object'?pManifest:{};let tmpDescriptorKeys=Object.keys(_DefaultConfiguration);for(let i=0;i<tmpDescriptorKeys.length;i++){if(!(tmpDescriptorKeys[i]in tmpManifest)){tmpManifest[tmpDescriptorKeys[i]]=JSON.parse(JSON.stringify(_DefaultConfiguration[tmpDescriptorKeys[i]]));}}if('Scope'in tmpManifest){if(typeof tmpManifest.Scope==='string'){this.scope=tmpManifest.Scope;}else{this.logError("(".concat(this.scope,") Error loading scope from manifest; expecting a string but property was type ").concat(typeof tmpManifest.Scope,"."),tmpManifest);}}else{this.logError("(".concat(this.scope,") Error loading scope from manifest object. Property \"Scope\" does not exist in the root of the object."),tmpManifest);}if('Descriptors'in tmpManifest){if(typeof tmpManifest.Descriptors==='object'){let tmpDescriptionAddresses=Object.keys(tmpManifest.Descriptors);for(let i=0;i<tmpDescriptionAddresses.length;i++){this.addDescriptor(tmpDescriptionAddresses[i],tmpManifest.Descriptors[tmpDescriptionAddresses[i]]);}}else{this.logError("(".concat(this.scope,") Error loading description object from manifest object. Expecting an object in 'Manifest.Descriptors' but the property was type ").concat(typeof tmpManifest.Descriptors,"."),tmpManifest);}}else{this.logError("(".concat(this.scope,") Error loading object description from manifest object. Property \"Descriptors\" does not exist in the root of the Manifest object."),tmpManifest);}if('HashTranslations'in tmpManifest){if(typeof tmpManifest.HashTranslations==='object'){for(let i=0;i<tmpManifest.HashTranslations.length;i++){// Each translation is
|
|
1554
1555
|
}}}}// Serialize the Manifest to a string
|
|
1555
1556
|
serialize(){return JSON.stringify(this.getManifest());}getManifest(){return{Scope:this.scope,Descriptors:JSON.parse(JSON.stringify(this.elementDescriptors)),HashTranslations:JSON.parse(JSON.stringify(this.hashTranslations.translationTable))};}// Add a descriptor to the manifest
|
|
1556
1557
|
addDescriptor(pAddress,pDescriptor){if(typeof pDescriptor==='object'){// Add the Address into the Descriptor if it doesn't exist:
|
|
1557
|
-
if(!
|
|
1558
|
+
if(!('Address'in pDescriptor)){pDescriptor.Address=pAddress;}if(!(pAddress in this.elementDescriptors)){this.elementAddresses.push(pAddress);}// Add the element descriptor to the schema
|
|
1558
1559
|
this.elementDescriptors[pAddress]=pDescriptor;// Always add the address as a hash
|
|
1559
|
-
this.elementHashes[pAddress]=pAddress;if(
|
|
1560
|
+
this.elementHashes[pAddress]=pAddress;if('Hash'in pDescriptor){// TODO: Check if this is a good idea or not..
|
|
1560
1561
|
// Collisions are bound to happen with both representations of the address/hash in here and developers being able to create their own hashes.
|
|
1561
1562
|
this.elementHashes[pDescriptor.Hash]=pAddress;}else{pDescriptor.Hash=pAddress;}return true;}else{this.logError("(".concat(this.scope,") Error loading object descriptor for address '").concat(pAddress,"' from manifest object. Expecting an object but property was type ").concat(typeof pDescriptor,"."));return false;}}getDescriptorByHash(pHash){return this.getDescriptor(this.resolveHashAddress(pHash));}getDescriptor(pAddress){return this.elementDescriptors[pAddress];}// execute an action function for each descriptor
|
|
1562
1563
|
eachDescriptor(fAction){let tmpDescriptorAddresses=Object.keys(this.elementDescriptors);for(let i=0;i<tmpDescriptorAddresses.length;i++){fAction(this.elementDescriptors[tmpDescriptorAddresses[i]]);}}/*************************************************************************
|
|
@@ -1564,9 +1565,9 @@ eachDescriptor(fAction){let tmpDescriptorAddresses=Object.keys(this.elementDescr
|
|
|
1564
1565
|
*/ // Check if an element exists by its hash
|
|
1565
1566
|
checkAddressExistsByHash(pObject,pHash){return this.checkAddressExists(pObject,this.resolveHashAddress(pHash));}// Check if an element exists at an address
|
|
1566
1567
|
checkAddressExists(pObject,pAddress){return this.objectAddressCheckAddressExists.checkAddressExists(pObject,pAddress);}// Turn a hash into an address, factoring in the translation table.
|
|
1567
|
-
resolveHashAddress(pHash){let tmpAddress=undefined;let tmpInElementHashTable=this.elementHashes
|
|
1568
|
+
resolveHashAddress(pHash){let tmpAddress=undefined;let tmpInElementHashTable=(pHash in this.elementHashes);let tmpInTranslationTable=(pHash in this.hashTranslations.translationTable);// The most straightforward: the hash exists, no translations.
|
|
1568
1569
|
if(tmpInElementHashTable&&!tmpInTranslationTable){tmpAddress=this.elementHashes[pHash];}// There is a translation from one hash to another, and, the elementHashes contains the pointer end
|
|
1569
|
-
else if(tmpInTranslationTable&&this.
|
|
1570
|
+
else if(tmpInTranslationTable&&this.hashTranslations.translate(pHash)in this.elementHashes){tmpAddress=this.elementHashes[this.hashTranslations.translate(pHash)];}// Use the level of indirection only in the Translation Table
|
|
1570
1571
|
else if(tmpInTranslationTable){tmpAddress=this.hashTranslations.translate(pHash);}// Just treat the hash as an address.
|
|
1571
1572
|
// TODO: Discuss this ... it is magic but controversial
|
|
1572
1573
|
else{tmpAddress=pHash;}return tmpAddress;}// Get the value of an element by its hash
|
|
@@ -1586,12 +1587,12 @@ if(tmpDescriptor.DataType){let tmpElementType=typeof tmpValue;switch(tmpDescript
|
|
|
1586
1587
|
addValidationError(tmpDescriptor.Address,"has a DataType ".concat(tmpDescriptor.DataType," but has a decimal point in the number."));}}break;case'float':if(tmpElementType!='number'){addValidationError(tmpDescriptor.Address,"has a DataType ".concat(tmpDescriptor.DataType," but is of the type ").concat(tmpElementType));}break;case'DateTime':let tmpValueDate=new Date(tmpValue);if(tmpValueDate.toString()=='Invalid Date'){addValidationError(tmpDescriptor.Address,"has a DataType ".concat(tmpDescriptor.DataType," but is not parsable as a Date by Javascript"));}default:// Check if this is a string, in the default case
|
|
1587
1588
|
// Note this is only when a DataType is specified and it is an unrecognized data type.
|
|
1588
1589
|
if(tmpElementType!='string'){addValidationError(tmpDescriptor.Address,"has a DataType ".concat(tmpDescriptor.DataType," (which auto-converted to String because it was unrecognized) but is of the type ").concat(tmpElementType));}break;}}}return tmpValidationData;}// Returns a default value, or, the default value for the data type (which is overridable with configuration)
|
|
1589
|
-
getDefaultValue(pDescriptor){if(typeof pDescriptor!='object'){return undefined;}if(
|
|
1590
|
+
getDefaultValue(pDescriptor){if(typeof pDescriptor!='object'){return undefined;}if('Default'in pDescriptor){return pDescriptor.Default;}else{// Default to a null if it doesn't have a type specified.
|
|
1590
1591
|
// This will ensure a placeholder is created but isn't misinterpreted.
|
|
1591
|
-
let tmpDataType=
|
|
1592
|
+
let tmpDataType='DataType'in pDescriptor?pDescriptor.DataType:'String';if(tmpDataType in this.options.defaultValues){return this.options.defaultValues[tmpDataType];}else{// give up and return null
|
|
1592
1593
|
return null;}}}// Enumerate through the schema and populate default values if they don't exist.
|
|
1593
1594
|
populateDefaults(pObject,pOverwriteProperties){return this.populateObject(pObject,pOverwriteProperties,// This just sets up a simple filter to see if there is a default set.
|
|
1594
|
-
pDescriptor=>{return
|
|
1595
|
+
pDescriptor=>{return'Default'in pDescriptor;});}// Forcefully populate all values even if they don't have defaults.
|
|
1595
1596
|
// Based on type, this can do unexpected things.
|
|
1596
1597
|
populateObject(pObject,pOverwriteProperties,fFilter){// Automatically create an object if one isn't passed in.
|
|
1597
1598
|
let tmpObject=typeof pObject==='object'?pObject:{};// Default to *NOT OVERWRITING* properties
|
|
@@ -3017,32 +3018,32 @@ this.connectFable(this);// --> Bootstrapping of fable into the Service Manager i
|
|
|
3017
3018
|
// They will then be available in the Default service provider set as well.
|
|
3018
3019
|
this.connectPreinitServiceProviderInstance(this.UUID);this.connectPreinitServiceProviderInstance(this.Logging);this.connectPreinitServiceProviderInstance(this.SettingsManager);// Initialize and instantiate the default baked-in Data Arithmatic service
|
|
3019
3020
|
this.addAndInstantiateServiceType('EnvironmentData',require('./services/Fable-Service-EnvironmentData.js'));this.addServiceType('Template',require('./services/Fable-Service-Template.js'));this.addServiceType('MetaTemplate',require('./services/Fable-Service-MetaTemplate.js'));this.addServiceType('Anticipate',require('./services/Fable-Service-Anticipate.js'));this.addAndInstantiateServiceType('Dates',require('./services/Fable-Service-DateManipulation.js'));this.addAndInstantiateServiceType('DataFormat',require('./services/Fable-Service-DataFormat.js'));this.addAndInstantiateServiceType('DataGeneration',require('./services/Fable-Service-DataGeneration.js'));this.addAndInstantiateServiceType('Utility',require('./services/Fable-Service-Utility.js'));this.addAndInstantiateServiceType('Math',require('./services/Fable-Service-Math.js'));this.addServiceType('ExpressionParser',require('./services/Fable-Service-ExpressionParser.js'));this.addServiceType('RestClient',require('./services/Fable-Service-RestClient.js'));this.addServiceType('Manifest',require('manyfest'));this.addServiceType('ObjectCache',require('cachetrax'));this.addAndInstantiateServiceType('ProgressTime',require('./services/Fable-Service-ProgressTime.js'));this.addServiceType('ProgressTrackerSet',require('./services/Fable-Service-ProgressTrackerSet.js'));this.addServiceType('Operation',require('./services/Fable-Service-Operation.js'));this.addServiceType('CSVParser',require('./services/Fable-Service-CSVParser.js'));this.addServiceType('FilePersistence',require('./services/Fable-Service-FilePersistence.js'));}/* State Accessors */get isFable(){return true;}get settings(){return this.SettingsManager.settings;}get settingsManager(){return this.SettingsManager;}// For backwards compatibility
|
|
3020
|
-
getUUID(){return this.UUID.getUUID();}newAnticipate(){return this.instantiateServiceProviderWithoutRegistration('Anticipate');}newManyfest(pManifestDefinition){return this.instantiateServiceProviderWithoutRegistration('Manifest',pManifestDefinition);}/* Service Manager Methods */addServiceType(pServiceType,pServiceClass){if(this.servicesMap
|
|
3021
|
+
getUUID(){return this.UUID.getUUID();}newAnticipate(){return this.instantiateServiceProviderWithoutRegistration('Anticipate');}newManyfest(pManifestDefinition){return this.instantiateServiceProviderWithoutRegistration('Manifest',pManifestDefinition);}/* Service Manager Methods */addServiceType(pServiceType,pServiceClass){if(pServiceType in this.servicesMap){// TODO: Check if any services are running?
|
|
3021
3022
|
this.log.warn("Adding a service type [".concat(pServiceType,"] that already exists. This will change the default class prototype for this service."));}else{// Add the container for instantiated services to go in
|
|
3022
3023
|
this.servicesMap[pServiceType]={};// Add the type to the list of types
|
|
3023
3024
|
this.serviceTypes.push(pServiceType);}// Using the static member of the class is a much more reliable way to check if it is a service class than instanceof
|
|
3024
3025
|
if(typeof pServiceClass=='function'&&pServiceClass.isFableService){// Add the class to the list of classes
|
|
3025
3026
|
this.serviceClasses[pServiceType]=pServiceClass;}else{// Add the base class to the list of classes
|
|
3026
|
-
this.log.error("Attempted to add service type [".concat(pServiceType,"] with an invalid class. Using base service class, which will not crash but won't provide meaningful services."));this.serviceClasses[pServiceType]=libFableServiceBase;}return this.serviceClasses[pServiceType];}addServiceTypeIfNotExists(pServiceType,pServiceClass){if(!this.servicesMap
|
|
3027
|
-
addAndInstantiateServiceType(pServiceType,pServiceClass){this.addServiceType(pServiceType,pServiceClass);return this.instantiateServiceProvider(pServiceType,{},"".concat(pServiceType,"-Default"));}addAndInstantiateServiceTypeIfNotExists(pServiceType,pServiceClass){if(!this.servicesMap
|
|
3027
|
+
this.log.error("Attempted to add service type [".concat(pServiceType,"] with an invalid class. Using base service class, which will not crash but won't provide meaningful services."));this.serviceClasses[pServiceType]=libFableServiceBase;}return this.serviceClasses[pServiceType];}addServiceTypeIfNotExists(pServiceType,pServiceClass){if(!(pServiceType in this.servicesMap)){return this.addServiceType(pServiceType,pServiceClass);}else{return this.serviceClasses[pServiceType];}}// This is for the services that are meant to run mostly single-instance so need a default at initialization
|
|
3028
|
+
addAndInstantiateServiceType(pServiceType,pServiceClass){this.addServiceType(pServiceType,pServiceClass);return this.instantiateServiceProvider(pServiceType,{},"".concat(pServiceType,"-Default"));}addAndInstantiateServiceTypeIfNotExists(pServiceType,pServiceClass){if(!(pServiceType in this.servicesMap)){return this.instantiateServiceProvider(pServiceType,{},"".concat(pServiceType,"-Default"));}else{return this.serviceClasses[pServiceType];}}// Some services expect to be overloaded / customized class.
|
|
3028
3029
|
instantiateServiceProviderFromPrototype(pServiceType,pOptions,pCustomServiceHash,pServicePrototype){// Instantiate the service
|
|
3029
3030
|
let tmpService=new pServicePrototype(this,pOptions,pCustomServiceHash);if(this.extraServiceInitialization){tmpService=this.extraServiceInitialization(tmpService);}// Add the service to the service map
|
|
3030
3031
|
this.servicesMap[pServiceType][tmpService.Hash]=tmpService;// If this is the first service of this type, make it the default
|
|
3031
|
-
if(!this.services
|
|
3032
|
+
if(!(pServiceType in this.services)){this.setDefaultServiceInstantiation(pServiceType,tmpService.Hash);}return tmpService;}instantiateServiceProvider(pServiceType,pOptions,pCustomServiceHash){// Instantiate the service
|
|
3032
3033
|
let tmpService=this.instantiateServiceProviderWithoutRegistration(pServiceType,pOptions,pCustomServiceHash);// Add the service to the service map
|
|
3033
3034
|
this.servicesMap[pServiceType][tmpService.Hash]=tmpService;// If this is the first service of this type, make it the default
|
|
3034
|
-
if(!this.services
|
|
3035
|
+
if(!(pServiceType in this.services)){this.setDefaultServiceInstantiation(pServiceType,tmpService.Hash);}return tmpService;}instantiateServiceProviderIfNotExists(pServiceType,pOptions,pCustomServiceHash){if(pServiceType in this.services){return this.services[pServiceType];}else{return this.instantiateServiceProvider(pServiceType,pOptions,pCustomServiceHash);}}// Create a service provider but don't register it to live forever in fable.services
|
|
3035
3036
|
instantiateServiceProviderWithoutRegistration(pServiceType,pOptions,pCustomServiceHash){// Instantiate the service
|
|
3036
3037
|
let tmpService=new this.serviceClasses[pServiceType](this,pOptions,pCustomServiceHash);if(this.extraServiceInitialization){tmpService=this.extraServiceInitialization(tmpService);}return tmpService;}// Connect an initialized service provider that came before Fable was initialized
|
|
3037
3038
|
connectPreinitServiceProviderInstance(pServiceInstance){let tmpServiceType=pServiceInstance.serviceType;let tmpServiceHash=pServiceInstance.Hash;// The service should already be instantiated, so just connect it to fable
|
|
3038
3039
|
pServiceInstance.connectFable(this);// Add the service type to the map if it isn't there yet
|
|
3039
|
-
if(!this.servicesMap
|
|
3040
|
+
if(!(tmpServiceType in this.servicesMap)){// If the core service hasn't registered itself yet, create the service container for it.
|
|
3040
3041
|
// This means you couldn't register another with this type unless it was later registered with a constructor class.
|
|
3041
3042
|
this.servicesMap[tmpServiceType]={};}// Add the service to the service map
|
|
3042
3043
|
this.servicesMap[tmpServiceType][tmpServiceHash]=pServiceInstance;// If this is the first service of this type, make it the default
|
|
3043
|
-
if(!this.services
|
|
3044
|
+
if(!(tmpServiceType in this.services)){this.setDefaultServiceInstantiation(tmpServiceType,tmpServiceHash,false);}return pServiceInstance;}setDefaultServiceInstantiation(pServiceType,pServiceHash,pOverwriteService){// Overwrite services by default, unless told not to
|
|
3044
3045
|
let tmpOverwriteService=typeof pOverwriteService==='undefined'?true:pOverwriteService;// Make sure the service exists
|
|
3045
|
-
if(this.servicesMap[pServiceType]
|
|
3046
|
+
if(pServiceHash in this.servicesMap[pServiceType]){if(!(pServiceType in this)||tmpOverwriteService){this[pServiceType]=this.servicesMap[pServiceType][pServiceHash];}if(!(pServiceType in this.services)||tmpOverwriteService){this.services[pServiceType]=this.servicesMap[pServiceType][pServiceHash];}return true;}return false;}}// This is for backwards compatibility
|
|
3046
3047
|
function autoConstruct(pSettings){return new Fable(pSettings);}module.exports=Fable;module.exports.new=autoConstruct;module.exports.LogProviderBase=libFableLog.LogProviderBase;module.exports.ServiceProviderBase=libFableServiceBase;module.exports.CoreServiceProviderBase=libFableServiceBase.CoreServiceProviderBase;module.exports.precedent=libFableSettings.precedent;},{"./services/Fable-Service-Anticipate.js":128,"./services/Fable-Service-CSVParser.js":129,"./services/Fable-Service-DataFormat.js":130,"./services/Fable-Service-DataGeneration.js":132,"./services/Fable-Service-DateManipulation.js":133,"./services/Fable-Service-EnvironmentData.js":134,"./services/Fable-Service-ExpressionParser.js":135,"./services/Fable-Service-FilePersistence.js":143,"./services/Fable-Service-Math.js":144,"./services/Fable-Service-MetaTemplate.js":145,"./services/Fable-Service-Operation.js":149,"./services/Fable-Service-ProgressTime.js":150,"./services/Fable-Service-ProgressTrackerSet.js":152,"./services/Fable-Service-RestClient.js":153,"./services/Fable-Service-Template.js":154,"./services/Fable-Service-Utility.js":155,"cachetrax":22,"fable-log":50,"fable-serviceproviderbase":51,"fable-settings":54,"fable-uuid":56,"manyfest":80}],128:[function(require,module,exports){const libFableServiceBase=require('fable-serviceproviderbase');class FableServiceAnticipate extends libFableServiceBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='AsyncAnticipate';// The queue of operations waiting to run.
|
|
3047
3048
|
this.operationQueue=[];this.erroredOperations=[];this.executingOperationCount=0;this.completedOperationCount=0;this.callDepth=0;this.maxOperations=1;this.lastError=undefined;this.waitingFunctions=[];}checkQueue(){// This could be combined with the last else if stanza but the logic for errors and non-errors would be blended and more complex to follow so keeping it unrolled.
|
|
3048
3049
|
if(this.lastError){// If there are no operations left, and we have waiting functions, call them.
|
|
@@ -3250,9 +3251,9 @@ getMonthFromDate(pJavascriptDate){var tmpMonths=["January","February","March","A
|
|
|
3250
3251
|
if(tmpString[i]==tmpSeparator// AND we are not in a nested portion of the string
|
|
3251
3252
|
&&tmpEnclosureStack.length==0){// Increment the segment count
|
|
3252
3253
|
tmpSegmentCount++;}// IF This is the start of an enclosure
|
|
3253
|
-
else if(
|
|
3254
|
+
else if(tmpString[i]in tmpEnclosureStartSymbolMap){// Add it to the stack!
|
|
3254
3255
|
tmpEnclosureStack.push(tmpEnclosureStartSymbolMap[tmpString[i]]);}// IF This is the end of an enclosure
|
|
3255
|
-
else if(
|
|
3256
|
+
else if(tmpString[i]in tmpEnclosureEndSymbolMap// AND it matches the current nest level symbol
|
|
3256
3257
|
&&tmpEnclosureEndSymbolMap[tmpString[i]]==tmpEnclosureStack[tmpEnclosureStack.length-1]){// Pop it off the stack!
|
|
3257
3258
|
tmpEnclosureStack.pop();}}return tmpSegmentCount;}/**
|
|
3258
3259
|
* Get all segments in a string, respecting enclosures
|
|
@@ -3266,9 +3267,9 @@ tmpEnclosureStack.pop();}}return tmpSegmentCount;}/**
|
|
|
3266
3267
|
if(tmpString[i]==tmpSeparator// AND we are not in a nested portion of the string
|
|
3267
3268
|
&&tmpEnclosureStack.length==0){// Return the segment
|
|
3268
3269
|
tmpSegmentList.push(tmpString.substring(tmpCurrentSegmentStart,i));tmpCurrentSegmentStart=i+1;}// IF This is the start of an enclosure
|
|
3269
|
-
else if(
|
|
3270
|
+
else if(tmpString[i]in tmpEnclosureStartSymbolMap){// Add it to the stack!
|
|
3270
3271
|
tmpEnclosureStack.push(tmpEnclosureStartSymbolMap[tmpString[i]]);}// IF This is the end of an enclosure
|
|
3271
|
-
else if(
|
|
3272
|
+
else if(tmpString[i]in tmpEnclosureEndSymbolMap// AND it matches the current nest level symbol
|
|
3272
3273
|
&&tmpEnclosureEndSymbolMap[tmpString[i]]==tmpEnclosureStack[tmpEnclosureStack.length-1]){// Pop it off the stack!
|
|
3273
3274
|
tmpEnclosureStack.pop();}}if(tmpCurrentSegmentStart<tmpString.length){tmpSegmentList.push(tmpString.substring(tmpCurrentSegmentStart));}return tmpSegmentList;}/**
|
|
3274
3275
|
* Get the first segment in a string, respecting enclosures
|
|
@@ -3282,9 +3283,9 @@ tmpEnclosureStack.pop();}}if(tmpCurrentSegmentStart<tmpString.length){tmpSegment
|
|
|
3282
3283
|
if(tmpString[i]==tmpSeparator// AND we are not in a nested portion of the string
|
|
3283
3284
|
&&tmpEnclosureStack.length==0){// Return the segment
|
|
3284
3285
|
return tmpString.substring(0,i);}// IF This is the start of an enclosure
|
|
3285
|
-
else if(
|
|
3286
|
+
else if(tmpString[i]in tmpEnclosureStartSymbolMap){// Add it to the stack!
|
|
3286
3287
|
tmpEnclosureStack.push(tmpEnclosureStartSymbolMap[tmpString[i]]);}// IF This is the end of an enclosure
|
|
3287
|
-
else if(
|
|
3288
|
+
else if(tmpString[i]in tmpEnclosureEndSymbolMap// AND it matches the current nest level symbol
|
|
3288
3289
|
&&tmpEnclosureEndSymbolMap[tmpString[i]]==tmpEnclosureStack[tmpEnclosureStack.length-1]){// Pop it off the stack!
|
|
3289
3290
|
tmpEnclosureStack.pop();}}return tmpString;}/**
|
|
3290
3291
|
* Count the number of enclosures in a string based on the start and end characters.
|
|
@@ -3371,10 +3372,10 @@ let tmpValue=tmpManifest.getValueByHash(tmpDataSource,tmpToken.Token);// if (!tm
|
|
|
3371
3372
|
// }
|
|
3372
3373
|
if(!tmpValue){tmpResults.ExpressionParserLog.push("WARNING: ExpressionParser.substituteValuesInTokenizedObjects found no value for the symbol hash or address ".concat(tmpToken.Token," at index ").concat(i));this.log.warn(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);continue;}else{tmpResults.ExpressionParserLog.push("INFO: ExpressionParser.substituteValuesInTokenizedObjects found a value [".concat(tmpValue,"] for the state address ").concat(tmpToken.Token," at index ").concat(i));this.log.info(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);try{let tmpValueParsed=new this.fable.Utility.bigNumber(tmpValue);tmpToken.Resolved=true;tmpToken.Value=tmpValueParsed.toString();}catch(pError){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.substituteValuesInTokenizedObjects found a non-numeric value for the state address ".concat(tmpToken.Token," at index ").concat(i));this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);tmpToken.Resolved=false;}}}if(pTokenizedObjects[i].Type==='Token.StateAddress'&&!tmpToken.Resolved){// Symbols are always hashes. This gracefully works for simple shallow objects because hashes default to the address in Manyfest.
|
|
3373
3374
|
let tmpValue=tmpManifest.getValueAtAddress(tmpDataSource,tmpToken.Token);if(!tmpValue){tmpResults.ExpressionParserLog.push("WARNING: ExpressionParser.substituteValuesInTokenizedObjects found no value for the state address ".concat(tmpToken.Token," at index ").concat(i));this.log.warn(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);continue;}else{tmpResults.ExpressionParserLog.push("INFO: ExpressionParser.substituteValuesInTokenizedObjects found a value [".concat(tmpValue,"] for the state address ").concat(tmpToken.Token," at index ").concat(i));this.log.info(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);try{let tmpValueParsed=new this.fable.Utility.bigNumber(tmpValue);tmpToken.Resolved=true;tmpToken.Value=tmpValueParsed.toString();}catch(pError){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.substituteValuesInTokenizedObjects found a non-numeric value for the state address ".concat(tmpToken.Token," at index ").concat(i));this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);tmpToken.Resolved=false;}}}if(pTokenizedObjects[i].Type==='Token.Constant'&&!tmpToken.Resolved){tmpResults.ExpressionParserLog.push("INFO: ExpressionParser.substituteValuesInTokenizedObjects found a value [".concat(tmpToken.Token,"] for the constant ").concat(tmpToken.Token," at index ").concat(i));this.log.info(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);try{let tmpValueParsed=new this.fable.Utility.bigNumber(tmpToken.Token);tmpToken.Resolved=true;tmpToken.Value=tmpValueParsed.toString();}catch(pError){// This constant has the right symbols but apparently isn't a parsable number.
|
|
3374
|
-
tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.substituteValuesInTokenizedObjects found a non-numeric value for the state address ".concat(tmpToken.Token," at index ").concat(i));this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);tmpToken.Resolved=false;}}}return pTokenizedObjects;}tokenize(pExpression,pResultObject){return this.Tokenizer.tokenize(pExpression,pResultObject);}lintTokenizedExpression(pTokenizedExpression,pResultObject){return this.Linter.lintTokenizedExpression(pTokenizedExpression,pResultObject);}buildPostfixedSolveList(pTokenizedExpression,pResultObject){return this.Postfix.buildPostfixedSolveList(pTokenizedExpression,pResultObject);}solvePostfixedExpression(pPostfixedExpression,pDataDestinationObject,pResultObject,pManifest){return this.Solver.solvePostfixedExpression(pPostfixedExpression,pDataDestinationObject,pResultObject,pManifest);}solve(pExpression,pDataSourceObject,pResultObject,pManifest,pDataDestinationObject){let tmpResultsObject=typeof pResultObject==='object'?pResultObject:{};let tmpDataSourceObject=typeof pDataSourceObject==='object'?pDataSourceObject:{};let tmpDataDestinationObject=typeof pDataDestinationObject==='object'?pDataDestinationObject:{};this.tokenize(pExpression,tmpResultsObject);this.lintTokenizedExpression(tmpResultsObject.RawTokens,tmpResultsObject);this.buildPostfixedSolveList(tmpResultsObject.RawTokens,tmpResultsObject);this.substituteValuesInTokenizedObjects(tmpResultsObject.PostfixTokenObjects,tmpDataSourceObject,tmpResultsObject,pManifest);return this.solvePostfixedExpression(tmpResultsObject.PostfixSolveList,tmpDataDestinationObject,tmpResultsObject,pManifest);}}module.exports=FableServiceExpressionParser;},{"./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-ExpressionTokenizer.js":137,"./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-FunctionMap.json":138,"./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-Linter.js":139,"./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-Postfix.js":140,"./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-SolvePostfixedExpression.js":141,"./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-TokenMap.json":142,"big.js":17,"fable-serviceproviderbase":51}],136:[function(require,module,exports){const libFableServiceProviderBase=require('fable-serviceproviderbase');class ExpressionParserOperationBase extends libFableServiceProviderBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='ExpressionParserOperationBase';this.numberTest=/^-{0,1}\d*\.{0,1}\d+$/;this.ExpressionParser=false;}connectExpressionParser(pExpressionParser){this.ExpressionParser=pExpressionParser;}getTokenType(pToken){if(this.ExpressionParser.tokenMap
|
|
3375
|
+
tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.substituteValuesInTokenizedObjects found a non-numeric value for the state address ".concat(tmpToken.Token," at index ").concat(i));this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);tmpToken.Resolved=false;}}}return pTokenizedObjects;}tokenize(pExpression,pResultObject){return this.Tokenizer.tokenize(pExpression,pResultObject);}lintTokenizedExpression(pTokenizedExpression,pResultObject){return this.Linter.lintTokenizedExpression(pTokenizedExpression,pResultObject);}buildPostfixedSolveList(pTokenizedExpression,pResultObject){return this.Postfix.buildPostfixedSolveList(pTokenizedExpression,pResultObject);}solvePostfixedExpression(pPostfixedExpression,pDataDestinationObject,pResultObject,pManifest){return this.Solver.solvePostfixedExpression(pPostfixedExpression,pDataDestinationObject,pResultObject,pManifest);}solve(pExpression,pDataSourceObject,pResultObject,pManifest,pDataDestinationObject){let tmpResultsObject=typeof pResultObject==='object'?pResultObject:{};let tmpDataSourceObject=typeof pDataSourceObject==='object'?pDataSourceObject:{};let tmpDataDestinationObject=typeof pDataDestinationObject==='object'?pDataDestinationObject:{};this.tokenize(pExpression,tmpResultsObject);this.lintTokenizedExpression(tmpResultsObject.RawTokens,tmpResultsObject);this.buildPostfixedSolveList(tmpResultsObject.RawTokens,tmpResultsObject);this.substituteValuesInTokenizedObjects(tmpResultsObject.PostfixTokenObjects,tmpDataSourceObject,tmpResultsObject,pManifest);return this.solvePostfixedExpression(tmpResultsObject.PostfixSolveList,tmpDataDestinationObject,tmpResultsObject,pManifest);}}module.exports=FableServiceExpressionParser;},{"./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-ExpressionTokenizer.js":137,"./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-FunctionMap.json":138,"./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-Linter.js":139,"./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-Postfix.js":140,"./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-SolvePostfixedExpression.js":141,"./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-TokenMap.json":142,"big.js":17,"fable-serviceproviderbase":51}],136:[function(require,module,exports){const libFableServiceProviderBase=require('fable-serviceproviderbase');class ExpressionParserOperationBase extends libFableServiceProviderBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='ExpressionParserOperationBase';this.numberTest=/^-{0,1}\d*\.{0,1}\d+$/;this.ExpressionParser=false;}connectExpressionParser(pExpressionParser){this.ExpressionParser=pExpressionParser;}getTokenType(pToken){if(pToken in this.ExpressionParser.tokenMap){return"Token.".concat(this.ExpressionParser.tokenMap[pToken].Type);}else if(pToken.length>2&&pToken[0]==='{'&&pToken[pToken.length-1]==='}'){return'Token.StateAddress';}else if(this.numberTest.test(pToken)){return'Token.Constant';}else{return'Token.Symbol';}// Just for documentation sake:
|
|
3375
3376
|
// There is a fifth token type, VirtualSymbol
|
|
3376
3377
|
// This is a value that's added during solve and looked up by address in the VirtualSymbol object.
|
|
3377
|
-
}getTokenContainerObject(pToken,pTokenType){return{Token:pToken,Type:typeof pTokenType==='undefined'?this.getTokenType(pToken):pTokenType,Descriptor:this.ExpressionParser.tokenMap
|
|
3378
|
+
}getTokenContainerObject(pToken,pTokenType){return{Token:pToken,Type:typeof pTokenType==='undefined'?this.getTokenType(pToken):pTokenType,Descriptor:pToken in this.ExpressionParser.tokenMap?this.ExpressionParser.tokenMap[pToken]:false};}}module.exports=ExpressionParserOperationBase;},{"fable-serviceproviderbase":51}],137:[function(require,module,exports){const libExpressionParserOperationBase=require('./Fable-Service-ExpressionParser-Base.js');class ExpressionTokenizer extends libExpressionParserOperationBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='ExpressionParser-Tokenizer';}tokenize(pExpression,pResultObject){let tmpResults=typeof pResultObject==='object'?pResultObject:{ExpressionParserLog:[]};tmpResults.RawExpression=pExpression;tmpResults.RawTokens=[];tmpResults.ExpressionParserLog=[];if(typeof pExpression!=='string'){this.log.warn('ExpressionParser.tokenize was passed a non-string expression.');return tmpResults.RawTokens;}/* Tokenize the expression
|
|
3378
3379
|
*
|
|
3379
3380
|
* Current token types:
|
|
3380
3381
|
* - Value
|
|
@@ -3396,7 +3397,7 @@ if(tmpCurrentTokenType==='StateAddress'&&tmpCharacter==='}'){tmpCurrentToken+=tm
|
|
|
3396
3397
|
// TODO: Should we just ignore it? We do at the moment.
|
|
3397
3398
|
if(tmpCharacter=='}'){if(tmpCurrentToken.length>0){tmpResults.RawTokens.push(tmpCurrentToken);}tmpCurrentToken='';tmpCurrentTokenType=false;tmpResults.ExpressionParserLog.push("ExpressionParser.tokenize found a closing brace without an opening brace in the expression: ".concat(pExpression," at character index ").concat(i));this.log.warn(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);continue;}// 5. If we're not in an address and we hit an opening brace, we start an address
|
|
3398
3399
|
if(tmpCharacter=='{'){if(tmpCurrentToken.length>0){tmpResults.RawTokens.push(tmpCurrentToken);}tmpCurrentToken='';tmpCurrentTokenType='StateAddress';tmpCurrentToken=tmpCharacter;continue;}// [ TOKENS ]
|
|
3399
|
-
if(this.ExpressionParser.tokenMap
|
|
3400
|
+
if(tmpCharacter in this.ExpressionParser.tokenMap){if(tmpCurrentToken.length>0){tmpResults.RawTokens.push(tmpCurrentToken);}tmpCurrentToken='';tmpCurrentTokenType=false;tmpResults.RawTokens.push(tmpCharacter);continue;}// If it's not an operator, it's a number or address.
|
|
3400
3401
|
// At the moment we aren't going to gate it on whether it's a valid address or not
|
|
3401
3402
|
// Just treat anything not a known token on its own as a value identifier
|
|
3402
3403
|
/* Per this stack overflow article: https://stackoverflow.com/questions/4434076/best-way-to-alphanumeric-check-in-javascript
|
|
@@ -3440,7 +3441,7 @@ this.getTokenType(pTokenizedExpression[0])==='Token.StateAddress'||this.getToken
|
|
|
3440
3441
|
//|| (this.getTokenType(pTokenizedExpression[2]) === 'Token.StateAddress') || (this.getTokenType(pTokenizedExpression[0]) === 'Token.Symbol')
|
|
3441
3442
|
){tmpResults.ExpressionParserLog.push("WARNING: ExpressionParser.lintTokenizedExpression found a single equality assignment in the tokenized expression with no assignable address on the left side of the assignment.");tmpResults.LinterResults.push(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);this.log.warn(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);}}}// 5. Check that there are no operators adjacent to each other
|
|
3442
3443
|
// This is a simple lint check, not a full-blown syntax check
|
|
3443
|
-
let tmpTokenPrevious=false;for(let i=0;i<pTokenizedExpression.length-1;i++){if(this.ExpressionParser.tokenMap
|
|
3444
|
+
let tmpTokenPrevious=false;for(let i=0;i<pTokenizedExpression.length-1;i++){if(pTokenizedExpression[i]in this.ExpressionParser.tokenMap&&this.ExpressionParser.tokenMap[pTokenizedExpression[i]].Type!='Parenthesis'&&!tmpTokenPrevious){tmpTokenPrevious=true;}else if(pTokenizedExpression[i]in this.ExpressionParser.tokenMap&&this.ExpressionParser.tokenMap[pTokenizedExpression[i]].Type!='Parenthesis'){// If this isn't a + or - positivity/negativity multiplier, it's an error.
|
|
3444
3445
|
if(pTokenizedExpression[i]!=='+'&&pTokenizedExpression[i]!=='-'){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.lintTokenizedExpression found an ".concat(pTokenizedExpression[i]," operator adjacent to another operator in the tokenized expression at token index ").concat(i));tmpResults.LinterResults.push(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);}}else{tmpTokenPrevious=false;}}return tmpResults.LinterResults;}}module.exports=ExpressionParserLinter;},{"./Fable-Service-ExpressionParser-Base.js":136}],140:[function(require,module,exports){const libExpressionParserOperationBase=require('./Fable-Service-ExpressionParser-Base.js');class ExpressionParserPostfix extends libExpressionParserOperationBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='ExpressionParser-Postfix';}getPosfixSolveListOperation(pOperation,pLeftValue,pRightValue,pDepthSolveList,pDepthSolveIndex){let tmpOperation={VirtualSymbolName:pOperation.VirtualSymbolName,Operation:pOperation,LeftValue:pLeftValue,RightValue:pRightValue};let tmpDepthSolveList=Array.isArray(pDepthSolveList)?pDepthSolveList:false;// // Although we have a `Token.Type == "Parenthesis"` option to check on, keeping these explicit means the solver won't
|
|
3445
3446
|
// // allow users to pass in parenthesis in the wrong order.
|
|
3446
3447
|
// // The linter does blow up as does the postfix, but, just in case we'll leave these explicit.
|
|
@@ -3470,13 +3471,13 @@ if(pTokenizedExpression[i]!=='+'&&pTokenizedExpression[i]!=='-'){tmpResults.Expr
|
|
|
3470
3471
|
*/if(!tmpOperation.LeftValue.VirtualSymbolName){tmpOperation.LeftValue.VirtualSymbolName=tmpOperation.VirtualSymbolName;}else{// We need to set the left value to a virtual symbol instead of the looked up value if it's already used in another operation
|
|
3471
3472
|
tmpOperation.LeftValue=this.getTokenContainerObject(tmpOperation.LeftValue.VirtualSymbolName,'Token.VirtualSymbol');// Now walk backwards and see if we need to update a previous symbol for a previously unparsed operator
|
|
3472
3473
|
if(tmpDepthSolveList){for(let i=pDepthSolveIndex-1;i>=0;i--){if(tmpDepthSolveList[i].Type==='Token.Operator'&&!tmpDepthSolveList[i].Parsed&&// When walking backward, we only want to mutate if the .
|
|
3473
|
-
tmpDepthSolveList[i]
|
|
3474
|
+
'Descriptor'in tmpDepthSolveList[i]&&'Descriptor'in tmpOperation.Operation&&// Anything >3 does not have commutative properties
|
|
3474
3475
|
tmpDepthSolveList[i].Descriptor.Precedence>3){// If the symbol to its right is not the same as this operation
|
|
3475
3476
|
if(tmpDepthSolveList[i+1].VirtualSymbolName!==tmpOperation.VirtualSymbolName){// This is the recursive "shunting" being simulated
|
|
3476
3477
|
tmpDepthSolveList[i+1].VirtualSymbolName=tmpOperation.VirtualSymbolName;}break;}}}}if(!tmpOperation.RightValue.VirtualSymbolName){tmpOperation.RightValue.VirtualSymbolName=tmpOperation.VirtualSymbolName;}else{// We need to set the right value to a virtual symbol instead of the looked up value if it's already used in another operation
|
|
3477
3478
|
tmpOperation.RightValue=this.getTokenContainerObject(tmpOperation.RightValue.VirtualSymbolName,'Token.VirtualSymbol');// Now walk forwards and see if we need to update an upcoming symbol for a previously unparsed operator
|
|
3478
3479
|
if(tmpDepthSolveList){for(let i=pDepthSolveIndex+1;i<tmpDepthSolveList.length;i++){if(tmpDepthSolveList[i].Type==='Token.Operator'&&!tmpDepthSolveList[i].Parsed&&// When walking forward, we only want to mutate if the precedence hasn't been solved.
|
|
3479
|
-
tmpDepthSolveList[i]
|
|
3480
|
+
'Descriptor'in tmpDepthSolveList[i]&&'Descriptor'in tmpOperation.Operation&&// Anything >3 does not have commutative properties
|
|
3480
3481
|
tmpDepthSolveList[i].Descriptor.Precedence>3){// If the symbol to its right is not the same as this operation
|
|
3481
3482
|
if(tmpDepthSolveList[i-1].VirtualSymbolName!==tmpOperation.VirtualSymbolName){// This is the recursive "shunting" being simulated
|
|
3482
3483
|
tmpDepthSolveList[i-1].VirtualSymbolName=tmpOperation.VirtualSymbolName;}break;}else if(tmpDepthSolveList[i].Type==='Token.Operator'&&!tmpDepthSolveList[i].Parsed){break;}}}}tmpOperation.Operation.Parsed=true;return tmpOperation;}buildPostfixedSolveList(pTokenizedExpression,pResultObject){let tmpResults=typeof pResultObject==='object'?pResultObject:{ExpressionParserLog:[]};tmpResults.PostfixedAssignmentAddress='Result';tmpResults.PostfixTokenObjects=[];tmpResults.PostfixSolveList=[];if(pTokenizedExpression.length<3){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.buildPostfixedSolveList was passed a tokenized expression with less than three tokens.");this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);return tmpResults.PostfixTokenObjects;}// 1. Figure out the Equality Assignment
|
|
@@ -3520,7 +3521,7 @@ tmpResults.PostfixTokenObjects[i].Depth=tmpDepth;tmpResults.PostfixTokenObjects[
|
|
|
3520
3521
|
}// 4. If it's an operator or constant or comment, just set the depth
|
|
3521
3522
|
else{tmpResults.PostfixTokenObjects[i].Depth=tmpDepth;tmpResults.PostfixTokenObjects[i].SolveLayerStack=tmpSolveLayerStack[tmpSolveLayerStack.length-1];}}// 4. Walk through the decorated symbols and generate the postfix solve list
|
|
3522
3523
|
// We are going to start by creating a map of the solve layers:
|
|
3523
|
-
let tmpSolveLayerMap={};let tmpSolveLayerMaxDepth=0;for(let i=0;i<tmpResults.PostfixTokenObjects.length;i++){if(!
|
|
3524
|
+
let tmpSolveLayerMap={};let tmpSolveLayerMaxDepth=0;for(let i=0;i<tmpResults.PostfixTokenObjects.length;i++){if(!(tmpResults.PostfixTokenObjects[i].SolveLayerStack in tmpSolveLayerMap)){tmpSolveLayerMap[tmpResults.PostfixTokenObjects[i].SolveLayerStack]=[];}tmpSolveLayerMap[tmpResults.PostfixTokenObjects[i].SolveLayerStack].push(tmpResults.PostfixTokenObjects[i]);// See what our max depth is. This is super important to the postfix operation
|
|
3524
3525
|
// The programmer in me thinks it would be funny to not track this and just use the map key length as the max size, which would work (logically impossible to have a depth > key length) but it would be quite a bit more confusing to grok the algorithm.
|
|
3525
3526
|
if(tmpResults.PostfixTokenObjects[i].Depth>tmpSolveLayerMaxDepth){tmpSolveLayerMaxDepth=tmpResults.PostfixTokenObjects[i].Depth;}}let tmpSolveLayerKeys=Object.keys(tmpSolveLayerMap);// Reset the virtual symbol index -- it was used above for uniquenes when creating abstract symbols for parenthesis and layer stacks.
|
|
3526
3527
|
let tmpVirtualSymbolIndex=0;tmpSolveLayerKeys.sort(// Sort the solve layers by depth.
|
|
@@ -3565,7 +3566,7 @@ let tmpPeekedNextToken=tmpResults.PostfixTokenObjects[i+1];if(tmpPeekedNextToken
|
|
|
3565
3566
|
// If the next token has higher precedence than what's before the open parenthesis, use it for the open as well
|
|
3566
3567
|
if(tmpPeekedNextToken.Descriptor.Precedence<tmpOpenParenthesis.PreviousPrecedence){tmpOpenParenthesis.VirtualSymbolName=tmpPeekedNextToken.VirtualSymbolName;tmpPostfixTokenObject.VirtualSymbolName=tmpResults.PostfixLayerstackMap[tmpPostfixTokenObject.VirtualSymbolName];}// Otherwise use this one -- it is the higher precedence. And update the previous parenthesis operator's virtual symbol to be the peeked token's virtual symbol.
|
|
3567
3568
|
else{tmpPostfixTokenObject.VirtualSymbolName=tmpOpenParenthesis.PreviousVirtualSymbolName;}}// The next token is an operator and it isn't a function
|
|
3568
|
-
else if(tmpPeekedNextToken.Type=='Token.Operator'&&
|
|
3569
|
+
else if(tmpPeekedNextToken.Type=='Token.Operator'&&'PreviousPrecedence'in tmpOpenParenthesis){// This is the second most complex case -- the next token is an operator.
|
|
3569
3570
|
// If the operater is at the same precedence or higher than the open parenthesis previous operator, use the previous operator's identifier
|
|
3570
3571
|
// NOTE: This line of code is insanely complex
|
|
3571
3572
|
if(tmpPeekedNextToken.Descriptor.Precedence<=tmpOpenParenthesis.PreviousPrecedence){tmpPostfixTokenObject.VirtualSymbolName=tmpOpenParenthesis.PreviousVirtualSymbolName;}// Otherwise use this one -- it is the higher precedence. And update the previous parenthesis operator's virtual symbol to be the peeked token's virtual symbol.
|
|
@@ -3590,16 +3591,16 @@ else if(i>0&&tmpToken.Token=='+'&&(tmpSolveLayerTokens[i-1].Type==='Token.Operat
|
|
|
3590
3591
|
else{tmpResults.PostfixSolveList.push(this.getPosfixSolveListOperation(tmpToken,tmpSolveLayerTokens[i-1],tmpSolveLayerTokens[i+1],tmpSolveLayerTokens,i));}}else if(tmpSolveLayerTokens[i].Type==='Token.Function'&&tmpPrecedence===0){let tmpToken=tmpSolveLayerTokens[i];// Not sure what to do with the other token.
|
|
3591
3592
|
tmpResults.PostfixSolveList.push(this.getPosfixSolveListOperation(tmpToken,tmpSolveLayerTokens[i+1],this.getTokenContainerObject('0.0')));}}}}// Now set the assignment address.
|
|
3592
3593
|
let tmpAssignmentInstruction=this.getPosfixSolveListOperation(this.getTokenContainerObject('Assign','Token.SolverInstruction'),this.getTokenContainerObject('DestinationHash','Token.SolverInstruction'),this.getTokenContainerObject('Resulting','Token.SolverInstruction'));tmpAssignmentInstruction.VirtualSymbolName=tmpResults.PostfixedAssignmentAddress;tmpResults.PostfixSolveList.push(tmpAssignmentInstruction);return tmpResults.PostfixSolveList;}}module.exports=ExpressionParserPostfix;},{"./Fable-Service-ExpressionParser-Base.js":136}],141:[function(require,module,exports){const libExpressionParserOperationBase=require('./Fable-Service-ExpressionParser-Base.js');class ExpressionParserSolver extends libExpressionParserOperationBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='ExpressionParser-Solver';}solvePostfixedExpression(pPostfixedExpression,pDataDestinationObject,pResultObject,pManifest){let tmpResults=typeof pResultObject==='object'?pResultObject:{ExpressionParserLog:[]};let tmpManifest=typeof pManifest==='object'?pManifest:this.fable.newManyfest();let tmpDataDestinationObject=typeof pDataDestinationObject==='object'?pDataDestinationObject:{};// If there was a fable passed in (e.g. the results object was a service or such), we won't decorate
|
|
3593
|
-
let tmpPassedInFable=
|
|
3594
|
+
let tmpPassedInFable=('fable'in tmpResults);if(!tmpPassedInFable){tmpResults.fable=this.fable;}if(!Array.isArray(pPostfixedExpression)){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.solvePostfixedExpression was passed a non-array postfixed expression.");this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);return false;}if(pPostfixedExpression.length<1){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.solvePostfixedExpression was passed an empty postfixed expression.");this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);return false;}// This is how the user communication magic happens.
|
|
3594
3595
|
tmpResults.VirtualSymbols={};for(let i=0;i<pPostfixedExpression.length;i++){if(pPostfixedExpression[i].Operation.Type==='Token.SolverInstruction'){continue;}let tmpStepResultObject={ExpressionStep:pPostfixedExpression[i],ExpressionStepIndex:i,ResultsObject:tmpResults,Manifest:tmpManifest};// Resolve the virtual symbols to their actual values
|
|
3595
3596
|
if(tmpStepResultObject.ExpressionStep.LeftValue.Type==='Token.VirtualSymbol'){tmpStepResultObject.ExpressionStep.LeftValue.Value=tmpManifest.getValueAtAddress(tmpResults.VirtualSymbols,tmpStepResultObject.ExpressionStep.LeftValue.Token);}if(tmpStepResultObject.ExpressionStep.RightValue.Type==='Token.VirtualSymbol'){tmpStepResultObject.ExpressionStep.RightValue.Value=tmpManifest.getValueAtAddress(tmpResults.VirtualSymbols,tmpStepResultObject.ExpressionStep.RightValue.Token);}// Resolve the parenthesis to their actual values
|
|
3596
3597
|
if(tmpStepResultObject.ExpressionStep.LeftValue.Type==='Token.Parenthesis'){tmpStepResultObject.ExpressionStep.LeftValue.Value=tmpManifest.getValueAtAddress(tmpResults.VirtualSymbols,tmpStepResultObject.ExpressionStep.LeftValue.VirtualSymbolName);}if(tmpStepResultObject.ExpressionStep.RightValue.Type==='Token.Parenthesis'){tmpStepResultObject.ExpressionStep.RightValue.Value=tmpManifest.getValueAtAddress(tmpResults.VirtualSymbols,tmpStepResultObject.ExpressionStep.RightValue.VirtualSymbolName);}if(tmpStepResultObject.ExpressionStep.Operation.Type='Operator'){// TODO: This can be optimized. A lot. If necessary. Seems pretty fast honestly for even thousands of operations. Slowest part is arbitrary precision.
|
|
3597
3598
|
// An operator always has a left and right value.
|
|
3598
|
-
let tmpFunctionAddress=false;if(
|
|
3599
|
+
let tmpFunctionAddress=false;if(tmpStepResultObject.ExpressionStep.Operation.Token in this.ExpressionParser.tokenMap){tmpFunctionAddress="ResultsObject.".concat(tmpStepResultObject.ExpressionStep.Operation.Descriptor.Function);}else if(tmpStepResultObject.ExpressionStep.Operation.Token.toLowerCase()in this.ExpressionParser.functionMap){tmpFunctionAddress="ResultsObject.".concat(this.ExpressionParser.functionMap[tmpStepResultObject.ExpressionStep.Operation.Token.toLowerCase()].Address);}try{this.log.trace("Solving Step ".concat(i," [").concat(tmpStepResultObject.ExpressionStep.VirtualSymbolName,"] --> [").concat(tmpStepResultObject.ExpressionStep.Operation.Token,"]: ( ").concat(tmpStepResultObject.ExpressionStep.LeftValue.Value," , ").concat(tmpStepResultObject.ExpressionStep.RightValue.Value," )"));tmpResults.VirtualSymbols[tmpStepResultObject.ExpressionStep.VirtualSymbolName]=tmpManifest.getValueAtAddress(tmpStepResultObject,"".concat(tmpFunctionAddress,"(ExpressionStep.LeftValue.Value,ExpressionStep.RightValue.Value)"));this.log.trace(" ---> Step ".concat(i,": ").concat(tmpResults.VirtualSymbols[tmpStepResultObject.ExpressionStep.VirtualSymbolName]));}catch(pError){tmpResults.ExpressionParserLog.push("ERROR: ExpressionParser.solvePostfixedExpression failed to solve step ".concat(i," with function ").concat(tmpStepResultObject.ExpressionStep.Operation.Token,"."));this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);return false;}// Equations don't always solve in virtual symbol order.
|
|
3599
3600
|
tmpResults.SolverFinalVirtualSymbol=tmpStepResultObject.ExpressionStep.VirtualSymbolName;}}let tmpSolverResultValue=tmpManifest.getValueAtAddress(tmpResults,"VirtualSymbols.".concat(tmpResults.SolverFinalVirtualSymbol));// Now deal with final assignment
|
|
3600
3601
|
for(let i=0;i<pPostfixedExpression.length;i++){if(pPostfixedExpression[i].Operation.Type==='Token.SolverInstruction'&&pPostfixedExpression[i].Operation.Token=='Assign'){tmpManifest.setValueAtAddress(tmpResults.VirtualSymbols,pPostfixedExpression[i].VirtualSymbolName,tmpSolverResultValue);tmpManifest.setValueByHash(tmpDataDestinationObject,pPostfixedExpression[i].VirtualSymbolName,tmpSolverResultValue);}}// Clean up the reference if we added it to the object.
|
|
3601
|
-
if(!tmpPassedInFable){delete tmpResults.fable;}return tmpSolverResultValue.toString();}}module.exports=ExpressionParserSolver;},{"./Fable-Service-ExpressionParser-Base.js":136}],142:[function(require,module,exports){module.exports={"=":{"Name":"Equals","Token":"=","Precedence":0,"Type":"Assignment"},"(":{"Name":"Left Parenthesis","Token":"(","Precedence":0,"Type":"Parenthesis"},")":{"Name":"Right Parenthesis","Token":")","Precedence":0,"Type":"Parenthesis"},"*":{"Name":"Multiply","Token":"*","Function":"fable.Math.multiplyPrecise","Precedence":3,"Type":"Operator"},"/":{"Name":"Divide","Token":"/","Function":"fable.Math.dividePrecise","Precedence":3,"Type":"Operator"},"^":{"Name":"Exponent","Token":"^","Function":"fable.Math.powerPrecise","Precedence":1,"Type":"Operator"},"%":{"Name":"Modulus","Token":"%","Function":"fable.Math.modPrecise","Precedence":3,"Type":"Operator"},"+":{"Name":"Add","Token":"+","Function":"fable.Math.addPrecise","Precedence":4,"Type":"Operator"},"-":{"Name":"Subtract","Token":"-","Function":"fable.Math.subtractPrecise","Precedence":4,"Type":"Operator"}};},{}],143:[function(require,module,exports){(function(process){(function(){const libFableServiceBase=require('fable-serviceproviderbase');const libFS=require('fs');const libPath=require('path');const libReadline=require('readline');class FableServiceFilePersistence extends libFableServiceBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='FilePersistence';if(!
|
|
3602
|
-
makeFolderRecursive(pParameters,fCallback){let tmpParameters=pParameters;if(typeof pParameters=='string'){tmpParameters={Path:pParameters};}else if(typeof pParameters!=='object'){fCallback(new Error('Parameters object or string not properly passed to recursive folder create.'));return false;}if(typeof tmpParameters.Path!=='string'){fCallback(new Error('Parameters object needs a path to run the folder create operation.'));return false;}if(!
|
|
3602
|
+
if(!tmpPassedInFable){delete tmpResults.fable;}return tmpSolverResultValue.toString();}}module.exports=ExpressionParserSolver;},{"./Fable-Service-ExpressionParser-Base.js":136}],142:[function(require,module,exports){module.exports={"=":{"Name":"Equals","Token":"=","Precedence":0,"Type":"Assignment"},"(":{"Name":"Left Parenthesis","Token":"(","Precedence":0,"Type":"Parenthesis"},")":{"Name":"Right Parenthesis","Token":")","Precedence":0,"Type":"Parenthesis"},"*":{"Name":"Multiply","Token":"*","Function":"fable.Math.multiplyPrecise","Precedence":3,"Type":"Operator"},"/":{"Name":"Divide","Token":"/","Function":"fable.Math.dividePrecise","Precedence":3,"Type":"Operator"},"^":{"Name":"Exponent","Token":"^","Function":"fable.Math.powerPrecise","Precedence":1,"Type":"Operator"},"%":{"Name":"Modulus","Token":"%","Function":"fable.Math.modPrecise","Precedence":3,"Type":"Operator"},"+":{"Name":"Add","Token":"+","Function":"fable.Math.addPrecise","Precedence":4,"Type":"Operator"},"-":{"Name":"Subtract","Token":"-","Function":"fable.Math.subtractPrecise","Precedence":4,"Type":"Operator"}};},{}],143:[function(require,module,exports){(function(process){(function(){const libFableServiceBase=require('fable-serviceproviderbase');const libFS=require('fs');const libPath=require('path');const libReadline=require('readline');class FableServiceFilePersistence extends libFableServiceBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='FilePersistence';if(!('Mode'in this.options)){this.options.Mode=parseInt('0777',8)&~process.umask();}this.libFS=libFS;this.libPath=libPath;this.libReadline=libReadline;}joinPath(){return libPath.resolve(...arguments);}existsSync(pPath){return libFS.existsSync(pPath);}exists(pPath,fCallback){let tmpFileExists=this.existsSync(pPath);;return fCallback(null,tmpFileExists);}appendFileSync(pFileName,pAppendContent,pOptions){let tmpOptions=typeof pOptions==='undefined'?'utf8':pOptions;return libFS.appendFileSync(pFileName,pAppendContent,tmpOptions);}deleteFileSync(pFileName){return libFS.unlinkSync(pFileName);}deleteFolderSync(pFileName){return libFS.rmdirSync(pFileName);}readFileSync(pFilePath,pOptions){let tmpOptions=typeof pOptions==='undefined'?'utf8':pOptions;return libFS.readFileSync(pFilePath,tmpOptions);}readFile(pFilePath,pOptions,fCallback){let tmpOptions=typeof pOptions==='undefined'?'utf8':pOptions;return libFS.readFile(pFilePath,tmpOptions,fCallback);}writeFileSync(pFileName,pFileContent,pOptions){let tmpOptions=typeof pOptions==='undefined'?'utf8':pOptions;return libFS.writeFileSync(pFileName,pFileContent,tmpOptions);}writeFileSyncFromObject(pFileName,pObject){return this.writeFileSync(pFileName,JSON.stringify(pObject,null,4));}writeFileSyncFromArray(pFileName,pFileArray){if(!Array.isArray(pFileArray)){this.log.error("File Persistence Service attempted to write ".concat(pFileName," from array but the expected array was not an array (it was a ").concat(typeof pFileArray,")."));return Error('Attempted to write ${pFileName} from array but the expected array was not an array (it was a ${typeof(pFileArray)}).');}else{for(let i=0;i<pFileArray.length;i++){return this.appendFileSync(pFileName,"".concat(pFileArray[i],"\n"));}}}writeFile(pFileName,pFileContent,pOptions,fCallback){let tmpOptions=typeof pOptions==='undefined'?'utf8':pOptions;return libFS.writeFile(pFileName,pFileContent,tmpOptions,fCallback);}lineReaderFactory(pFilePath,fOnLine,fOnComplete,fOnError){let tmpLineReader={};if(typeof pFilePath!='string'){return false;}tmpLineReader.filePath=pFilePath;tmpLineReader.fileStream=libFS.createReadStream(tmpLineReader.filePath);tmpLineReader.reader=libReadline.createInterface({input:tmpLineReader.fileStream,crlfDelay:Infinity});if(typeof fOnError==='function'){tmpLineReader.reader.on('error',fOnError);}tmpLineReader.reader.on('line',typeof fOnLine==='function'?fOnLine:()=>{});if(typeof fOnComplete==='function'){tmpLineReader.reader.on('close',fOnComplete);}return tmpLineReader;}// Folder management
|
|
3603
|
+
makeFolderRecursive(pParameters,fCallback){let tmpParameters=pParameters;if(typeof pParameters=='string'){tmpParameters={Path:pParameters};}else if(typeof pParameters!=='object'){fCallback(new Error('Parameters object or string not properly passed to recursive folder create.'));return false;}if(typeof tmpParameters.Path!=='string'){fCallback(new Error('Parameters object needs a path to run the folder create operation.'));return false;}if(!('Mode'in tmpParameters)){tmpParameters.Mode=this.options.Mode;}// Check if we are just starting .. if so, build the initial state for our recursive function
|
|
3603
3604
|
if(typeof tmpParameters.CurrentPathIndex==='undefined'){// Build the tools to start recursing
|
|
3604
3605
|
tmpParameters.ActualPath=libPath.normalize(tmpParameters.Path);tmpParameters.ActualPathParts=tmpParameters.ActualPath.split(libPath.sep);tmpParameters.CurrentPathIndex=0;tmpParameters.CurrentPath='';}else{// This is not our first run, so we will continue the recursion.
|
|
3605
3606
|
// Build the new base path
|
|
@@ -3678,19 +3679,19 @@ pParserState.Pattern=false;pParserState.PatternStartNode=false;pParserState.Star
|
|
|
3678
3679
|
* @private
|
|
3679
3680
|
*/parseCharacter(pCharacter,pParserState,pData,pDataContext){// If we are already in a pattern match traversal
|
|
3680
3681
|
if(pParserState.PatternMatch){// If the pattern is still matching the start and we haven't passed the buffer
|
|
3681
|
-
if(!pParserState.StartPatternMatchComplete&&pParserState.Pattern
|
|
3682
|
+
if(!pParserState.StartPatternMatchComplete&&pCharacter in pParserState.Pattern){pParserState.Pattern=pParserState.Pattern[pCharacter];this.appendOutputBuffer(pCharacter,pParserState);}else if(pParserState.EndPatternMatchBegan){if(pCharacter in pParserState.Pattern.PatternEnd){// This leaf has a PatternEnd tree, so we will wait until that end is met.
|
|
3682
3683
|
pParserState.Pattern=pParserState.Pattern.PatternEnd[pCharacter];// Flush the output buffer.
|
|
3683
3684
|
this.appendOutputBuffer(pCharacter,pParserState);// If this last character is the end of the pattern, parse it.
|
|
3684
|
-
if(pParserState.Pattern
|
|
3685
|
-
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);return this.resetOutputBuffer(pParserState);}else{this.fable.log.info("MetaTemplate: The pattern ".concat(pParserState.Pattern.PatternStartString," is asynchronous and cannot be used in a synchronous parser."));return this.resetOutputBuffer(pParserState);}}else if(pParserState.PatternStartNode.PatternEnd
|
|
3686
|
-
pParserState.Pattern=pParserState.PatternStartNode.PatternEnd[pCharacter];this.appendOutputBuffer(pCharacter,pParserState);}else{pParserState.EndPatternMatchBegan=false;this.appendOutputBuffer(pCharacter,pParserState);}}else if(pParserState.Pattern
|
|
3685
|
+
if('Parse'in pParserState.Pattern&&(!pParserState.Pattern.isAsync||pParserState.Pattern.isBoth)){// Run the function
|
|
3686
|
+
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);return this.resetOutputBuffer(pParserState);}else{this.fable.log.info("MetaTemplate: The pattern ".concat(pParserState.Pattern.PatternStartString," is asynchronous and cannot be used in a synchronous parser."));return this.resetOutputBuffer(pParserState);}}else if(pCharacter in pParserState.PatternStartNode.PatternEnd){// We broke out of the end -- see if this is a new start of the end.
|
|
3687
|
+
pParserState.Pattern=pParserState.PatternStartNode.PatternEnd[pCharacter];this.appendOutputBuffer(pCharacter,pParserState);}else{pParserState.EndPatternMatchBegan=false;this.appendOutputBuffer(pCharacter,pParserState);}}else if('PatternEnd'in pParserState.Pattern){if(!pParserState.StartPatternMatchComplete){pParserState.StartPatternMatchComplete=true;pParserState.PatternStartNode=pParserState.Pattern;}this.appendOutputBuffer(pCharacter,pParserState);if(pCharacter in pParserState.Pattern.PatternEnd){// This is the first character of the end pattern.
|
|
3687
3688
|
pParserState.EndPatternMatchBegan=true;// This leaf has a PatternEnd tree, so we will wait until that end is met.
|
|
3688
3689
|
pParserState.Pattern=pParserState.Pattern.PatternEnd[pCharacter];// If this last character is the end of the pattern, parse it.
|
|
3689
|
-
if(pParserState.Pattern
|
|
3690
|
+
if('Parse'in pParserState.Pattern){if(pParserState.Pattern.isAsync&&!pParserState.Pattern.isBoth){this.fable.log.info("MetaTemplate: The pattern ".concat(pParserState.Pattern.PatternStartString," is asynchronous and cannot be used in a synchronous parser."));this.resetOutputBuffer(pParserState);}else{// Run the t*mplate function
|
|
3690
3691
|
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);return this.resetOutputBuffer(pParserState);}}}}else{// We are in a pattern start but didn't match one; reset and start trying again from this character.
|
|
3691
3692
|
this.resetOutputBuffer(pParserState);}}// If we aren't in a pattern match or pattern, and this isn't the start of a new pattern (RAW mode)....
|
|
3692
3693
|
if(!pParserState.PatternMatch){// This may be the start of a new pattern....
|
|
3693
|
-
if(pParserState.ParseTree
|
|
3694
|
+
if(pCharacter in pParserState.ParseTree){// ... assign the root node as the matched node.
|
|
3694
3695
|
this.resetOutputBuffer(pParserState);this.appendOutputBuffer(pCharacter,pParserState);pParserState.Pattern=pParserState.ParseTree[pCharacter];pParserState.PatternMatch=true;return true;}else{this.appendOutputBuffer(pCharacter,pParserState);}}return false;}executePatternAsync(pParserState,pData,fCallback,pDataContext){// ... this is the end of a pattern, cut off the end tag and parse it.
|
|
3695
3696
|
// Trim the start and end tags off the output buffer now
|
|
3696
3697
|
if(pParserState.Pattern.isAsync&&!pParserState.Pattern.isBoth){// Run the function
|
|
@@ -3707,17 +3708,17 @@ pParserState.OutputBuffer=pParserState.Pattern.Parse(pParserState.OutputBuffer.s
|
|
|
3707
3708
|
* @private
|
|
3708
3709
|
*/parseCharacterAsync(pCharacter,pParserState,pData,fCallback,pDataContext){// If we are already in a pattern match traversal
|
|
3709
3710
|
if(pParserState.PatternMatch){// If the pattern is still matching the start and we haven't passed the buffer
|
|
3710
|
-
if(!pParserState.StartPatternMatchComplete&&pParserState.Pattern
|
|
3711
|
+
if(!pParserState.StartPatternMatchComplete&&pCharacter in pParserState.Pattern){pParserState.Pattern=pParserState.Pattern[pCharacter];this.appendOutputBuffer(pCharacter,pParserState);}else if(pParserState.EndPatternMatchBegan){if(pCharacter in pParserState.Pattern.PatternEnd){// This leaf has a PatternEnd tree, so we will wait until that end is met.
|
|
3711
3712
|
pParserState.Pattern=pParserState.Pattern.PatternEnd[pCharacter];// Flush the output buffer.
|
|
3712
3713
|
this.appendOutputBuffer(pCharacter,pParserState);// If this last character is the end of the pattern, parse it.
|
|
3713
|
-
if(pParserState.Pattern
|
|
3714
|
-
pParserState.Pattern=pParserState.PatternStartNode.PatternEnd[pCharacter];this.appendOutputBuffer(pCharacter,pParserState);}else{pParserState.EndPatternMatchBegan=false;this.appendOutputBuffer(pCharacter,pParserState);}}else if(pParserState.Pattern
|
|
3714
|
+
if('Parse'in pParserState.Pattern){return this.executePatternAsync(pParserState,pData,fCallback,pDataContext);}}else if(pCharacter in pParserState.PatternStartNode.PatternEnd){// We broke out of the end -- see if this is a new start of the end.
|
|
3715
|
+
pParserState.Pattern=pParserState.PatternStartNode.PatternEnd[pCharacter];this.appendOutputBuffer(pCharacter,pParserState);}else{pParserState.EndPatternMatchBegan=false;this.appendOutputBuffer(pCharacter,pParserState);}}else if('PatternEnd'in pParserState.Pattern){if(!pParserState.StartPatternMatchComplete){pParserState.StartPatternMatchComplete=true;pParserState.PatternStartNode=pParserState.Pattern;}this.appendOutputBuffer(pCharacter,pParserState);if(pCharacter in pParserState.Pattern.PatternEnd){// This is the first character of the end pattern.
|
|
3715
3716
|
pParserState.EndPatternMatchBegan=true;// This leaf has a PatternEnd tree, so we will wait until that end is met.
|
|
3716
3717
|
pParserState.Pattern=pParserState.Pattern.PatternEnd[pCharacter];// If this last character is the end of the pattern, parse it.
|
|
3717
|
-
if(pParserState.Pattern
|
|
3718
|
+
if('Parse'in pParserState.Pattern){return this.executePatternAsync(pParserState,pData,fCallback,pDataContext);}}}else{// We are in a pattern start but didn't match one; reset and start trying again from this character.
|
|
3718
3719
|
this.resetOutputBuffer(pParserState);}}// If we aren't in a pattern match or pattern, and this isn't the start of a new pattern (RAW mode)....
|
|
3719
3720
|
else{// This may be the start of a new pattern....
|
|
3720
|
-
if(pParserState.ParseTree
|
|
3721
|
+
if(pCharacter in pParserState.ParseTree){// ... assign the root node as the matched node.
|
|
3721
3722
|
this.resetOutputBuffer(pParserState);this.appendOutputBuffer(pCharacter,pParserState);pParserState.Pattern=pParserState.ParseTree[pCharacter];pParserState.PatternMatch=true;}else{this.appendOutputBuffer(pCharacter,pParserState);}}// Without this, templates of all sizes work fine in node. They do not in the browser.
|
|
3722
3723
|
// Trying this out without the timout on non asynchronous template flips.
|
|
3723
3724
|
return fCallback();}/**
|
|
@@ -3745,21 +3746,21 @@ this.flushOutputBuffer(tmpParserState);return fCallback(pError,tmpParserState.Ou
|
|
|
3745
3746
|
* @param {string} pPattern - The string to add to the tree
|
|
3746
3747
|
* @returns {Object} The resulting leaf node that was added (or found)
|
|
3747
3748
|
* @private
|
|
3748
|
-
*/addChild(pTree,pPattern){if(!
|
|
3749
|
+
*/addChild(pTree,pPattern){if(!(pPattern in pTree)){pTree[pPattern]={};}return pTree[pPattern];}/**
|
|
3749
3750
|
* Add a child character to a Parse Tree PatternEnd subtree
|
|
3750
3751
|
* @method addChild
|
|
3751
3752
|
* @param {Object} pTree - A parse tree to push the characters into
|
|
3752
3753
|
* @param {string} pPattern - The string to add to the tree
|
|
3753
3754
|
* @returns {Object} The resulting leaf node that was added (or found)
|
|
3754
3755
|
* @private
|
|
3755
|
-
*/addEndChild(pTree,pPattern){if(!
|
|
3756
|
+
*/addEndChild(pTree,pPattern){if(!('PatternEnd'in pTree)){pTree.PatternEnd={};}pTree.PatternEnd[pPattern]={};return pTree.PatternEnd[pPattern];}/** Add a Pattern to the Parse Tree
|
|
3756
3757
|
* @method addPattern
|
|
3757
3758
|
* @param {Object} pPatternStart - The starting string for the pattern (e.g. "${")
|
|
3758
3759
|
* @param {string} pPatternEnd - The ending string for the pattern (e.g. "}")
|
|
3759
3760
|
* @param {function} fParser - The function to parse if this is the matched pattern, once the Pattern End is met. If this is a string, a simple replacement occurs.
|
|
3760
3761
|
* @return {bool} True if adding the pattern was successful
|
|
3761
3762
|
*/addPattern(pPatternStart,pPatternEnd,fParser){if(pPatternStart.length<1){return false;}if(typeof pPatternEnd==='string'&&pPatternEnd.length<1){return false;}let tmpLeaf=this.ParseTree;// Add the tree of leaves iteratively
|
|
3762
|
-
for(var i=0;i<pPatternStart.length;i++){tmpLeaf=this.addChild(tmpLeaf,pPatternStart[i],i);}if(!
|
|
3763
|
+
for(var i=0;i<pPatternStart.length;i++){tmpLeaf=this.addChild(tmpLeaf,pPatternStart[i],i);}if(!('PatternEnd'in tmpLeaf)){tmpLeaf.PatternEnd={};}let tmpPatternEnd=typeof pPatternEnd==='string'?pPatternEnd:pPatternStart;for(let i=0;i<tmpPatternEnd.length;i++){tmpLeaf=this.addEndChild(tmpLeaf,tmpPatternEnd[i],i);}tmpLeaf.PatternStartString=pPatternStart;tmpLeaf.PatternEndString=tmpPatternEnd;tmpLeaf.Parse=typeof fParser==='function'?fParser:typeof fParser==='string'?()=>{return fParser;}:pData=>{return pData;};return tmpLeaf;}/** Add a Pattern to the Parse Tree
|
|
3763
3764
|
* @method addPatternAsync
|
|
3764
3765
|
* @param {Object} pPatternStart - The starting string for the pattern (e.g. "${")
|
|
3765
3766
|
* @param {string} pPatternEnd - The ending string for the pattern (e.g. "}")
|
|
@@ -3787,41 +3788,41 @@ tmpAnticipate.wait(pError=>{if(pError){this.fable.log.error("Operation [".concat
|
|
|
3787
3788
|
addStep(fStepFunction,pStepMetadata,pStepName,pStepDescription,pGUIDStep){let tmpStep={};// GUID is optional
|
|
3788
3789
|
tmpStep.GUIDStep=typeof pGUIDStep!=='undefined'?pGUIDStep:"STEP-".concat(this.state.Steps.length,"-").concat(this.fable.DataGeneration.randomNumericString());// Name is optional
|
|
3789
3790
|
tmpStep.Name=typeof pStepName!=='undefined'?pStepName:"Step [".concat(tmpStep.GUIDStep,"]");tmpStep.Description=typeof pStepDescription!=='undefined'?pStepDescription:"Step execution of ".concat(tmpStep.Name,".");tmpStep.ProgressTracker=this.progressTrackerSet.createProgressTracker(tmpStep.GUIDStep);tmpStep.Metadata=typeof pStepMetadata==='object'?pStepMetadata:{};// There is an array of steps, in the Operation State itself ... push a step there
|
|
3790
|
-
this.state.Steps.push(tmpStep);this.stepMap[tmpStep.GUIDStep]=tmpStep;this.stepFunctions[tmpStep.GUIDStep]=typeof fStepFunction=='function'?fStepFunction:function(fDone){return fDone();};this.state.Status.StepCount++;return tmpStep;}setStepTotalOperations(pGUIDStep,pTotalOperationCount){if(!this.stepMap
|
|
3791
|
-
if(typeof pReferenceTime=='string'){tmpReferenceTime=this.timeStamps
|
|
3792
|
-
if(typeof pReferenceTime=='string'){tmpReferenceTime=this.timeStamps
|
|
3791
|
+
this.state.Steps.push(tmpStep);this.stepMap[tmpStep.GUIDStep]=tmpStep;this.stepFunctions[tmpStep.GUIDStep]=typeof fStepFunction=='function'?fStepFunction:function(fDone){return fDone();};this.state.Status.StepCount++;return tmpStep;}setStepTotalOperations(pGUIDStep,pTotalOperationCount){if(!(pGUIDStep in this.stepMap)){return new Error("Step [".concat(pGUIDStep,"] does not exist in operation [").concat(this.state.Metadata.UUID,"] ").concat(this.state.Metadata.Name," when attempting to set total operations to ").concat(pTotalOperationCount,"."));}this.progressTrackerSet.setProgressTrackerTotalOperations(this.stepMap[pGUIDStep].ProgressTracker.Hash,pTotalOperationCount);}writeOperationLog(pLogLevel,pLogText,pLogObject){this.state.Log.push("[".concat(new Date().toUTCString(),"]-[").concat(pLogLevel,"]: ").concat(pLogText));if(typeof pLogObject=='object'){this.state.Log.push(JSON.stringify(pLogObject));}}writeOperationErrors(pLogText,pLogObject){this.state.Errors.push("".concat(pLogText));if(typeof pLogObject=='object'){this.state.Errors.push(JSON.stringify(pLogObject));}}trace(pLogText,pLogObject){this.writeOperationLog('TRACE',pLogText,pLogObject);this.fable.log.trace(pLogText,pLogObject);}debug(pLogText,pLogObject){this.writeOperationLog('DEBUG',pLogText,pLogObject);this.fable.log.debug(pLogText,pLogObject);}info(pLogText,pLogObject){this.writeOperationLog('INFO',pLogText,pLogObject);this.fable.log.info(pLogText,pLogObject);}warn(pLogText,pLogObject){this.writeOperationLog('WARN',pLogText,pLogObject);this.fable.log.warn(pLogText,pLogObject);}error(pLogText,pLogObject){this.writeOperationLog('ERROR',pLogText,pLogObject);this.writeOperationErrors(pLogText,pLogObject);this.fable.log.error(pLogText,pLogObject);}fatal(pLogText,pLogObject){this.writeOperationLog('FATAL',pLogText,pLogObject);this.writeOperationErrors(pLogText,pLogObject);this.fable.log.fatal(pLogText,pLogObject);}}module.exports=FableOperation;},{"./Fable-Service-Operation-DefaultSettings.js":148,"big.js":17,"fable-serviceproviderbase":51}],150:[function(require,module,exports){const libFableServiceBase=require('fable-serviceproviderbase');class FableServiceProgressTime extends libFableServiceBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='ProgressTime';this.timeStamps={};}formatTimeDuration(pTimeDurationInMilliseconds){let tmpTimeDuration=typeof pTimeDurationInMilliseconds=='number'?pTimeDurationInMilliseconds:0;if(pTimeDurationInMilliseconds<0){return'unknown';}let tmpTimeDurationString='';if(tmpTimeDuration>3600000){tmpTimeDurationString+=Math.floor(tmpTimeDuration/3600000)+'h ';tmpTimeDuration=tmpTimeDuration%3600000;}if(tmpTimeDuration>60000){tmpTimeDurationString+=Math.floor(tmpTimeDuration/60000)+'m ';tmpTimeDuration=tmpTimeDuration%60000;}if(tmpTimeDuration>1000){tmpTimeDurationString+=Math.floor(tmpTimeDuration/1000)+'s ';tmpTimeDuration=tmpTimeDuration%1000;}tmpTimeDurationString+=Math.round(tmpTimeDuration)+'ms';return tmpTimeDurationString;}createTimeStamp(pTimeStampHash){let tmpTimeStampHash=typeof pTimeStampHash=='string'?pTimeStampHash:'Default';this.timeStamps[tmpTimeStampHash]=+new Date();return this.timeStamps[tmpTimeStampHash];}getTimeStampValue(pTimeStampHash){let tmpTimeStampHash=typeof pTimeStampHash=='string'?pTimeStampHash:'Default';return tmpTimeStampHash in this.timeStamps?this.timeStamps[tmpTimeStampHash]:-1;}updateTimeStampValue(pTimeStampHash,pReferenceTime){let tmpTimeStampHash=typeof pTimeStampHash=='string'?pTimeStampHash:'Default';let tmpReferenceTime=false;// This function allows the user to pass in either a reference time in ms, or, a hash of a timestamp.
|
|
3792
|
+
if(typeof pReferenceTime=='string'){tmpReferenceTime=tmpReference in this.timeStamps?this.timeStamps[tmpReference]:false;}else if(typeof pReferenceTime=='number'){tmpReferenceTime=pReferenceTime;}else{tmpReferenceTime=+new Date();}if(tmpTimeStampHash in this.timeStamps&&tmpReferenceTime){this.timeStamps[tmpTimeStampHash]=tmpReferenceTime;return this.timeStamps[tmpTimeStampHash];}else{return-1;}}removeTimeStamp(pTimeStampHash){let tmpTimeStampHash=typeof pTimeStampHash=='string'?pTimeStampHash:'Default';if(tmpTimeStampHash in this.timeStamps){delete this.timeStamps[tmpTimeStampHash];return true;}else{return false;}}getTimeStampDelta(pTimeStampHash,pReferenceTime){let tmpTimeStampHash=typeof pTimeStampHash=='string'?pTimeStampHash:'Default';let tmpReferenceTime=false;// This function allows the user to pass in either a reference time in ms, or, a hash of a timestamp.
|
|
3793
|
+
if(typeof pReferenceTime=='string'){tmpReferenceTime=tmpReference in this.timeStamps?this.timeStamps[tmpReference]:false;}else if(typeof pReferenceTime=='number'){tmpReferenceTime=pReferenceTime;}else{tmpReferenceTime=+new Date();}if(tmpTimeStampHash in this.timeStamps&&tmpReferenceTime){return tmpReferenceTime-this.timeStamps[tmpTimeStampHash];}else{return-1;}}getDurationBetweenTimestamps(pTimeStampHashStart,pTimeStampHashEnd){let tmpTimeStampHashStart=typeof pTimeStampHashStart=='string'?pTimeStampHashStart:'Default';let tmpTimeStampHashEnd=typeof pTimeStampHashEnd=='string'?pTimeStampHashEnd:'Default';if(tmpTimeStampHashStart in this.timeStamps&&tmpTimeStampHashEnd in this.timeStamps){return this.timeStamps[tmpTimeStampHashEnd]-this.timeStamps[tmpTimeStampHashStart];}else{return-1;}}getTimeStampDeltaMessage(pTimeStampHash,pMessage,pReferenceTime){let tmpTimeStampHash=typeof pTimeStampHash=='string'?pTimeStampHash:'Default';let tmpMessage=typeof pMessage!=='undefined'?pMessage:"Elapsed for ".concat(tmpTimeStampHash,": ");let tmpOperationTime=this.getTimeStampDelta(tmpTimeStampHash,pReferenceTime);return"".concat(tmpMessage," ").concat(this.formatTimeDuration(tmpOperationTime));}logTimeStampDelta(pTimeStampHash,pMessage,pReferenceTime){this.fable.log.info(this.getTimeStampDeltaMessage(pTimeStampHash,pMessage,pReferenceTime));}}module.exports=FableServiceProgressTime;},{"fable-serviceproviderbase":51}],151:[function(require,module,exports){class ProgressTracker{constructor(pProgressTrackerSet,pProgressTrackerHash){this.progressTrackerSet=pProgressTrackerSet;this.progressTrackerHash=pProgressTrackerHash;this.data=this.progressTrackerSet.getProgressTrackerData(this.progressTrackerHash);}updateProgressTracker(pProgressAmount){return this.progressTrackerSet.updateProgressTracker(this.progressTrackerHash,pProgressAmount);}incrementProgressTracker(pProgressIncrementAmount){return this.progressTrackerSet.incrementProgressTracker(this.progressTrackerHash,pProgressIncrementAmount);}setProgressTrackerTotalOperations(pTotalOperationCount){return this.progressTrackerSet.setProgressTrackerTotalOperations(this.progressTrackerHash,pTotalOperationCount);}getProgressTrackerStatusString(){return this.progressTrackerSet.getProgressTrackerStatusString(this.progressTrackerHash);}}module.exports=ProgressTracker;},{}],152:[function(require,module,exports){const libFableServiceBase=require('fable-serviceproviderbase');const libProgressTrackerClass=require('./Fable-Service-ProgressTracker/ProgressTracker.js');class FableServiceProgressTrackerSet extends libFableServiceBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.serviceType='ProgressTrackerSet';this.progressTrackers={};// Create an internal PorgressTime service to track timestamps
|
|
3793
3794
|
this.progressTimes=this.fable.instantiateServiceProviderWithoutRegistration('ProgressTime');// This timestamp is used and updated by *all* progress trackers.
|
|
3794
|
-
this.progressTimes.createTimeStamp('CurrentTime');}getProgressTracker(pProgressTrackerHash){let tmpProgressTrackerHash=typeof pProgressTrackerHash=='string'?pProgressTrackerHash:'Default';if(!this.progressTrackers
|
|
3795
|
-
AllowTruePercentComplete:false,ElapsedTime:-1,AverageOperationTime:-1,EstimatedCompletionTime:-1,TotalCount:tmpTotalOperations,CurrentCount:-1};if(this.progressTrackers
|
|
3796
|
-
if(!this.progressTrackers
|
|
3795
|
+
this.progressTimes.createTimeStamp('CurrentTime');}getProgressTracker(pProgressTrackerHash){let tmpProgressTrackerHash=typeof pProgressTrackerHash=='string'?pProgressTrackerHash:'Default';if(!(tmpProgressTrackerHash in this.progressTrackers)){this.fable.log.warn("ProgressTracker ".concat(tmpProgressTrackerHash," does not exist! Creating a new tracker..."));this.createProgressTracker(tmpProgressTrackerHash,100);}return new libProgressTrackerClass(this,pProgressTrackerHash);}getProgressTrackerData(pProgressTrackerHash){let tmpProgressTrackerHash=typeof pProgressTrackerHash=='string'?pProgressTrackerHash:'Default';if(!(tmpProgressTrackerHash in this.progressTrackers)){this.fable.log.warn("ProgressTracker ".concat(tmpProgressTrackerHash," does not exist! Creating a new tracker..."));this.createProgressTracker(tmpProgressTrackerHash,100);}return this.progressTrackers[tmpProgressTrackerHash];}createProgressTracker(pProgressTrackerHash,pTotalOperations){let tmpProgressTrackerHash=typeof pProgressTrackerHash=='string'?pProgressTrackerHash:'Default';let tmpTotalOperations=typeof pTotalOperations=='number'?pTotalOperations:100;let tmpProgressTracker={Hash:tmpProgressTrackerHash,StartTimeHash:"".concat(tmpProgressTrackerHash,"-Start"),StartTimeStamp:-1,CurrentTimeStamp:-1,EndTimeHash:"".concat(tmpProgressTrackerHash,"-End"),EndTimeStamp:-1,PercentComplete:-1,// If this is set to true, PercentComplete will be calculated as CurrentCount / TotalCount even if it goes over 100%
|
|
3796
|
+
AllowTruePercentComplete:false,ElapsedTime:-1,AverageOperationTime:-1,EstimatedCompletionTime:-1,TotalCount:tmpTotalOperations,CurrentCount:-1};if(tmpProgressTrackerHash in this.progressTrackers){this.fable.log.warn("ProgressTracker ".concat(tmpProgressTrackerHash," already exists! Overwriting with a new tracker..."));this.progressTimes.removeTimeStamp(tmpProgressTracker.StartTimeHash);this.progressTimes.removeTimeStamp(tmpProgressTracker.EndTimeHash);}this.progressTrackers[tmpProgressTrackerHash]=tmpProgressTracker;return tmpProgressTracker;}setProgressTrackerTotalOperations(pProgressTrackerHash,pTotalOperations){let tmpProgressTrackerHash=typeof pProgressTrackerHash=='string'?pProgressTrackerHash:'Default';let tmpTotalOperations=typeof pTotalOperations=='number'?pTotalOperations:100;if(!(tmpProgressTrackerHash in this.progressTrackers)){this.fable.log.warn("Attempted to set the total operations of ProgressTracker ".concat(tmpProgressTrackerHash," but it does not exist! Creating a new tracker..."));this.createProgressTracker(tmpProgressTrackerHash,tmpTotalOperations);}this.progressTrackers[tmpProgressTrackerHash].TotalCount=tmpTotalOperations;return this.progressTrackers[tmpProgressTrackerHash];}startProgressTracker(pProgressTrackerHash){let tmpProgressTrackerHash=typeof pProgressTrackerHash=='string'?pProgressTrackerHash:'Default';// This is the only method to lazily create ProgressTrackers now
|
|
3797
|
+
if(!(tmpProgressTrackerHash in this.progressTrackers)){this.createProgressTracker(tmpProgressTrackerHash,100);}let tmpProgressTracker=this.progressTrackers[tmpProgressTrackerHash];this.progressTimes.createTimeStamp(this.progressTrackers[tmpProgressTrackerHash].StartTimeHash);tmpProgressTracker.StartTimeStamp=this.progressTimes.getTimeStampValue(this.progressTrackers[tmpProgressTrackerHash].StartTimeHash);if(tmpProgressTracker.CurrentCount<0){tmpProgressTracker.CurrentCount=0;}return this.solveProgressTrackerStatus(tmpProgressTrackerHash);}endProgressTracker(pProgressTrackerHash){let tmpProgressTrackerHash=typeof pProgressTrackerHash=='string'?pProgressTrackerHash:'Default';if(!(tmpProgressTrackerHash in this.progressTrackers)){this.fable.log.error("Attempted to end ProgressTracker ".concat(tmpProgressTrackerHash," that does not exist!"));return false;}let tmpProgressTracker=this.progressTrackers[tmpProgressTrackerHash];this.progressTimes.createTimeStamp(this.progressTrackers[tmpProgressTrackerHash].EndTimeHash);tmpProgressTracker.EndTimeStamp=this.progressTimes.getTimeStampValue(this.progressTrackers[tmpProgressTrackerHash].EndTimeHash);return this.solveProgressTrackerStatus(tmpProgressTrackerHash);}solveProgressTrackerStatus(pProgressTrackerHash){let tmpProgressTrackerHash=typeof pProgressTrackerHash=='string'?pProgressTrackerHash:'Default';if(!(tmpProgressTrackerHash in this.progressTrackers)){this.fable.log.error("Attempted to solve ProgressTracker ".concat(tmpProgressTrackerHash," that does not exist!"));return false;}let tmpProgressTracker=this.progressTrackers[tmpProgressTrackerHash];if(tmpProgressTracker.TotalCount<1||isNaN(tmpProgressTracker.TotalCount)){this.fable.log.error("ProgressTracker ".concat(tmpProgressTracker.Hash," has an invalid total count of operations (").concat(tmpProgressTracker.TotalCount,"! Setting it to the default of 100..."));tmpProgressTracker.TotalCount=100;}// Compute the percentage of progress that is complete.
|
|
3797
3798
|
if(tmpProgressTracker.CurrentCount<1){tmpProgressTracker.PercentComplete=0;}else{tmpProgressTracker.PercentComplete=tmpProgressTracker.CurrentCount/tmpProgressTracker.TotalCount*100.0;}if(!tmpProgressTracker.AllowTruePercentComplete&&tmpProgressTracker.PercentComplete>100){tmpProgressTracker.PercentComplete=100;}// Compute the average time per operation
|
|
3798
3799
|
this.progressTimes.updateTimeStampValue('CurrentTime');tmpProgressTracker.CurrentTimeStamp=this.progressTimes.getTimeStampValue('CurrentTime');tmpProgressTracker.ElapsedTime=tmpProgressTracker.CurrentTimeStamp-tmpProgressTracker.StartTimeStamp;if(tmpProgressTracker.EndTimeStamp>0){tmpProgressTracker.ElapsedTime=tmpProgressTracker.EndTimeStamp-tmpProgressTracker.StartTimeStamp;}if(tmpProgressTracker.CurrentCount>0){tmpProgressTracker.AverageOperationTime=(tmpProgressTracker.CurrentTimeStamp-tmpProgressTracker.StartTimeStamp)/tmpProgressTracker.CurrentCount;}else{tmpProgressTracker.AverageOperationTime=-1;}// Compute the estimated completion
|
|
3799
|
-
if(tmpProgressTracker.AverageOperationTime>0){tmpProgressTracker.EstimatedCompletionTime=Math.max(tmpProgressTracker.TotalCount-tmpProgressTracker.CurrentCount,0)*tmpProgressTracker.AverageOperationTime;}else{tmpProgressTracker.EstimatedCompletionTime=-1;}return tmpProgressTracker;}updateProgressTracker(pProgressTrackerHash,pCurrentOperations){let tmpProgressTrackerHash=typeof pProgressTrackerHash=='string'?pProgressTrackerHash:'Default';let tmpCurrentOperations=parseInt(pCurrentOperations);if(isNaN(tmpCurrentOperations)){this.fable.log.warn("Attempted to update ProgressTracker ".concat(tmpProgressTrackerHash," with an invalid number of operations!"));return false;}if(!this.progressTrackers
|
|
3800
|
+
if(tmpProgressTracker.AverageOperationTime>0){tmpProgressTracker.EstimatedCompletionTime=Math.max(tmpProgressTracker.TotalCount-tmpProgressTracker.CurrentCount,0)*tmpProgressTracker.AverageOperationTime;}else{tmpProgressTracker.EstimatedCompletionTime=-1;}return tmpProgressTracker;}updateProgressTracker(pProgressTrackerHash,pCurrentOperations){let tmpProgressTrackerHash=typeof pProgressTrackerHash=='string'?pProgressTrackerHash:'Default';let tmpCurrentOperations=parseInt(pCurrentOperations);if(isNaN(tmpCurrentOperations)){this.fable.log.warn("Attempted to update ProgressTracker ".concat(tmpProgressTrackerHash," with an invalid number of operations!"));return false;}if(!(tmpProgressTrackerHash in this.progressTrackers)){this.createProgressTracker(100,tmpProgressTrackerHash);}this.progressTrackers[tmpProgressTrackerHash].CurrentCount=tmpCurrentOperations;return this.solveProgressTrackerStatus(tmpProgressTrackerHash);}incrementProgressTracker(pProgressTrackerHash,pOperationIncrementAmount){let tmpProgressTrackerHash=typeof pProgressTrackerHash=='string'?pProgressTrackerHash:'Default';let tmpOperationIncrementAmount=parseInt(pOperationIncrementAmount);if(isNaN(tmpOperationIncrementAmount)){tmpOperationIncrementAmount=1;}if(!(tmpProgressTrackerHash in this.progressTrackers)){this.fable.log.warn("Attempted to increment ProgressTracker ".concat(tmpProgressTrackerHash," but it did not exist."));return false;}if(this.progressTrackers[tmpProgressTrackerHash].StartTimeStamp<1){this.fable.log.warn("Attempted to increment ProgressTracker ".concat(tmpProgressTrackerHash," but it was not started.. starting now."));this.startProgressTracker(tmpProgressTrackerHash);}this.progressTrackers[tmpProgressTrackerHash].CurrentCount=this.progressTrackers[tmpProgressTrackerHash].CurrentCount+tmpOperationIncrementAmount;return this.solveProgressTrackerStatus(tmpProgressTrackerHash);}getProgressTrackerCompletedOperationCountString(pProgressTrackerHash){let tmpProgressTrackerHash=typeof pProgressTrackerHash=='string'?pProgressTrackerHash:'Default';// This call here can mean if we add operations and then immediately get the string, this function runs twice.
|
|
3800
3801
|
const tmpProgressTracker=this.progressTrackers[tmpProgressTrackerHash];// The states of a progress tracker:
|
|
3801
3802
|
if(tmpProgressTracker.CurrentCount<0){return"none";}else if(tmpProgressTracker.CurrentCount<1){return"0";}else{return"".concat(tmpProgressTracker.CurrentCount);}}getProgressTrackerPercentCompleteString(pProgressTrackerHash){let tmpProgressTrackerHash=typeof pProgressTrackerHash=='string'?pProgressTrackerHash:'Default';// This call here can mean if we add operations and then immediately get the string, this function runs twice.
|
|
3802
3803
|
// TODO: Is there a pattern to avoid this double call that's worth putting in?
|
|
3803
|
-
this.solveProgressTrackerStatus(tmpProgressTrackerHash);if(!this.progressTrackers
|
|
3804
|
+
this.solveProgressTrackerStatus(tmpProgressTrackerHash);if(!(tmpProgressTrackerHash in this.progressTrackers)){return"ProgressTracker ".concat(tmpProgressTrackerHash," does not exist! No stats to display.");}else{const tmpProgressTracker=this.progressTrackers[tmpProgressTrackerHash];// The states of a progress tracker:
|
|
3804
3805
|
// 1. Not started
|
|
3805
3806
|
if(tmpProgressTracker.StartTimeStamp<1){return"0%";}// 2. Started, but no operations completed
|
|
3806
3807
|
if(tmpProgressTracker.CurrentCount<1){return"0%";}// 3. Started, some operations completed
|
|
3807
3808
|
else if(tmpProgressTracker.EndTimeStamp<1){return"".concat(tmpProgressTracker.PercentComplete.toFixed(3),"%");}// 4. Done
|
|
3808
3809
|
else{return"".concat(tmpProgressTracker.PercentComplete.toFixed(3),"%");}}}getProgressTrackerStatusString(pProgressTrackerHash){let tmpProgressTrackerHash=typeof pProgressTrackerHash=='string'?pProgressTrackerHash:'Default';// This call here can mean if we add operations and then immediately get the string, this function runs twice.
|
|
3809
3810
|
// TODO: Is there a pattern to avoid this double call that's worth putting in?
|
|
3810
|
-
this.solveProgressTrackerStatus(tmpProgressTrackerHash);if(!this.progressTrackers
|
|
3811
|
+
this.solveProgressTrackerStatus(tmpProgressTrackerHash);if(!(tmpProgressTrackerHash in this.progressTrackers)){return"ProgressTracker ".concat(tmpProgressTrackerHash," does not exist! No stats to display.");}else{const tmpProgressTracker=this.progressTrackers[tmpProgressTrackerHash];// The states of a progress tracker:
|
|
3811
3812
|
// 1. Not started
|
|
3812
3813
|
if(tmpProgressTracker.StartTimeStamp<1){return"ProgressTracker ".concat(tmpProgressTracker.Hash," has not been started yet.");}// 2. Started, but no operations completed
|
|
3813
3814
|
if(tmpProgressTracker.CurrentCount<1&&tmpProgressTracker.EndTimeStamp<1){return"ProgressTracker ".concat(tmpProgressTracker.Hash," has no completed operations. ").concat(this.progressTimes.formatTimeDuration(tmpProgressTracker.ElapsedTime)," have elapsed since it was started.");}// 3. Started, some operations completed
|
|
3814
3815
|
else if(tmpProgressTracker.EndTimeStamp<1){return"ProgressTracker ".concat(tmpProgressTracker.Hash," is ").concat(tmpProgressTracker.PercentComplete.toFixed(3),"% completed - ").concat(tmpProgressTracker.CurrentCount," / ").concat(tmpProgressTracker.TotalCount," operations over ").concat(this.progressTimes.formatTimeDuration(tmpProgressTracker.ElapsedTime)," (median ").concat(this.progressTimes.formatTimeDuration(tmpProgressTracker.AverageOperationTime)," per). Estimated completion: ").concat(this.progressTimes.formatTimeDuration(tmpProgressTracker.EstimatedCompletionTime));}// 4. Done
|
|
3815
3816
|
else{return"ProgressTracker ".concat(tmpProgressTracker.Hash," is done. ").concat(tmpProgressTracker.CurrentCount," / ").concat(tmpProgressTracker.TotalCount," operations were completed in ").concat(this.progressTimes.formatTimeDuration(tmpProgressTracker.ElapsedTime)," (median ").concat(this.progressTimes.formatTimeDuration(tmpProgressTracker.AverageOperationTime)," per).");}}}logProgressTrackerStatus(pProgressTrackerHash){this.fable.log.info(this.getProgressTrackerStatusString(pProgressTrackerHash));}}module.exports=FableServiceProgressTrackerSet;},{"./Fable-Service-ProgressTracker/ProgressTracker.js":151,"fable-serviceproviderbase":51}],153:[function(require,module,exports){(function(Buffer){(function(){const libFableServiceBase=require('fable-serviceproviderbase');const libSimpleGet=require('simple-get');const libCookie=require('cookie');class FableServiceRestClient extends libFableServiceBase{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this.TraceLog=false;if(this.options.TraceLog||this.fable.TraceLog){this.TraceLog=true;}this.dataFormat=this.fable.services.DataFormat;this.serviceType='RestClient';this.cookie=false;// This is a function that can be overridden, to allow the management
|
|
3816
3817
|
// of the request options before they are passed to the request library.
|
|
3817
|
-
this.prepareRequestOptions=pOptions=>{return pOptions;};}get simpleGet(){return libSimpleGet;}prepareCookies(pRequestOptions){if(this.cookie){let tmpCookieObject=this.cookie;if(!
|
|
3818
|
+
this.prepareRequestOptions=pOptions=>{return pOptions;};}get simpleGet(){return libSimpleGet;}prepareCookies(pRequestOptions){if(this.cookie){let tmpCookieObject=this.cookie;if(!('headers'in pRequestOptions)){pRequestOptions.headers={};}let tmpCookieKeys=Object.keys(tmpCookieObject);if(tmpCookieKeys.length>0){// Only grab the first for now.
|
|
3818
3819
|
pRequestOptions.headers.cookie=libCookie.serialize(tmpCookieKeys[0],tmpCookieObject[tmpCookieKeys[0]]);}}return pRequestOptions;}preRequest(pOptions){// Validate the options object
|
|
3819
3820
|
let tmpOptions=this.prepareCookies(pOptions);// Prepend a string to the URL if it exists in the Fable Config
|
|
3820
|
-
if(this.fable.settings
|
|
3821
|
+
if('RestClientURLPrefix'in this.fable.settings){tmpOptions.url=this.fable.settings.RestClientURLPrefix+tmpOptions.url;}return this.prepareRequestOptions(tmpOptions);}executeChunkedRequest(pOptions,fCallback){let tmpOptions=this.preRequest(pOptions);tmpOptions.RequestStartTime=this.fable.log.getTimeStamp();if(this.TraceLog){this.fable.log.debug("Beginning ".concat(tmpOptions.method," request to ").concat(tmpOptions.url," at ").concat(tmpOptions.RequestStartTime));}return libSimpleGet(tmpOptions,(pError,pResponse)=>{if(pError){return fCallback(pError,pResponse);}if(this.TraceLog){let tmpConnectTime=this.fable.log.getTimeStamp();this.fable.log.debug("--> ".concat(tmpOptions.method," connected in ").concat(this.dataFormat.formatTimeDelta(tmpOptions.RequestStartTime,tmpConnectTime),"ms code ").concat(pResponse.statusCode));}let tmpData='';pResponse.on('data',pChunk=>{// For JSON, the chunk is the serialized object.
|
|
3821
3822
|
if(this.TraceLog){let tmpChunkTime=this.fable.log.getTimeStamp();this.fable.log.debug("--> ".concat(tmpOptions.method," data chunk size ").concat(pChunk.length,"b received in ").concat(this.dataFormat.formatTimeDelta(tmpOptions.RequestStartTime,tmpChunkTime),"ms"));}tmpData+=pChunk;});pResponse.on('end',()=>{if(this.TraceLog){let tmpCompletionTime=this.fable.log.getTimeStamp();this.fable.log.debug("==> ".concat(tmpOptions.method," completed data size ").concat(tmpData.length,"b received in ").concat(this.dataFormat.formatTimeDelta(tmpOptions.RequestStartTime,tmpCompletionTime),"ms"));}return fCallback(pError,pResponse,tmpData);});});}executeChunkedRequestBinary(pOptions,fCallback){let tmpOptions=this.preRequest(pOptions);tmpOptions.RequestStartTime=this.fable.log.getTimeStamp();if(this.TraceLog){this.fable.log.debug("Beginning ".concat(tmpOptions.method," request to ").concat(tmpOptions.url," at ").concat(tmpOptions.RequestStartTime));}tmpOptions.json=false;tmpOptions.encoding=null;return libSimpleGet(tmpOptions,(pError,pResponse)=>{if(pError){return fCallback(pError,pResponse);}if(this.TraceLog){let tmpConnectTime=this.fable.log.getTimeStamp();this.fable.log.debug("--> ".concat(tmpOptions.method," connected in ").concat(this.dataFormat.formatTimeDelta(tmpOptions.RequestStartTime,tmpConnectTime),"ms code ").concat(pResponse.statusCode));}let tmpDataBuffer=false;pResponse.on('data',pChunk=>{// For JSON, the chunk is the serialized object.
|
|
3822
3823
|
if(this.TraceLog){let tmpChunkTime=this.fable.log.getTimeStamp();this.fable.log.debug("--> ".concat(tmpOptions.method," data chunk size ").concat(pChunk.length,"b received in ").concat(this.dataFormat.formatTimeDelta(tmpOptions.RequestStartTime,tmpChunkTime),"ms"));}// TODO: Potentially create a third option that streams this to a file? So it doesn't have to hold it all in memory.
|
|
3823
|
-
if(!tmpDataBuffer){tmpDataBuffer=Buffer.from(pChunk);}else{tmpDataBuffer=Buffer.concat([tmpDataBuffer,pChunk]);}});pResponse.on('end',()=>{if(this.TraceLog){let tmpCompletionTime=this.fable.log.getTimeStamp();this.fable.log.debug("==> ".concat(tmpOptions.method," completed data size ").concat(tmpDataBuffer.length,"b received in ").concat(this.dataFormat.formatTimeDelta(tmpOptions.RequestStartTime,tmpCompletionTime),"ms"));}return fCallback(pError,pResponse,tmpDataBuffer);});});}executeJSONRequest(pOptions,fCallback){pOptions.json=true;let tmpOptions=this.preRequest(pOptions);if(!
|
|
3824
|
-
if (!
|
|
3824
|
+
if(!tmpDataBuffer){tmpDataBuffer=Buffer.from(pChunk);}else{tmpDataBuffer=Buffer.concat([tmpDataBuffer,pChunk]);}});pResponse.on('end',()=>{if(this.TraceLog){let tmpCompletionTime=this.fable.log.getTimeStamp();this.fable.log.debug("==> ".concat(tmpOptions.method," completed data size ").concat(tmpDataBuffer.length,"b received in ").concat(this.dataFormat.formatTimeDelta(tmpOptions.RequestStartTime,tmpCompletionTime),"ms"));}return fCallback(pError,pResponse,tmpDataBuffer);});});}executeJSONRequest(pOptions,fCallback){pOptions.json=true;let tmpOptions=this.preRequest(pOptions);if(!('headers'in tmpOptions)){tmpOptions.headers={};}/* Automated headers break some APIs
|
|
3825
|
+
if (!('Content-Type' in tmpOptions.headers))
|
|
3825
3826
|
{
|
|
3826
3827
|
tmpOptions.headers['Content-Type'] = 'application/json';
|
|
3827
3828
|
}
|
|
@@ -3880,5 +3881,5 @@ let tmpChunkSize=typeof pChunkSize=='number'?pChunkSize:0;let tmpChunkCache=type
|
|
|
3880
3881
|
// This is not meant to replace the more complex libraries such as moment or luxon.
|
|
3881
3882
|
// This *is* meant to be a simple, small, and fast way to convert ISO strings to dates in engines
|
|
3882
3883
|
// with ultra limited JS capabilities where those don't work.
|
|
3883
|
-
isoStringToDate(pISOString){if(!
|
|
3884
|
+
isoStringToDate(pISOString){if(!('Dates'in this.fable)){this.fable.instantiateServiceProvider('Dates');}let tmpDate=false;try{tmpDate=this.fable.Dates.dayJS.utc(pISOString);}catch(pError){// TODO: Should this throw? Doubtful.
|
|
3884
3885
|
this.fable.log.error("Could not parse date string ".concat(pISOString," with dayJS."));return false;}if(tmpDate){return tmpDate.toDate();}else{return false;}}}module.exports=FableServiceUtility;},{"async.eachlimit":1,"async.waterfall":15,"big.js":17,"fable-serviceproviderbase":51}]},{},[127])(127);});
|