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.
Files changed (24) hide show
  1. package/debug/Harness.js +13 -18
  2. package/dist/fable.compatible.js +93 -92
  3. package/dist/fable.compatible.min.js +2 -2
  4. package/dist/fable.compatible.min.js.map +1 -1
  5. package/dist/fable.js +93 -92
  6. package/dist/fable.min.js +2 -2
  7. package/dist/fable.min.js.map +1 -1
  8. package/package.json +5 -5
  9. package/source/Fable-Browser-Shim.js +1 -1
  10. package/source/Fable.js +11 -11
  11. package/source/services/Fable-Service-DataFormat.js +6 -6
  12. package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-Base.js +2 -2
  13. package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-ExpressionTokenizer.js +1 -1
  14. package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-Linter.js +2 -2
  15. package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-Postfix.js +4 -4
  16. package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-SolvePostfixedExpression.js +3 -3
  17. package/source/services/Fable-Service-FilePersistence.js +2 -2
  18. package/source/services/Fable-Service-MetaTemplate/MetaTemplate-StringParser.js +16 -16
  19. package/source/services/Fable-Service-MetaTemplate/MetaTemplate-WordTree.js +3 -3
  20. package/source/services/Fable-Service-Operation.js +1 -1
  21. package/source/services/Fable-Service-ProgressTime.js +7 -7
  22. package/source/services/Fable-Service-ProgressTrackerSet.js +11 -11
  23. package/source/services/Fable-Service-RestClient.js +4 -4
  24. 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.hasOwnProperty('showtimestamps')?this._Settings.showtimestamps==true:true;this._FormattedTimeStamps=this._Settings.hasOwnProperty('formattedtimestamps')?this._Settings.formattedtimestamps==true:true;this._ContextMessage=this._Settings.hasOwnProperty('Context')?"(".concat(this._Settings.Context,")"):pFableLog._Settings.hasOwnProperty('Product')?"(".concat(pFableLog._Settings.Product,")"):'Unnamed_Log_Context';// Allow the user to decide what gets output to the console
638
- this._OutputLogLinesToConsole=this._Settings.hasOwnProperty('outputloglinestoconsole')?this._Settings.outputloglinestoconsole:true;this._OutputObjectsToConsole=this._Settings.hasOwnProperty('outputobjectstoconsole')?this._Settings.outputobjectstoconsole:true;// Precompute the prefix for each level
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=tmpSettings.hasOwnProperty('LogStreams')?tmpSettings.LogStreams:require('./Fable-Log-DefaultStreams.json');this.logStreams=[];// This object gets decorated for one-time instantiated providers that
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.hasOwnProperty(pLogger.loggerUUID)){return false;}// Add it to the streams and to the mutex
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(!this._Providers.hasOwnProperty(tmpStreamDefinition.loggertype)){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.
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.hasOwnProperty(tmpEnvironmentVariableName)){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){/**
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'&&pSettings.hasOwnProperty('UUIDModeRandom')?pSettings.UUIDModeRandom==true:false;// These two properties are only useful if we are in Random mode. Otherwise it generates a v4 spec
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'&&pSettings.hasOwnProperty('UUIDLength')?pSettings.UUIDLength+0:8;// Dictionary for "Random UUID Mode"
745
- this._UUIDRandomDictionary=typeof pSettings==='object'&&pSettings.hasOwnProperty('UUIDDictionary')?pSettings.UUIDDictionary+0:'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';this.randomByteGenerator=new libRandomByteGenerator();// Lookup table for hex codes
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.hasOwnProperty(pTranslationHash)){delete this.translationTable[pTranslationHash];}}// This removes translations.
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.hasOwnProperty(pTranslation)){return this.translationTable[pTranslation];}else{return pTranslation;}}}module.exports=ManyfestHashTranslation;},{"./Manyfest-LogToConsole.js":71}],71:[function(require,module,exports){/**
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.hasOwnProperty(tmpFunctionAddress)&&typeof pObject[tmpFunctionAddress]=='function'){return true;}else{// The address suggests it is a function, but it is not.
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].hasOwnProperty(tmpBoxedPropertyReference);}else{// Use the new in operator to see if the element is in the array
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.hasOwnProperty(pAddress);}}else{let tmpSubObjectName=tmpAddressPartBeginning;let tmpNewAddress=pAddress.substring(tmpAddressPartBeginning.length+1);// Test if the tmpNewAddress is an array or object
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.hasOwnProperty(tmpSubObjectName)&&typeof pObject[tmpSubObjectName]!=='object'){return false;}else if(pObject.hasOwnProperty(tmpSubObjectName)){// If there is already a subobject pass that to the recursive thingy
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.hasOwnProperty(tmpSubObjectName)&&typeof pObject[tmpSubObjectName]!=='object'){return undefined;}else if(pObject.hasOwnProperty(tmpSubObjectName)){// If there is already a subobject pass that to the recursive thingy
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++){if(tmpFunctionArguments[i][0]=="'"&&tmpFunctionArguments[i][tmpFunctionArguments[i].length-1]=="'"){tmpArgumentValues.push(tmpFunctionArguments[i].substring(1,tmpFunctionArguments[i].length-1));}else if(tmpFunctionArguments[i][0]=='"'&&tmpFunctionArguments[i][tmpFunctionArguments[i].length-1]=='"'){tmpArgumentValues.push(tmpFunctionArguments[i].substring(1,tmpFunctionArguments[i].length-1));}else if(tmpFunctionArguments[i][0]=="`"&&tmpFunctionArguments[i][tmpFunctionArguments[i].length-1]=="`"){tmpArgumentValues.push(tmpFunctionArguments[i].substring(1,tmpFunctionArguments[i].length-1));}else{tmpArgumentValues.push(this.getValueAtAddress(tmpRootObject,tmpFunctionArguments[i]));}}return pObject[tmpFunctionAddress].apply(pObject,tmpArgumentValues);}}// Boxed elements look like this:
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.hasOwnProperty(tmpSubObjectName)&&typeof pObject[tmpSubObjectName]!=='object'){return undefined;}else if(pObject.hasOwnProperty(tmpSubObjectName)){// If there is already a subobject pass that to the recursive thingy
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(tmpEnclosureStartSymbolMap.hasOwnProperty(tmpString[i])){// Add it to the stack!
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(tmpEnclosureEndSymbolMap.hasOwnProperty(tmpString[i])// AND it matches the current nest level symbol
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(tmpEnclosureStartSymbolMap.hasOwnProperty(tmpString[i])){// Add it to the stack!
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(tmpEnclosureEndSymbolMap.hasOwnProperty(tmpString[i])// AND it matches the current nest level symbol
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(tmpEnclosureStartSymbolMap.hasOwnProperty(tmpString[i])){// Add it to the stack!
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(tmpEnclosureEndSymbolMap.hasOwnProperty(tmpString[i])// AND it matches the current nest level symbol
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.hasOwnProperty(tmpSubObjectName)&&typeof pObject[tmpSubObjectName]!=='object'){if(!pObject.hasOwnProperty('__ERROR'))pObject['__ERROR']={};// Put it in an error object so data isn't lost
1433
- pObject['__ERROR'][pAddress]=pValue;return false;}else if(pObject.hasOwnProperty(tmpSubObjectName)){// If there is already a subobject pass that to the recursive thingy
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].hasOwnProperty('Hash')){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
1532
- if(pManyfestSchemaDescriptors.hasOwnProperty(pInputAddress)){tmpOldDescriptorAddress=pInputAddress;}else if(tmpHashMapping.hasOwnProperty(pInputAddress)){tmpOldDescriptorAddress=tmpHashMapping[pInputAddress];}// If there was a matching descriptor in the manifest, store it in the temporary descriptor
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(!tmpNewManyfestSchemaDescriptors.hasOwnProperty(pDescriptorAddress)){tmpNewManyfestSchemaDescriptors[pDescriptorAddress]=tmpSource[pDescriptorAddress];}});return tmpNewManyfestSchemaDescriptors;}}module.exports=ManyfestSchemaManipulation;},{"./Manyfest-LogToConsole.js":71}],80:[function(require,module,exports){/**
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(!this.options.hasOwnProperty('defaultValues')){this.options.defaultValues={"String":"","Number":0,"Float":0.0,"Integer":0,"Boolean":false,"Binary":0,"DateTime":0,"Array":[],"Object":{},"Null":null};}if(!this.options.hasOwnProperty('strict')){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
+ 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(!tmpManifest.hasOwnProperty(tmpDescriptorKeys[i])){tmpManifest[tmpDescriptorKeys[i]]=JSON.parse(JSON.stringify(_DefaultConfiguration[tmpDescriptorKeys[i]]));}}if(tmpManifest.hasOwnProperty('Scope')){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(tmpManifest.hasOwnProperty('Descriptors')){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(tmpManifest.hasOwnProperty('HashTranslations')){if(typeof tmpManifest.HashTranslations==='object'){for(let i=0;i<tmpManifest.HashTranslations.length;i++){// Each translation is
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(!pDescriptor.hasOwnProperty('Address')){pDescriptor.Address=pAddress;}if(!this.elementDescriptors.hasOwnProperty(pAddress)){this.elementAddresses.push(pAddress);}// Add the element descriptor to the schema
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(pDescriptor.hasOwnProperty('Hash')){// TODO: Check if this is a good idea or not..
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.hasOwnProperty(pHash);let tmpInTranslationTable=this.hashTranslations.translationTable.hasOwnProperty(pHash);// The most straightforward: the hash exists, no translations.
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.elementHashes.hasOwnProperty(this.hashTranslations.translate(pHash))){tmpAddress=this.elementHashes[this.hashTranslations.translate(pHash)];}// Use the level of indirection only in the Translation Table
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(pDescriptor.hasOwnProperty('Default')){return pDescriptor.Default;}else{// Default to a null if it doesn't have a type specified.
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=pDescriptor.hasOwnProperty('DataType')?pDescriptor.DataType:'String';if(this.options.defaultValues.hasOwnProperty(tmpDataType)){return this.options.defaultValues[tmpDataType];}else{// give up and return null
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 pDescriptor.hasOwnProperty('Default');});}// Forcefully populate all values even if they don't have defaults.
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.hasOwnProperty(pServiceType)){// TODO: Check if any services are running?
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.hasOwnProperty(pServiceType)){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
3027
- addAndInstantiateServiceType(pServiceType,pServiceClass){this.addServiceType(pServiceType,pServiceClass);return this.instantiateServiceProvider(pServiceType,{},"".concat(pServiceType,"-Default"));}addAndInstantiateServiceTypeIfNotExists(pServiceType,pServiceClass){if(!this.servicesMap.hasOwnProperty(pServiceType)){return this.instantiateServiceProvider(pServiceType,{},"".concat(pServiceType,"-Default"));}else{return this.serviceClasses[pServiceType];}}// Some services expect to be overloaded / customized class.
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.hasOwnProperty(pServiceType)){this.setDefaultServiceInstantiation(pServiceType,tmpService.Hash);}return tmpService;}instantiateServiceProvider(pServiceType,pOptions,pCustomServiceHash){// Instantiate the service
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.hasOwnProperty(pServiceType)){this.setDefaultServiceInstantiation(pServiceType,tmpService.Hash);}return tmpService;}instantiateServiceProviderIfNotExists(pServiceType,pOptions,pCustomServiceHash){if(this.services.hasOwnProperty(pServiceType)){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
+ 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.hasOwnProperty(tmpServiceType)){// If the core service hasn't registered itself yet, create the service container for it.
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.hasOwnProperty(tmpServiceType)){this.setDefaultServiceInstantiation(tmpServiceType,tmpServiceHash,false);}return pServiceInstance;}setDefaultServiceInstantiation(pServiceType,pServiceHash,pOverwriteService){// Overwrite services by default, unless told not to
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].hasOwnProperty(pServiceHash)){if(!this.hasOwnProperty(pServiceType)||tmpOverwriteService){this[pServiceType]=this.servicesMap[pServiceType][pServiceHash];}if(!this.services.hasOwnProperty(pServiceType)||tmpOverwriteService){this.services[pServiceType]=this.servicesMap[pServiceType][pServiceHash];}return true;}return false;}}// This is for backwards compatibility
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(tmpEnclosureStartSymbolMap.hasOwnProperty(tmpString[i])){// Add it to the stack!
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(tmpEnclosureEndSymbolMap.hasOwnProperty(tmpString[i])// AND it matches the current nest level symbol
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(tmpEnclosureStartSymbolMap.hasOwnProperty(tmpString[i])){// Add it to the stack!
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(tmpEnclosureEndSymbolMap.hasOwnProperty(tmpString[i])// AND it matches the current nest level symbol
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(tmpEnclosureStartSymbolMap.hasOwnProperty(tmpString[i])){// Add it to the stack!
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(tmpEnclosureEndSymbolMap.hasOwnProperty(tmpString[i])// AND it matches the current nest level symbol
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.hasOwnProperty(pToken)){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
+ 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.hasOwnProperty(pToken)?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
+ }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.hasOwnProperty(tmpCharacter)){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
+ 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.hasOwnProperty(pTokenizedExpression[i])&&this.ExpressionParser.tokenMap[pTokenizedExpression[i]].Type!='Parenthesis'&&!tmpTokenPrevious){tmpTokenPrevious=true;}else if(this.ExpressionParser.tokenMap.hasOwnProperty(pTokenizedExpression[i])&&this.ExpressionParser.tokenMap[pTokenizedExpression[i]].Type!='Parenthesis'){// If this isn't a + or - positivity/negativity multiplier, it's an error.
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].hasOwnProperty('Descriptor')&&tmpOperation.Operation.hasOwnProperty('Descriptor')&&// Anything >3 does not have commutative properties
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].hasOwnProperty('Descriptor')&&tmpOperation.Operation.hasOwnProperty('Descriptor')&&// Anything >3 does not have commutative properties
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(!tmpSolveLayerMap.hasOwnProperty(tmpResults.PostfixTokenObjects[i].SolveLayerStack)){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
+ 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'&&tmpOpenParenthesis.hasOwnProperty('PreviousPrecedence')){// This is the second most complex case -- the next token is an 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=tmpResults.hasOwnProperty('fable');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
+ 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(this.ExpressionParser.tokenMap.hasOwnProperty(tmpStepResultObject.ExpressionStep.Operation.Token)){tmpFunctionAddress="ResultsObject.".concat(tmpStepResultObject.ExpressionStep.Operation.Descriptor.Function);}else if(this.ExpressionParser.functionMap.hasOwnProperty(tmpStepResultObject.ExpressionStep.Operation.Token.toLowerCase())){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
+ 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(!this.options.hasOwnProperty('Mode')){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
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(!tmpParameters.hasOwnProperty('Mode')){tmpParameters.Mode=this.options.Mode;}// Check if we are just starting .. if so, build the initial state for our recursive function
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.hasOwnProperty(pCharacter)){pParserState.Pattern=pParserState.Pattern[pCharacter];this.appendOutputBuffer(pCharacter,pParserState);}else if(pParserState.EndPatternMatchBegan){if(pParserState.Pattern.PatternEnd.hasOwnProperty(pCharacter)){// This leaf has a PatternEnd tree, so we will wait until that end is met.
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.hasOwnProperty('Parse')&&(!pParserState.Pattern.isAsync||pParserState.Pattern.isBoth)){// Run the function
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.hasOwnProperty(pCharacter)){// We broke out of the end -- see if this is a new start of the end.
3686
- pParserState.Pattern=pParserState.PatternStartNode.PatternEnd[pCharacter];this.appendOutputBuffer(pCharacter,pParserState);}else{pParserState.EndPatternMatchBegan=false;this.appendOutputBuffer(pCharacter,pParserState);}}else if(pParserState.Pattern.hasOwnProperty('PatternEnd')){if(!pParserState.StartPatternMatchComplete){pParserState.StartPatternMatchComplete=true;pParserState.PatternStartNode=pParserState.Pattern;}this.appendOutputBuffer(pCharacter,pParserState);if(pParserState.Pattern.PatternEnd.hasOwnProperty(pCharacter)){// This is the first character of the end 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.hasOwnProperty('Parse')){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
+ 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.hasOwnProperty(pCharacter)){// ... assign the root node as the matched node.
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.hasOwnProperty(pCharacter)){pParserState.Pattern=pParserState.Pattern[pCharacter];this.appendOutputBuffer(pCharacter,pParserState);}else if(pParserState.EndPatternMatchBegan){if(pParserState.Pattern.PatternEnd.hasOwnProperty(pCharacter)){// This leaf has a PatternEnd tree, so we will wait until that end is met.
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.hasOwnProperty('Parse')){return this.executePatternAsync(pParserState,pData,fCallback,pDataContext);}}else if(pParserState.PatternStartNode.PatternEnd.hasOwnProperty(pCharacter)){// We broke out of the end -- see if this is a new start of the end.
3714
- pParserState.Pattern=pParserState.PatternStartNode.PatternEnd[pCharacter];this.appendOutputBuffer(pCharacter,pParserState);}else{pParserState.EndPatternMatchBegan=false;this.appendOutputBuffer(pCharacter,pParserState);}}else if(pParserState.Pattern.hasOwnProperty('PatternEnd')){if(!pParserState.StartPatternMatchComplete){pParserState.StartPatternMatchComplete=true;pParserState.PatternStartNode=pParserState.Pattern;}this.appendOutputBuffer(pCharacter,pParserState);if(pParserState.Pattern.PatternEnd.hasOwnProperty(pCharacter)){// This is the first character of the end 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.hasOwnProperty('Parse')){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
+ 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.hasOwnProperty(pCharacter)){// ... assign the root node as the matched node.
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(!pTree.hasOwnProperty(pPattern)){pTree[pPattern]={};}return pTree[pPattern];}/**
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(!pTree.hasOwnProperty('PatternEnd')){pTree.PatternEnd={};}pTree.PatternEnd[pPattern]={};return pTree.PatternEnd[pPattern];}/** Add a Pattern to the Parse Tree
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(!tmpLeaf.hasOwnProperty('PatternEnd')){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
+ 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.hasOwnProperty(pGUIDStep)){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 this.timeStamps.hasOwnProperty(tmpTimeStampHash)?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.
3791
- if(typeof pReferenceTime=='string'){tmpReferenceTime=this.timeStamps.hasOwnProperty(tmpReference)?this.timeStamps[tmpReference]:false;}else if(typeof pReferenceTime=='number'){tmpReferenceTime=pReferenceTime;}else{tmpReferenceTime=+new Date();}if(this.timeStamps.hasOwnProperty(tmpTimeStampHash)&&tmpReferenceTime){this.timeStamps[tmpTimeStampHash]=tmpReferenceTime;return this.timeStamps[tmpTimeStampHash];}else{return-1;}}removeTimeStamp(pTimeStampHash){let tmpTimeStampHash=typeof pTimeStampHash=='string'?pTimeStampHash:'Default';if(this.timeStamps.hasOwnProperty(tmpTimeStampHash)){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.
3792
- if(typeof pReferenceTime=='string'){tmpReferenceTime=this.timeStamps.hasOwnProperty(tmpReference)?this.timeStamps[tmpReference]:false;}else if(typeof pReferenceTime=='number'){tmpReferenceTime=pReferenceTime;}else{tmpReferenceTime=+new Date();}if(this.timeStamps.hasOwnProperty(tmpTimeStampHash)&&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(this.timeStamps.hasOwnProperty(tmpTimeStampHashStart)&&this.timeStamps.hasOwnProperty(tmpTimeStampHashEnd)){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
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.hasOwnProperty(tmpProgressTrackerHash)){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(!this.progressTrackers.hasOwnProperty(tmpProgressTrackerHash)){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%
3795
- AllowTruePercentComplete:false,ElapsedTime:-1,AverageOperationTime:-1,EstimatedCompletionTime:-1,TotalCount:tmpTotalOperations,CurrentCount:-1};if(this.progressTrackers.hasOwnProperty(tmpProgressTrackerHash)){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(!this.progressTrackers.hasOwnProperty(tmpProgressTrackerHash)){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
3796
- if(!this.progressTrackers.hasOwnProperty(tmpProgressTrackerHash)){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(!this.progressTrackers.hasOwnProperty(tmpProgressTrackerHash)){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(!this.progressTrackers.hasOwnProperty(tmpProgressTrackerHash)){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.
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.hasOwnProperty(tmpProgressTrackerHash)){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(!this.progressTrackers.hasOwnProperty(tmpProgressTrackerHash)){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
+ 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.hasOwnProperty(tmpProgressTrackerHash)){return"ProgressTracker ".concat(tmpProgressTrackerHash," does not exist! No stats to display.");}else{const tmpProgressTracker=this.progressTrackers[tmpProgressTrackerHash];// The states of a progress tracker:
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.hasOwnProperty(tmpProgressTrackerHash)){return"ProgressTracker ".concat(tmpProgressTrackerHash," does not exist! No stats to display.");}else{const tmpProgressTracker=this.progressTrackers[tmpProgressTrackerHash];// The states of a progress tracker:
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(!pRequestOptions.hasOwnProperty('headers')){pRequestOptions.headers={};}let tmpCookieKeys=Object.keys(tmpCookieObject);if(tmpCookieKeys.length>0){// Only grab the first for now.
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.hasOwnProperty('RestClientURLPrefix')){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
+ 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(!tmpOptions.hasOwnProperty('headers')){tmpOptions.headers={};}/* Automated headers break some APIs
3824
- if (!tmpOptions.headers.hasOwnProperty('Content-Type'))
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(!this.fable.hasOwnProperty('Dates')){this.fable.instantiateServiceProvider('Dates');}let tmpDate=false;try{tmpDate=this.fable.Dates.dayJS.utc(pISOString);}catch(pError){// TODO: Should this throw? Doubtful.
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);});