Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

fable

Package Overview
Dependencies
Maintainers
2
Versions
155
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fable - npm Package Compare versions

Comparing version 3.0.135 to 3.0.136

example_applications/mathematical_playground/.vscode/launch.json

65

example_applications/mathematical_playground/Math-Solver-Harness.js

@@ -18,31 +18,31 @@ const libFable = require('../../source/Fable.js');

// Look up somoe variables in an object
_Fable.log.info(`One-liner solve with variables is: ${_ExpressionParser.solve("Volume = Width * Height * Depth", {"Width": 73.5, "Height": 28.8, "Depth": 200.5})}`);
// _Fable.log.info(`One-liner solve with variables is: ${_ExpressionParser.solve("Volume = Width * Height * Depth", {"Width": 73.5, "Height": 28.8, "Depth": 200.5})}`);
/* * * * * * * * * * * * * * * * *
*
* A simple run through of some mathematical expressions
*
*/
_Fable.log.info(`Beginning Run-through for Set of Test Expressions....`);
// An array of equations with expected values
let _Equations = require(`./Equations.json`);
// The application state is a plain javascript object we pass into the solver to pull variables from
let _AppData = require(`./AppData.json`);
// The manifest is a Manyfest which describes hashes for complex addresses in the application state object
// For example you can't use "Student[0].Age" as a variable in the expression
// ...but you can use "Student[0].Age" as an address in the manifest with a hash of "StudentAge"
// ...and then reference "StudentAge" in the expression.
let tmpManifestConfiguration = { "Scope":"None", "Descriptors":[] };
let tmpManifest = _Fable.newManyfest(tmpManifestConfiguration);
// Run each expression in the Equations.json file through the expression parser.
for (let i = 0; i < _Equations.Expressions.length; i++)
{
let tmpResultValue = _ExpressionParser.solve(_Equations.Expressions[i].Equation, _AppData, {}, tmpManifest);
console.log(`Expression [${i}]: [${_Equations.Expressions[i].Equation}] ==> ${tmpResultValue}`);
if (tmpResultValue !== _Equations.Expressions[i].ExpectedResult)
{
console.log(`Error: Equation ${_Equations.Expressions[i].Equation} expected [${_Equations.Expressions[i].ExpectedResult}] but got [${tmpResultValue}]`);
}
}
// /* * * * * * * * * * * * * * * * *
// *
// * A simple run through of some mathematical expressions
// *
// */
// _Fable.log.info(`Beginning Run-through for Set of Test Expressions....`);
// // An array of equations with expected values
// let _Equations = require(`./Equations.json`);
// // The application state is a plain javascript object we pass into the solver to pull variables from
// let _AppData = require(`./AppData.json`);
// // The manifest is a Manyfest which describes hashes for complex addresses in the application state object
// // For example you can't use "Student[0].Age" as a variable in the expression
// // ...but you can use "Student[0].Age" as an address in the manifest with a hash of "StudentAge"
// // ...and then reference "StudentAge" in the expression.
// let tmpManifestConfiguration = { "Scope":"None", "Descriptors":[] };
// let tmpManifest = _Fable.newManyfest(tmpManifestConfiguration);
// // Run each expression in the Equations.json file through the expression parser.
// for (let i = 0; i < _Equations.Expressions.length; i++)
// {
// let tmpResultValue = _ExpressionParser.solve(_Equations.Expressions[i].Equation, _AppData, {}, tmpManifest);
// console.log(`Expression [${i}]: [${_Equations.Expressions[i].Equation}] ==> ${tmpResultValue}`);
// if (tmpResultValue !== _Equations.Expressions[i].ExpectedResult)
// {
// console.log(`Error: Equation ${_Equations.Expressions[i].Equation} expected [${_Equations.Expressions[i].ExpectedResult}] but got [${tmpResultValue}]`);
// }
// }

@@ -63,3 +63,3 @@

// The expression we pass into the solver is just a string
let tmpExpression = 'HyperMax.HealthIndex = (SUM(Calories) / SUM(Sugar)) * MEDIAN(Fat) + (SQRT(AVG(Protein)) - (PI() + 99)';
let tmpExpression = 'HyperMax.HealthIndex = (SUM(Calories) / SUM(Sugar)) * MEDIAN(Fat) + (SQRT(AVG(Protein)) - (PI() + 99))';
_Fable.log.info(`Solving tmpExpression: [${tmpExpression}]`);

@@ -79,11 +79,8 @@

_ExpressionParser.substituteValuesInTokenizedObjects(tmpExpressionParseOutcome.PostfixTokenObjects, _FruitData, tmpExpressionParseOutcome, _FruitManifest);
// Now that we have a postfixed expression and the mapped-in values, show the user what the solution steps look like
for (let i = 0; i < tmpExpressionParseOutcome.PostfixSolveList.length; i++)
{
let tmpToken = tmpExpressionParseOutcome.PostfixSolveList[i];
console.log(`${i}: ${tmpToken.VirtualSymbolName} = (${tmpToken.LeftValue.Token}::${tmpToken.LeftValue.Value}) ${tmpToken.Operation.Token} (${tmpToken.RightValue.Token}::${tmpToken.RightValue.Value}) `)
}
// Step 5: Solve the postfixed expression
let tmpResultValue = _ExpressionParser.solvePostfixedExpression(tmpExpressionParseOutcome.PostfixSolveList, tmpSolverResultsObject, tmpExpressionParseOutcome, _FruitManifest);
// Now that we have a solved expression and the mapped-in values, show the user the solution
_Fable.ExpressionParser.Messaging.logFunctionOutcome(tmpExpressionParseOutcome);
// Step 6: Look at the results.

@@ -90,0 +87,0 @@ console.log(`Outcome object: ${JSON.stringify(tmpSolverResultsObject)}`);

{
"name": "fable",
"version": "3.0.135",
"version": "3.0.136",
"description": "A service dependency injection, configuration and logging library.",

@@ -5,0 +5,0 @@ "main": "source/Fable.js",

@@ -17,3 +17,3 @@ const { PE } = require('big.js');

*
* There were two problems with the codebase...
* There were two problems with the codebase above...
*

@@ -26,3 +26,3 @@ * First, the code was very unreadable and determining it was correct or extending it

* numbers and an arbitrary precision library as the back-end would have taken a significantly
* longer amount of time than just writing the parser from scratch, et voila.
* longer amount of time than just writing the parser from scratch... et voila.
*/

@@ -32,2 +32,8 @@

{
/**
* Constructs a new instance of the ExpressionParser service.
* @param {Object} pFable - The Fable object.
* @param {Object} pOptions - The options for the service.
* @param {string} pServiceHash - The hash of the service.
*/
constructor(pFable, pOptions, pServiceHash)

@@ -37,6 +43,8 @@ {

// The configuration for tokens that the solver recognizes, with precedence and friendly names.
this.tokenMap = require('./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-TokenMap.json');
// This precedence is higher than defined in our token map
this.tokenMaxPrecedence = 5;
// This precedence is higher than defined in our token map. We could make this value dynamic
this.tokenMaxPrecedence = 10;
// The configuration for which functions are available to the solver.
this.functionMap = require('./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-FunctionMap.json');

@@ -46,142 +54,41 @@

// These are sub-services for the tokenizer, linter, compiler, marshaler and solver.
this.fable.addServiceTypeIfNotExists('ExpressionParser-Tokenizer', require('./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-ExpressionTokenizer.js'));
this.fable.addServiceTypeIfNotExists('ExpressionParser-Linter', require('./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-Linter.js'));
this.fable.addServiceTypeIfNotExists('ExpressionParser-Postfix', require('./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-Postfix.js'));
this.fable.addServiceTypeIfNotExists('ExpressionParser-ValueMarshal', require('./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-ValueMarshal.js'));
this.fable.addServiceTypeIfNotExists('ExpressionParser-Solver', require('./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-SolvePostfixedExpression.js'));
// And the sub-service for the friendly user messaging
this.fable.addServiceTypeIfNotExists('ExpressionParser-Messaging', require('./Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-Messaging.js'));
// This code instantitates these fable services to child objects of this service, but does not pollute the main fable with them.
this.Tokenizer = this.fable.instantiateServiceProviderWithoutRegistration('ExpressionParser-Tokenizer');
this.Linter = this.fable.instantiateServiceProviderWithoutRegistration('ExpressionParser-Linter');
this.Postfix = this.fable.instantiateServiceProviderWithoutRegistration('ExpressionParser-Postfix');
this.ValueMarshal = this.fable.instantiateServiceProviderWithoutRegistration('ExpressionParser-ValueMarshal');
this.Solver = this.fable.instantiateServiceProviderWithoutRegistration('ExpressionParser-Solver');
this.Messaging = this.fable.instantiateServiceProviderWithoutRegistration('ExpressionParser-Messaging');
// Now wire each of these up. Not in love with this pattern but better than a giant file here.
// Wire each sub service into this instance of the solver.
this.Tokenizer.connectExpressionParser(this);
this.Linter.connectExpressionParser(this);
this.Postfix.connectExpressionParser(this);
this.ValueMarshal.connectExpressionParser(this);
this.Solver.connectExpressionParser(this);
}
this.Messaging.connectExpressionParser(this);
substituteValuesInTokenizedObjects(pTokenizedObjects, pDataSource, pResultObject, pManifest)
{
let tmpResults = (typeof(pResultObject) === 'object') ? pResultObject : { ExpressionParserLog: [] };
if (!Array.isArray(pTokenizedObjects))
{
tmpResults.ExpressionParserLog.push(`ERROR: ExpressionParser.substituteValuesInTokenizedObjects was passed a non-array tokenized object list.`);
this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);
return pTokenizedObjects;
}
if (typeof(pDataSource) !== 'object')
{
tmpResults.ExpressionParserLog.push(`ERROR: ExpressionParser.substituteValuesInTokenizedObjects either was passed no data source, or was passed a non-object data source.`);
this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);
return pTokenizedObjects;
}
let tmpDataSource = pDataSource;
let tmpManifest = (typeof(pManifest) == 'object') ? pManifest : this.fable.newManyfest(pManifest);
for (let i = 0; i < pTokenizedObjects.length; i++)
{
if (typeof(pTokenizedObjects[i]) !== 'object')
{
tmpResults.ExpressionParserLog.push(`WARNING: ExpressionParser.substituteValuesInTokenizedObjects found a non-object tokenized object at index ${i}`);
this.log.warn(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);
continue;
}
let tmpToken = pTokenizedObjects[i];
if ((pTokenizedObjects[i].Type === 'Token.Symbol') && !tmpToken.Resolved)
{
// Symbols always look up values by hash first
let tmpValue = tmpManifest.getValueByHash(tmpDataSource, tmpToken.Token);
// if (!tmpValue)
// {
// // If no hash resolves, try by address.
// tmpValue = tmpManifest.getValueAtAddress(tmpToken.Token, tmpDataSource);
// }
if (!tmpValue)
{
tmpResults.ExpressionParserLog.push(`WARNING: ExpressionParser.substituteValuesInTokenizedObjects found no value for the symbol hash or address ${tmpToken.Token} at index ${i}`);
this.log.warn(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);
continue;
}
else
{
tmpResults.ExpressionParserLog.push(`INFO: ExpressionParser.substituteValuesInTokenizedObjects found a value [${tmpValue}] for the state address ${tmpToken.Token} at index ${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)
{
// TODO: Should we allow this to be a function? Good god the complexity and beauty of that...
if (Array.isArray(tmpValue) || (typeof(tmpValue) === 'object'))
{
tmpToken.Resolved = true;
tmpToken.Value = tmpValue;
}
else
{
tmpResults.ExpressionParserLog.push(`INFO: ExpressionParser.substituteValuesInTokenizedObjects found a non-numeric, non-set value for the state address ${tmpToken.Token} at index ${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.
let tmpValue = tmpManifest.getValueAtAddress(tmpDataSource, tmpToken.Token);
if (!tmpValue)
{
tmpResults.ExpressionParserLog.push(`WARNING: ExpressionParser.substituteValuesInTokenizedObjects found no value for the state address ${tmpToken.Token} at index ${i}`);
this.log.warn(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);
continue;
}
else
{
//tmpResults.ExpressionParserLog.push(`INFO: ExpressionParser.substituteValuesInTokenizedObjects found a value [${tmpValue}] for the state address ${tmpToken.Token} at index ${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 ${tmpToken.Token} at index ${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 [${tmpToken.Token}] for the constant ${tmpToken.Token} at index ${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.
tmpResults.ExpressionParserLog.push(`ERROR: ExpressionParser.substituteValuesInTokenizedObjects found a non-numeric value for the state address ${tmpToken.Token} at index ${i}`);
this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);
tmpToken.Resolved = false;
}
}
}
return pTokenizedObjects;
this.GenericManifest = this.fable.newManyfest();
// This will look for a LogNoisiness on fable (or one that falls in from pict) and if it doesn't exist, set one for this service.
this.LogNoisiness = ('LogNoisiness' in this.fable) ? this.fable.LogNoisiness : 0;
}
/**
* Tokenizes the given mathematical expression string.
*
* @param {string} pExpression - The expression to tokenize.
* @param {object} pResultObject - The result object to store the tokenized expression.
* @returns {object} - The tokenized expression.
*/
tokenize(pExpression, pResultObject)

@@ -192,2 +99,9 @@ {

/**
* Lints a tokenized expression.
*
* @param {Array} pTokenizedExpression - The tokenized expression to lint.
* @param {Object} pResultObject - The result object where we store the linting result.
* @returns {Object} - The linting result object.
*/
lintTokenizedExpression(pTokenizedExpression, pResultObject)

@@ -198,2 +112,9 @@ {

/**
* Builds a postfix solve list for the given tokenized expression and result object.
*
* @param {Array} pTokenizedExpression - The tokenized expression.
* @param {Object} pResultObject - The result object where the algorithm "shows its work".
* @returns {Array} The postfix solve list.
*/
buildPostfixedSolveList(pTokenizedExpression, pResultObject)

@@ -204,2 +125,27 @@ {

/**
* Substitutes values in tokenized objects.
*
* This means marshaling data from pDataSource into the array of objects with the passed in Manifest (or a generic manifest) to prepare for solving.
*
* @param {Array} pTokenizedObjects - The array of tokenized objects.
* @param {Object} pDataSource - The data source object.
* @param {Object} pResultObject - The result object.
* @param {Object} pManifest - The manifest object.
* @returns {Object} - The updated result object.
*/
substituteValuesInTokenizedObjects(pTokenizedObjects, pDataSource, pResultObject, pManifest)
{
return this.ValueMarshal.substituteValuesInTokenizedObjects(pTokenizedObjects, pDataSource, pResultObject, pManifest);
}
/**
* Solves a postfixed expression Array.
*
* @param {Array} pPostfixedExpression - The postfixed expression to solve.
* @param {object} pDataDestinationObject - The data destination object where data gets marshaled to after solving.
* @param {object} pResultObject - The result object where the algorithm "shows its work".
* @param {object} pManifest - The manifest object.
* @returns {any} The result of the solved expression.
*/
solvePostfixedExpression(pPostfixedExpression, pDataDestinationObject, pResultObject, pManifest)

@@ -226,2 +172,3 @@ {

// This is technically a "pre-compile" and we can keep this Results Object around to reuse for better performance. Not required.
this.tokenize(pExpression, tmpResultsObject);

@@ -231,3 +178,6 @@ this.lintTokenizedExpression(tmpResultsObject.RawTokens, tmpResultsObject);

// This is where the data from variables gets marshaled into their symbols (from AppData or the like)
this.substituteValuesInTokenizedObjects(tmpResultsObject.PostfixTokenObjects, tmpDataSourceObject, tmpResultsObject, pManifest);
// Finally this is the expr solving method, which returns a string and also marshals it into tmpDataDestinationObject
return this.solvePostfixedExpression(tmpResultsObject.PostfixSolveList, tmpDataDestinationObject, tmpResultsObject, pManifest);

@@ -234,0 +184,0 @@ }

@@ -8,3 +8,2 @@ const libExpressionParserOperationBase = require('./Fable-Service-ExpressionParser-Base.js');

super(pFable, pOptions, pServiceHash);
this.serviceType = 'ExpressionParser-Tokenizer';

@@ -11,0 +10,0 @@ }

@@ -8,3 +8,2 @@ const libExpressionParserOperationBase = require('./Fable-Service-ExpressionParser-Base.js');

super(pFable, pOptions, pServiceHash);
this.serviceType = 'ExpressionParser-Linter';

@@ -11,0 +10,0 @@ }

@@ -8,3 +8,2 @@ const libExpressionParserOperationBase = require('./Fable-Service-ExpressionParser-Base.js');

super(pFable, pOptions, pServiceHash);
this.serviceType = 'ExpressionParser-Postfix';

@@ -642,5 +641,9 @@ }

// 7. Lastly set the assignment address.
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);
let tmpAbstractAssignToken = this.getTokenContainerObject('=');
// The address we are assigning to
tmpAbstractAssignToken.VirtualSymbolName = tmpResults.PostfixedAssignmentAddress;
// The address it's coming from
let tmpSolveResultToken = this.getTokenContainerObject('Result', 'Token.LastResult');
let tmpFinalAssignmentInstruction = this.getPosfixSolveListOperation(tmpAbstractAssignToken, tmpSolveResultToken, this.getTokenContainerObject('SolverMarshal', 'Token.SolverMarshal'));
tmpResults.PostfixSolveList.push(tmpFinalAssignmentInstruction);

@@ -647,0 +650,0 @@ return tmpResults.PostfixSolveList;

@@ -8,3 +8,2 @@ const libExpressionParserOperationBase = require('./Fable-Service-ExpressionParser-Base.js');

super(pFable, pOptions, pServiceHash);
this.serviceType = 'ExpressionParser-Solver';

@@ -52,3 +51,11 @@ }

// Resolve the virtual symbols to their actual values
if (tmpStepResultObject.ExpressionStep.LeftValue.Type === 'Token.LastResult')
{
tmpStepResultObject.ExpressionStep.LeftValue.Value = tmpResults.LastResult;
}
if (tmpStepResultObject.ExpressionStep.RightValue.Type === 'Token.LastResult')
{
tmpStepResultObject.ExpressionStep.RightValue.Value = tmpResults.LastResult;
}
if (tmpStepResultObject.ExpressionStep.LeftValue.Type === 'Token.VirtualSymbol')

@@ -100,3 +107,4 @@ {

//this.log.trace(`Solving Step ${i} [${tmpStepResultObject.ExpressionStep.VirtualSymbolName}] --> [${tmpStepResultObject.ExpressionStep.Operation.Token}]: ( ${tmpStepResultObject.ExpressionStep.LeftValue.Value} , ${tmpStepResultObject.ExpressionStep.RightValue.Value} )`);
tmpResults.VirtualSymbols[tmpStepResultObject.ExpressionStep.VirtualSymbolName] = tmpManifest.getValueAtAddress(tmpStepResultObject, `${tmpFunctionAddress}(ExpressionStep.LeftValue.Value,ExpressionStep.RightValue.Value)`);
tmpManifest.setValueAtAddress(tmpResults.VirtualSymbols, tmpStepResultObject.ExpressionStep.VirtualSymbolName, tmpManifest.getValueAtAddress(tmpStepResultObject, `${tmpFunctionAddress}(ExpressionStep.LeftValue.Value,ExpressionStep.RightValue.Value)`));
tmpResults.LastResult = tmpManifest.getValueAtAddress(tmpResults.VirtualSymbols, tmpStepResultObject.ExpressionStep.VirtualSymbolName);
//this.log.trace(` ---> Step ${i}: ${tmpResults.VirtualSymbols[tmpStepResultObject.ExpressionStep.VirtualSymbolName]}`)

@@ -118,6 +126,6 @@ }

// Now deal with final assignment
// Now deal with final assignment(s)
for (let i = 0; i < pPostfixedExpression.length; i++)
{
if ((pPostfixedExpression[i].Operation.Type === 'Token.SolverInstruction') && (pPostfixedExpression[i].Operation.Token == 'Assign'))
if (pPostfixedExpression[i].RightValue.Type === 'Token.SolverMarshal')
{

@@ -127,5 +135,6 @@ tmpManifest.setValueAtAddress(tmpResults.VirtualSymbols, pPostfixedExpression[i].VirtualSymbolName, tmpSolverResultValue);

}
}
tmpResults.RawResult = tmpSolverResultValue;
}
// Clean up the reference if we added it to the object.
// Clean up the fable reference if we added it to the object.
if (!tmpPassedInFable)

@@ -132,0 +141,0 @@ {

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc