Socket
Socket
Sign inDemoInstall

@airtasker/form-schema-compiler

Package Overview
Dependencies
1
Maintainers
1
Versions
19
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.1.1 to 0.1.2

lib/interpreter/evaluateConditionalExpression.js

80

lib/compileComponents.js

@@ -6,2 +6,4 @@ "use strict";

var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

@@ -153,3 +155,3 @@

if (error.kind === 'ErrorPathTrace') {
if (error.kind === "ErrorPathTrace") {
_this.path = key + "." + error.path;

@@ -161,5 +163,4 @@ _this.originMessage = error.originMessage;

}
_this.kind = 'ErrorPathTrace';
_this.kind = "ErrorPathTrace";
_this.message = "Found an error in " + _this.path + ". Error details: " + _this.originMessage;
return _this;

@@ -171,3 +172,47 @@ }

var tripeOutFromProgramInPropertyBinding = function tripeOutFromProgramInPropertyBinding(ast) {
if (ast.type !== _const.TYPES.PropertyBinding || ast.value.type !== _const.TYPES.Program) {
return ast;
}
return _extends({}, ast, {
value: ast.value.body[0]
});
};
/**
* compile PropertyBindingValue to ast expression
* @param {*} options
* @param {*} value
*/
var compilePropertyBindingValue = function compilePropertyBindingValue(options, value) {
if (Array.isArray(value)) {
return {
type: _const.TYPES.ArrayExpression,
elements: value.map(function (v) {
return tripeOutFromProgramInPropertyBinding(compilePropertyBindingValue(options, v));
})
};
} else if ((typeof value === "undefined" ? "undefined" : _typeof(value)) === "object") {
return {
type: _const.TYPES.ObjectExpression,
properties: Object.entries(compileProps(value, options)).map(function (_ref) {
var _ref2 = _slicedToArray(_ref, 2),
key = _ref2[0],
value = _ref2[1];
return {
key: toValueObject(key),
value: tripeOutFromProgramInPropertyBinding(value)
};
})
};
} else if (typeof value === "string") {
return (0, _parsers.parseExpressionString)(value);
}
throw new Error("Unsupported type for property binding " + (typeof value === "undefined" ? "undefined" : _typeof(value)));
};
/**
* compile value to ast expression,

@@ -179,4 +224,2 @@ * examples see expression parsers and tests

*/
var compileValue = (0, _curry2.default)(function (options, value, key) {

@@ -188,16 +231,11 @@ try {

type: _const.ANNOTATION_TYPES.EventBinding,
value: (0, _parsers.parseExpressionString)(value)
value: (0, _parsers.parseBlockExpressionString)(value)
};
case _const.ANNOTATION_TYPES.PropertyBinding:
if ((typeof value === "undefined" ? "undefined" : _typeof(value)) === "object") {
return {
type: _const.ANNOTATION_TYPES.PropertyBinding,
nested: true,
value: compileProps(value, options)
};
}
return {
type: _const.ANNOTATION_TYPES.PropertyBinding,
nested: false,
value: (0, _parsers.parseExpressionString)(value)
value: {
type: _const.TYPES.Program,
body: [compilePropertyBindingValue(options, value, key)]
}
};

@@ -255,7 +293,7 @@ case _const.ANNOTATION_TYPES.TwoWayBinding:

*/
var compileComponent = function compileComponent(_ref) {
var compileComponent = function compileComponent(_ref3) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var type = _ref.type,
props = _objectWithoutProperties(_ref, ["type"]);
var type = _ref3.type,
props = _objectWithoutProperties(_ref3, ["type"]);

@@ -291,5 +329,5 @@ if (!type) {

var compile = function compile(_ref2, options) {
var schemaVersion = _ref2.schemaVersion,
rest = _objectWithoutProperties(_ref2, ["schemaVersion"]);
var compile = function compile(_ref4, options) {
var schemaVersion = _ref4.schemaVersion,
rest = _objectWithoutProperties(_ref4, ["schemaVersion"]);

@@ -296,0 +334,0 @@ if (!schemaVersion || !(0, _utils.isVersionCompatible)(schemaVersion)) {

@@ -12,55 +12,37 @@ "use strict";

var TYPES = exports.TYPES = {
Numeric: "Numeric",
String: "String",
Boolean: "Boolean",
Object: "Object",
Array: "Array",
Null: "Null",
RegExp: "RegExp",
Identifier: "Identifier",
Keyword: 'Keyword',
ArrayExpression: "ArrayExpression",
AssignExpression: "AssignExpression",
ObjectExpression: "ObjectExpression",
ObjectProperty: "ObjectProperty",
ArrayExpression: "ArrayExpression",
BinaryExpression: "BinaryExpression",
UnaryExpression: "UnaryExpression",
BlockStatement: "BlockStatement",
Boolean: "Boolean",
CallExpression: "CallExpression",
TemplateLiteral: "TemplateLiteral",
Components: "Components",
ConditionalExpression: "ConditionalExpression",
EventBinding: "EventBinding",
Identifier: "Identifier",
IfStatement: "IfStatement",
Keyword: "Keyword",
MemberExpression: "MemberExpression",
IfStatement: "IfStatement",
Components: "Components",
Null: "Null",
Numeric: "Numeric",
Object: "Object",
ObjectExpression: "ObjectExpression",
Operator: "Operator",
Program: "Program",
PropertyBinding: "PropertyBinding",
Punctuation: "Punctuation",
Raw: "Raw",
Program: 'Program',
BlockStatement: 'BlockStatement',
PropertyBinding: 'PropertyBinding',
EventBinding: 'EventBinding'
RegExp: "RegExp",
String: "String",
TemplateLiteral: "TemplateLiteral",
UnaryExpression: "UnaryExpression"
};
/**
those const not used in the app, leave here for reference
var PRIMITIVES = exports.PRIMITIVES = [TYPES.Numeric, TYPES.String, TYPES.Boolean, TYPES.Null];
export const PRIMITIVES = [
TYPES.Numeric,
TYPES.String,
TYPES.Boolean,
TYPES.Null
];
var OBJECTS = exports.OBJECTS = [TYPES.RegExp, TYPES.Identifier, TYPES.Component];
export const OBJECTS = [TYPES.RegExp, TYPES.Identifier, TYPES.Component];
var EXPRESSIONS = exports.EXPRESSIONS = [TYPES.ObjectExpression, TYPES.ArrayExpression, TYPES.BinaryExpression, TYPES.AssignExpression, TYPES.CallExpression, TYPES.UnaryExpression, TYPES.MemberExpression, TYPES.ConditionalExpression, TYPES.TemplateLiteral];
export const EXPRESSIONS = [
TYPES.ObjectExpression,
TYPES.ArrayExpression,
TYPES.BinaryExpression,
TYPES.AssignExpression,
TYPES.CallExpression,
TYPES.UnaryExpression,
TYPES.TemplateLiteral,
];
*/
var OPERATORS = exports.OPERATORS = {

@@ -89,5 +71,5 @@ Assign: "=",

var IF_KEYWORDS = exports.IF_KEYWORDS = {
If: 'if',
Else: 'else',
Then: 'then'
If: "if",
Else: "else",
Then: "then"
};

@@ -94,0 +76,0 @@ var KEYWORDS = exports.KEYWORDS = [].concat(BOOLEANS, _toConsumableArray(Object.values(IF_KEYWORDS)));

@@ -5,3 +5,3 @@ "use strict";

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };

@@ -12,14 +12,6 @@ var _TypeHandlers;

var _evaluateIdentifier = require("./evaluateIdentifier");
var _evaluateArrayExpression = require("./evaluateArrayExpression");
var _evaluateIdentifier2 = _interopRequireDefault(_evaluateIdentifier);
var _evaluateArrayExpression2 = _interopRequireDefault(_evaluateArrayExpression);
var _evaluateProgram = require("./evaluateProgram");
var _evaluateProgram2 = _interopRequireDefault(_evaluateProgram);
var _evaluateUnaryExpression = require("./evaluateUnaryExpression");
var _evaluateUnaryExpression2 = _interopRequireDefault(_evaluateUnaryExpression);
var _evaluateAssignExpression = require("./evaluateAssignExpression");

@@ -37,2 +29,18 @@

var _evaluateConditionalExpression = require("./evaluateConditionalExpression");
var _evaluateConditionalExpression2 = _interopRequireDefault(_evaluateConditionalExpression);
var _evaluateEventBindingExpression = require("./evaluateEventBindingExpression");
var _evaluateEventBindingExpression2 = _interopRequireDefault(_evaluateEventBindingExpression);
var _evaluateIdentifier = require("./evaluateIdentifier");
var _evaluateIdentifier2 = _interopRequireDefault(_evaluateIdentifier);
var _evaluateIfStatement = require("./evaluateIfStatement");
var _evaluateIfStatement2 = _interopRequireDefault(_evaluateIfStatement);
var _evaluateMemberObjectExpression = require("./evaluateMemberObjectExpression");

@@ -46,6 +54,10 @@

var _evaluateArrayExpression = require("./evaluateArrayExpression");
var _evaluateProgram = require("./evaluateProgram");
var _evaluateArrayExpression2 = _interopRequireDefault(_evaluateArrayExpression);
var _evaluateProgram2 = _interopRequireDefault(_evaluateProgram);
var _evaluatePropertyBindingExpression = require("./evaluatePropertyBindingExpression");
var _evaluatePropertyBindingExpression2 = _interopRequireDefault(_evaluatePropertyBindingExpression);
var _evaluateTemplateLiteral = require("./evaluateTemplateLiteral");

@@ -55,14 +67,6 @@

var _evaluateIfStatement = require("./evaluateIfStatement");
var _evaluateUnaryExpression = require("./evaluateUnaryExpression");
var _evaluateIfStatement2 = _interopRequireDefault(_evaluateIfStatement);
var _evaluateUnaryExpression2 = _interopRequireDefault(_evaluateUnaryExpression);
var _evaluateEventBindingExpression = require("./evaluateEventBindingExpression");
var _evaluateEventBindingExpression2 = _interopRequireDefault(_evaluateEventBindingExpression);
var _evaluatePropertyBindingExpression = require("./evaluatePropertyBindingExpression");
var _evaluatePropertyBindingExpression2 = _interopRequireDefault(_evaluatePropertyBindingExpression);
var _utils = require("../utils");

@@ -84,12 +88,16 @@

};
var toRegExp = function toRegExp(_ref2) {
var pattern = _ref2.pattern,
flags = _ref2.flags;
return new RegExp(pattern, flags);
var getStringifyValue = function getStringifyValue(_ref2) {
var value = _ref2.value;
return JSON.stringify(value);
};
var evaluateComponents = function evaluateComponents(expression, env) {
return env.evaluateComponents(expression);
var toRegExp = function toRegExp(_ref3) {
var pattern = _ref3.pattern,
flags = _ref3.flags;
return "new RegExp(" + JSON.stringify(pattern) + ", " + JSON.stringify(flags) + ")";
};
var evaluateComponents = function evaluateComponents(expression) {
return "return $$env.evaluateComponents(" + JSON.stringify(expression) + ")";
};
var TypeHandlers = (_TypeHandlers = {}, _defineProperty(_TypeHandlers, _const.TYPES.Numeric, getValue), _defineProperty(_TypeHandlers, _const.TYPES.String, getValue), _defineProperty(_TypeHandlers, _const.TYPES.Boolean, getValue), _defineProperty(_TypeHandlers, _const.TYPES.Null, getValue), _defineProperty(_TypeHandlers, _const.TYPES.Raw, getValue), _defineProperty(_TypeHandlers, _const.TYPES.RegExp, toRegExp), _defineProperty(_TypeHandlers, _const.TYPES.Identifier, _evaluateIdentifier2.default), _defineProperty(_TypeHandlers, _const.TYPES.UnaryExpression, _evaluateUnaryExpression2.default), _defineProperty(_TypeHandlers, _const.TYPES.AssignExpression, _evaluateAssignExpression2.default), _defineProperty(_TypeHandlers, _const.TYPES.BinaryExpression, _evaluateBinaryExpression2.default), _defineProperty(_TypeHandlers, _const.TYPES.CallExpression, _evaluateCallExpression2.default), _defineProperty(_TypeHandlers, _const.TYPES.Components, evaluateComponents), _defineProperty(_TypeHandlers, _const.TYPES.MemberExpression, _evaluateMemberObjectExpression2.default), _defineProperty(_TypeHandlers, _const.TYPES.ObjectExpression, _evaluateObjectExpression2.default), _defineProperty(_TypeHandlers, _const.TYPES.ArrayExpression, _evaluateArrayExpression2.default), _defineProperty(_TypeHandlers, _const.TYPES.TemplateLiteral, _evaluateTemplateLiteral2.default), _defineProperty(_TypeHandlers, _const.TYPES.Program, _evaluateProgram2.default), _defineProperty(_TypeHandlers, _const.TYPES.BlockStatement, _evaluateProgram2.default), _defineProperty(_TypeHandlers, _const.TYPES.IfStatement, _evaluateIfStatement2.default), _defineProperty(_TypeHandlers, _const.TYPES.EventBinding, _evaluateEventBindingExpression2.default), _defineProperty(_TypeHandlers, _const.TYPES.PropertyBinding, _evaluatePropertyBindingExpression2.default), _TypeHandlers);
var TypeHandlers = (_TypeHandlers = {}, _defineProperty(_TypeHandlers, _const.TYPES.ArrayExpression, _evaluateArrayExpression2.default), _defineProperty(_TypeHandlers, _const.TYPES.AssignExpression, _evaluateAssignExpression2.default), _defineProperty(_TypeHandlers, _const.TYPES.BinaryExpression, _evaluateBinaryExpression2.default), _defineProperty(_TypeHandlers, _const.TYPES.BlockStatement, _evaluateProgram2.default), _defineProperty(_TypeHandlers, _const.TYPES.Boolean, getValue), _defineProperty(_TypeHandlers, _const.TYPES.CallExpression, _evaluateCallExpression2.default), _defineProperty(_TypeHandlers, _const.TYPES.Components, evaluateComponents), _defineProperty(_TypeHandlers, _const.TYPES.ConditionalExpression, _evaluateConditionalExpression2.default), _defineProperty(_TypeHandlers, _const.TYPES.EventBinding, _evaluateEventBindingExpression2.default), _defineProperty(_TypeHandlers, _const.TYPES.Identifier, _evaluateIdentifier2.default), _defineProperty(_TypeHandlers, _const.TYPES.IfStatement, _evaluateIfStatement2.default), _defineProperty(_TypeHandlers, _const.TYPES.MemberExpression, _evaluateMemberObjectExpression2.default), _defineProperty(_TypeHandlers, _const.TYPES.Null, getValue), _defineProperty(_TypeHandlers, _const.TYPES.Numeric, getValue), _defineProperty(_TypeHandlers, _const.TYPES.ObjectExpression, _evaluateObjectExpression2.default), _defineProperty(_TypeHandlers, _const.TYPES.Program, _evaluateProgram2.default), _defineProperty(_TypeHandlers, _const.TYPES.PropertyBinding, _evaluatePropertyBindingExpression2.default), _defineProperty(_TypeHandlers, _const.TYPES.Raw, getStringifyValue), _defineProperty(_TypeHandlers, _const.TYPES.RegExp, toRegExp), _defineProperty(_TypeHandlers, _const.TYPES.String, getStringifyValue), _defineProperty(_TypeHandlers, _const.TYPES.TemplateLiteral, _evaluateTemplateLiteral2.default), _defineProperty(_TypeHandlers, _const.TYPES.UnaryExpression, _evaluateUnaryExpression2.default), _TypeHandlers);

@@ -99,15 +107,64 @@ /**

* @param {*} ast
* @param {Environment} environment
* @returns {*}
*/
var evaluate = function evaluate(_ref3, environment) {
var type = _ref3.type,
ast = _objectWithoutProperties(_ref3, ["type"]);
var evaluate = function evaluate(ast) {
var type = ast.type,
rest = _objectWithoutProperties(ast, ["type"]);
if ((0, _utils.hasKey)(TypeHandlers, type)) {
return TypeHandlers[type](ast, environment, evaluate);
return TypeHandlers[type](rest, evaluate);
}
throw new Error("Wrong type " + type + ", " + JSON.stringify(_extends({ type: type }, ast)));
throw new Error("Wrong type " + type + ", " + JSON.stringify(ast));
};
var match = function match(left, right) {
var regex = right instanceof RegExp ? right : new RegExp(right);
if (left == null) {
return regex.test("");
}
return regex.test(left);
};
var get = function get(obj, key) {
if (obj == null) {
return null;
}
var value = obj[key];
if (value == null) {
return null;
}
return value;
};
var toString = function toString(obj) {
switch (typeof obj === "undefined" ? "undefined" : _typeof(obj)) {
case "string":
return obj;
case "number":
if (Number.isNaN(obj)) {
return "";
}
return obj.toString();
default:
// all other types will be convert to '' for convenience
return "";
}
};
var cache = new WeakMap();
var getOrCreate = function getOrCreate(ast) {
var _ref4;
var cachedFn = cache.get(ast);
if (cachedFn) {
return cachedFn;
}
var context = [match, get, toString];
var newFn = (_ref4 = new Function("$$match", "$$get", "$$toString", "$$env", evaluate(ast))).bind.apply(_ref4, [null].concat(context));
cache.set(ast, newFn);
return newFn;
};
/**

@@ -123,5 +180,6 @@ * evaluateWithEnvironmentCheck

}
return evaluate(ast, environment);
return getOrCreate(ast)(environment);
};
exports.default = evaluateWithEnvironmentCheck;
"use strict";
exports.__esModule = true;
var evaluateArrayExpression = function evaluateArrayExpression(_ref, env, evaluate) {
var _path = require("path");
var evaluateArrayExpression = function evaluateArrayExpression(_ref, evaluate) {
var elements = _ref.elements;
return elements.map(function (element) {
return evaluate(element, env);
});
return "[" + elements.map(function (element) {
return evaluate(element);
}).join(",") + "]";
};
exports.default = evaluateArrayExpression;
"use strict";
exports.__esModule = true;
var evaluateAssignExpression = function evaluateAssignExpression(_ref, env, evaluate) {
var left = _ref.left,
var evaluateAssignExpression = function evaluateAssignExpression(_ref, evaluate) {
var name = _ref.left.name,
right = _ref.right;
return env.set(left.name, evaluate(right, env));
return "$$env.set(\"" + name + "\", " + evaluate(right) + ")";
};
exports.default = evaluateAssignExpression;
"use strict";
exports.__esModule = true;
exports.evaluateNonBranchableBinaryExpression = undefined;
var _OpMapping;
var _const = require("../const");
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
var handleRegex = function handleRegex(left, operator, right) {

@@ -16,3 +19,5 @@ var regex = right instanceof RegExp ? right : new RegExp(right);

var evaluateNonBranchableBinaryExpression = exports.evaluateNonBranchableBinaryExpression = function evaluateNonBranchableBinaryExpression(_ref) {
var OpMapping = (_OpMapping = {}, _defineProperty(_OpMapping, _const.OPERATORS.Or, "||"), _defineProperty(_OpMapping, _const.OPERATORS.And, "&&"), _defineProperty(_OpMapping, _const.OPERATORS.LessThan, "<"), _defineProperty(_OpMapping, _const.OPERATORS.LessThanOrEqualTo, "<="), _defineProperty(_OpMapping, _const.OPERATORS.GreaterThan, ">"), _defineProperty(_OpMapping, _const.OPERATORS.GreaterThanOrEqualTo, ">="), _defineProperty(_OpMapping, _const.OPERATORS.EqualTo, "==="), _defineProperty(_OpMapping, _const.OPERATORS.NotEqualTo, "!=="), _defineProperty(_OpMapping, _const.OPERATORS.Add, "+"), _defineProperty(_OpMapping, _const.OPERATORS.Subtract, "-"), _defineProperty(_OpMapping, _const.OPERATORS.Multiply, "*"), _defineProperty(_OpMapping, _const.OPERATORS.Divide, "/"), _defineProperty(_OpMapping, _const.OPERATORS.Remainder, "%"), _OpMapping);
var evaluateBinaryExpression = function evaluateBinaryExpression(_ref, evaluate) {
var operator = _ref.operator,

@@ -22,54 +27,15 @@ left = _ref.left,

switch (operator) {
case _const.OPERATORS.LessThan:
return left < right;
case _const.OPERATORS.LessThanOrEqualTo:
return left <= right;
case _const.OPERATORS.GreaterThan:
return left > right;
case _const.OPERATORS.GreaterThanOrEqualTo:
return left >= right;
case _const.OPERATORS.EqualTo:
return left === right;
case _const.OPERATORS.NotEqualTo:
return left !== right;
case _const.OPERATORS.Match:
return handleRegex(left, operator, right);
case _const.OPERATORS.Add:
return left + right;
case _const.OPERATORS.Subtract:
return left - right;
case _const.OPERATORS.Multiply:
return left * right;
case _const.OPERATORS.Divide:
return left / right;
case _const.OPERATORS.Remainder:
return left % right;
default:
throw new Error("unknown binary expression: " + { operator: operator, left: left, right: right });
var evaluatedLeft = evaluate(left);
var evaluatedRight = evaluate(right);
if (operator in OpMapping) {
return "(" + evaluatedLeft + OpMapping[operator] + evaluatedRight + ")";
}
};
if (operator === _const.OPERATORS.Match) {
return "$$match(" + evaluatedLeft + "," + evaluatedRight + ")";
}
var evaluateBinaryExpression = function evaluateBinaryExpression(_ref2, env, evaluate) {
var operator = _ref2.operator,
left = _ref2.left,
right = _ref2.right;
switch (operator) {
// specially handling for OR and AND
case _const.OPERATORS.Or:
// if left is true will ignore right
return evaluate(left, env) || evaluate(right, env);
case _const.OPERATORS.And:
// if left is false will ignore right
return evaluate(left, env) && evaluate(right, env);
default:
return evaluateNonBranchableBinaryExpression({
operator: operator,
left: evaluate(left, env),
right: evaluate(right, env)
});
}
throw new Error("unknown binary expression: " + { operator: operator, left: left, right: right });
};
exports.default = evaluateBinaryExpression;
"use strict";
exports.__esModule = true;
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
var evaluateCallExpression = function evaluateCallExpression(ast, env, evaluate) {
var callee = evaluate(ast.callee, env);
if (typeof callee !== "function") {
throw new Error("Wrong call expression, callee have to be function " + JSON.stringify(ast));
}
var evaluateCallExpression = function evaluateCallExpression(ast, evaluate) {
var callee = evaluate(ast.callee);
var args = ast.arguments.map(function (arg) {
return evaluate(arg, env);
return evaluate(arg);
});
return callee.apply(undefined, _toConsumableArray(args));
return callee + "(" + args.join(",") + ")";
};
exports.default = evaluateCallExpression;
"use strict";
exports.__esModule = true;
var evaluateEventBindingExpression = function evaluateEventBindingExpression(_ref, env, evaluate) {
var evaluateEventBindingExpression = function evaluateEventBindingExpression(_ref, evaluate) {
var value = _ref.value;
return evaluate(value, env);
return evaluate(value);
};
exports.default = evaluateEventBindingExpression;
"use strict";
exports.__esModule = true;
var evaluateIdentifier = function evaluateIdentifier(_ref, env) {
var evaluateIdentifier = function evaluateIdentifier(_ref) {
var name = _ref.name;
return env.get(name);
return "$$env.get(\"" + name + "\")";
};
exports.default = evaluateIdentifier;
"use strict";
exports.__esModule = true;
var evaluateIfStatement = function evaluateIfStatement(_ref, env, evaluate) {
var _const = require("../const");
var evaluateIfStatement = function evaluateIfStatement(_ref, evaluate) {
var test = _ref.test,

@@ -9,7 +12,8 @@ consequent = _ref.consequent,

if (evaluate(test, env)) {
return consequent ? evaluate(consequent, env) : null;
}
return alternate ? evaluate(alternate, env) : null;
var evaluatedTest = evaluate(test);
var evaluatedConsequent = consequent ? evaluate(consequent) : "";
var evaluatedAlternate = alternate ? evaluate(alternate) : "";
return "if(" + evaluatedTest + "){" + evaluatedConsequent + ";}else{" + evaluatedAlternate + ";}";
};
exports.default = evaluateIfStatement;
"use strict";
exports.__esModule = true;
var evaluateMemberObjectExpression = function evaluateMemberObjectExpression(ast, env, evaluate) {
var object = evaluate(ast.object, env);
var property = evaluate(ast.property, env);
var evaluateMemberObjectExpression = function evaluateMemberObjectExpression(ast, evaluate) {
var evaluatedObject = evaluate(ast.object);
var evaluatedProperty = evaluate(ast.property);
if (object == null) {
return null;
}
return object[property];
return "$$get(" + evaluatedObject + "," + evaluatedProperty + ")";
};
exports.default = evaluateMemberObjectExpression;

@@ -1,15 +0,14 @@

"use strict";
'use strict';
exports.__esModule = true;
var evaluateObjectExpression = function evaluateObjectExpression(_ref, env, evaluate) {
var evaluateObjectExpression = function evaluateObjectExpression(_ref, evaluate) {
var properties = _ref.properties;
return properties.reduce(function (result, _ref2) {
return '({' + properties.map(function (_ref2) {
var key = _ref2.key,
value = _ref2.value;
result[evaluate(key, env)] = evaluate(value, env);
return result;
}, {});
return '[' + evaluate(key) + ']:' + evaluate(value);
}).join(',') + '})';
};
exports.default = evaluateObjectExpression;
"use strict";
exports.__esModule = true;
var _const = require("../const");
// evaluate both block and program statement
var evaluateProgram = function evaluateProgram(_ref, env, evaluate) {
var evaluateProgram = function evaluateProgram(_ref, evaluate) {
var body = _ref.body;
if (body.length === 0) {
return null;
return "return null;";
}
var lstIndex = body.length - 1;
var evaluatedBody = body.map(function (ast) {
return evaluate(ast);
});
var js = "";
for (var i = 0; i < lstIndex; i++) {
evaluate(body[i], env);
js += evaluatedBody[i] + ";";
}
return evaluate(body[lstIndex], env); // always return the last value
if (body[lstIndex].type === _const.TYPES.IfStatement) {
js += "" + evaluatedBody[lstIndex];
} else {
js += "return " + evaluatedBody[lstIndex] + ";";
}
return js;
};
exports.default = evaluateProgram;

@@ -1,6 +0,6 @@

'use strict';
"use strict";
exports.__esModule = true;
var _mapValues = require('lodash/mapValues');
var _mapValues = require("lodash/mapValues");

@@ -11,13 +11,8 @@ var _mapValues2 = _interopRequireDefault(_mapValues);

var evaluatePropertyBindingExpression = function evaluatePropertyBindingExpression(_ref, env, evaluate) {
var evaluatePropertyBindingExpression = function evaluatePropertyBindingExpression(_ref, evaluate) {
var value = _ref.value;
if ('type' in value) {
return evaluate(value, env);
}
return (0, _mapValues2.default)(value, function (ast) {
return evaluate(ast, env);
});
return evaluate(value);
};
exports.default = evaluatePropertyBindingExpression;
"use strict";
exports.__esModule = true;
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var toString = function toString(obj) {
switch (typeof obj === "undefined" ? "undefined" : _typeof(obj)) {
case "string":
return obj;
case "number":
if (Number.isNaN(obj)) {
return "";
}
return obj.toString();
default:
// all other types will be convert to '' for convenience
return "";
}
};
var evaluateTemplateLiteral = function evaluateTemplateLiteral(_ref, env, evaluate) {
var evaluateTemplateLiteral = function evaluateTemplateLiteral(_ref, evaluate) {
var expressions = _ref.expressions,
quasis = _ref.quasis;
return quasis.reduce(function (retVal, _ref2, i) {
var value = _ref2.value;
return retVal + value + toString(i < expressions.length && evaluate(expressions[i], env));
}, "");
var evaluatedExpr = expressions.map(function (expr) {
return evaluate(expr);
});
return quasis.reduce(function (retVal, quasi, i) {
return i < expressions.length ? retVal + "+(" + evaluate(quasi) + ")+$$toString(" + evaluatedExpr[i] + ")" : retVal + "+(" + evaluate(quasi) + ")";
}, "''");
};
exports.default = evaluateTemplateLiteral;

@@ -7,13 +7,14 @@ "use strict";

var evaluateUnaryExpression = function evaluateUnaryExpression(_ref, env, evaluate) {
var evaluateUnaryExpression = function evaluateUnaryExpression(_ref, evaluate) {
var operator = _ref.operator,
argument = _ref.argument;
var evaluated = evaluate(argument);
switch (operator) {
case _const.OPERATORS.Not:
return !evaluate(argument, env);
return "(!(" + evaluated + "))";
case _const.OPERATORS.Add:
return +evaluate(argument, env);
return "(+(" + evaluated + "))";
case _const.OPERATORS.Subtract:
return -evaluate(argument, env);
return "(-(" + evaluated + "))";
default:

@@ -20,0 +21,0 @@ throw new Error("wrong UnaryExpression " + JSON.stringify({ operator: operator, argument: argument }));

"use strict";
exports.__esModule = true;
exports.parseTwoWayBindingString = exports.parseExpressionString = exports.parseTemplateString = undefined;
exports.parseTemplateString = exports.parseExpressionString = exports.parseBlockExpressionString = undefined;
var _flowRight = require("lodash/flowRight");
var _flowRight2 = _interopRequireDefault(_flowRight);
var _curryRight = require("lodash/curryRight");
var _curryRight2 = _interopRequireDefault(_curryRight);
var _parseExpressionTokenStream = require("./parseExpressionTokenStream");

@@ -12,6 +20,2 @@

var _flowRight = require("lodash/flowRight");
var _flowRight2 = _interopRequireDefault(_flowRight);
var _const = require("../const");

@@ -21,11 +25,7 @@

var parse = (0, _flowRight2.default)(_parseExpressionTokenStream2.default, _tokenizers.createExpressionTokenStream, _tokenizers.createInputStream);
/**
* parse template string
* @param templateString:string
* parse a block of expression string
* @param expressionString:string
*/
var parseTemplateString = exports.parseTemplateString = function parseTemplateString(templateString) {
return parse("`" + templateString + "`");
};
var parseBlockExpressionString = exports.parseBlockExpressionString = (0, _flowRight2.default)(_parseExpressionTokenStream2.default, _tokenizers.createExpressionTokenStream, _tokenizers.createInputStream);

@@ -36,17 +36,10 @@ /**

*/
var parseExpressionString = exports.parseExpressionString = parse;
var parseExpressionString = exports.parseExpressionString = (0, _flowRight2.default)((0, _curryRight2.default)(_parseExpressionTokenStream2.default, 2)(false), _tokenizers.createExpressionTokenStream, _tokenizers.createInputStream);
/**
* parse two way binding string
* Will throw error if TwoWayBinding is not a identifier.
* @param expressionString
* parse template string
* @param templateString:string
*/
var parseTwoWayBindingString = exports.parseTwoWayBindingString = function parseTwoWayBindingString(expressionString) {
var ast = parse(expressionString);
var id = ast.body[0];
if (id && id.type !== _const.TYPES.Identifier) {
throw new Error("data binding type have to be Identifier instead of " + ast.type + "(" + expressionString + ")");
}
return ast;
var parseTemplateString = exports.parseTemplateString = function parseTemplateString(templateString) {
return parseBlockExpressionString("`" + templateString + "`");
};

@@ -32,4 +32,7 @@ "use strict";

* @param tokenStream
* @param isBlock default to true, pass as block of code if true
*/
var parseExpressionTokenStream = function parseExpressionTokenStream(tokenStream) {
var isBlock = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
var isKeyword = function isKeyword(keyword) {

@@ -132,13 +135,22 @@ return utils.isKeyword(tokenStream.peek(), keyword);

var token = isUnary();
if (token) {
tokenStream.next();
return {
type: _const.TYPES.UnaryExpression,
operator: token.value,
argument: maybeUnary(expr)
};
if (!token) {
return expr();
}
return expr();
tokenStream.next();
var argument = maybeUnary(expr);
if (!isSimpleExpr(argument)) {
unexpected(token);
}
return {
type: _const.TYPES.UnaryExpression,
operator: token.value,
argument: argument
};
}
function isSimpleExpr(_ref) {
var type = _ref.type;
return _const.EXPRESSIONS.includes(type) || _const.PRIMITIVES.includes(type) || _const.OBJECTS.includes(type);
}
/**

@@ -154,21 +166,24 @@ * return binary expression if next token is an operator

var token = isOperator();
if (token) {
var rightOpPrec = _const.PRECEDENCE[token.value];
var isAssign = token.value === _const.OPERATORS.Assign;
if (rightOpPrec > leftOpPrec) {
if (isAssign && left.type !== _const.TYPES.Identifier) {
tokenStream.croak("You can only assign to an identifier \"" + JSON.stringify(left) + "\"");
}
tokenStream.next();
var right = maybeBinary(parseAtom(), rightOpPrec);
var binary = {
type: isAssign ? _const.TYPES.AssignExpression : _const.TYPES.BinaryExpression,
operator: token.value,
left: left,
right: right
};
return maybeBinary(binary, leftOpPrec);
}
if (!isSimpleExpr(left) || !token) {
return left;
}
return left;
var rightOpPrec = _const.PRECEDENCE[token.value];
var isAssign = token.value === _const.OPERATORS.Assign;
if (rightOpPrec <= leftOpPrec) {
return left;
}
if (isAssign && left.type !== _const.TYPES.Identifier) {
tokenStream.croak("You can only assign to an identifier \"" + JSON.stringify(left) + "\"");
}
tokenStream.next();
var right = maybeBinary(parseAtom(), rightOpPrec);
var binary = {
type: isAssign ? _const.TYPES.AssignExpression : _const.TYPES.BinaryExpression,
operator: token.value,
left: left,
right: right
};
return maybeBinary(binary, leftOpPrec);
}

@@ -284,6 +299,9 @@

* parse next expression
* @param {Boolean} allowBlock
* @returns {Expression}
*/
function parseExpression() {
return maybeBinary(parseAtom(), 0);
var allowBlock = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
return maybeBinary(parseAtom(allowBlock), 0);
}

@@ -293,9 +311,10 @@

* parse single expression, could be a call expression, an unary expression, an identifier or an expression inside a parentheses
* @param {Boolean} allowBlock
* @returns {Expression}
*/
function parseAtom() {
var skipUnaryCheck = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
var allowBlock = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
return maybeUnary(function () {
return maybeCallOrMember(parseSimpleAtom());
return maybeCallOrMember(parseSimpleAtom(allowBlock));
});

@@ -307,3 +326,3 @@ }

while (!tokenStream.eof()) {
body.push(parseExpression());
body.push(parseExpression(true));
if (tokenStream.eof()) {

@@ -327,7 +346,13 @@ // skip semi colon check if tokenStream is end;

_const.PUNCTUATIONS.SemiColon, // ;
parseExpression)
function () {
return parseExpression(true);
})
};
}
function parseIfStatement() {
/**
* @param {Boolean} allowBlock
*/
function parseIfStatement(allowBlock) {
debugger;
skipKeyword(_const.IF_KEYWORDS.If);

@@ -338,9 +363,13 @@ var test = parseExpression();

var alternate = null;
var isConditionalExpression = false;
if (isKeyword(_const.IF_KEYWORDS.Then)) {
skipKeyword(_const.IF_KEYWORDS.Then);
if (isPunctuation(_const.PUNCTUATIONS.Braces[0])) {
consequent = parseExpression();
isConditionalExpression = true;
} else {
if (allowBlock) {
consequent = parseBlockStatement();
} else {
consequent = parseExpression();
unexpected();
}

@@ -351,6 +380,12 @@ }

skipKeyword(_const.IF_KEYWORDS.Else);
if (isPunctuation(_const.PUNCTUATIONS.Braces[0])) {
alternate = parseBlockStatement();
if (isKeyword(_const.IF_KEYWORDS.If)) {
alternate = parseExpression(allowBlock);
} else if (isConditionalExpression) {
alternate = parseExpression();
} else {
alternate = parseExpression();
if (allowBlock) {
alternate = parseBlockStatement();
} else {
unexpected();
}
}

@@ -360,3 +395,3 @@ }

return {
type: _const.TYPES.IfStatement,
type: isConditionalExpression ? _const.TYPES.ConditionalExpression : _const.TYPES.IfStatement,
test: test,

@@ -370,5 +405,8 @@ consequent: consequent,

* parse a simple atom, e.g identifier, number, string, object, array, boolean, etc
* @param {Boolean} allowBlock
* @returns {Expression}
*/
function parseSimpleAtom() {
var allowBlock = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
if (isPunctuation(_const.PUNCTUATIONS.Parentheses[0])) {

@@ -398,3 +436,3 @@ // if it reads parentheses, then will parse the expression inside the parentheses

if (isKeyword(_const.IF_KEYWORDS.If)) {
return parseIfStatement();
return parseIfStatement(allowBlock);
}

@@ -416,4 +454,4 @@

return parseProgram();
return isBlock ? parseProgram() : parseExpression();
}; /* eslint-disable no-use-before-define */
exports.default = parseExpressionTokenStream;
{
"name": "@airtasker/form-schema-compiler",
"version": "0.1.1",
"version": "0.1.2",
"description": "a form schema compiler",

@@ -5,0 +5,0 @@ "main": "./lib/index.js",

@@ -16,4 +16,4 @@ import curryRight from "lodash/curryRight";

parseExpressionString,
parseTemplateString,
parseTwoWayBindingString
parseBlockExpressionString,
parseTemplateString
} from "./parsers";

@@ -113,3 +113,3 @@ import createTypeCompiler from "./typeCompiler";

super();
if (error.kind === 'ErrorPathTrace') {
if (error.kind === "ErrorPathTrace") {
this.path = `${key}.${error.path}`;

@@ -121,9 +121,53 @@ this.originMessage = error.originMessage;

}
this.kind = 'ErrorPathTrace';
this.message = `Found an error in ${this.path}. Error details: ${this.originMessage}`;
this.kind = "ErrorPathTrace";
this.message = `Found an error in ${this.path}. Error details: ${
this.originMessage
}`;
}
}
const tripeOutFromProgramInPropertyBinding = ast => {
if (ast.type !== TYPES.PropertyBinding || ast.value.type !== TYPES.Program) {
return ast;
}
return {
...ast,
value: ast.value.body[0]
};
};
/**
* compile PropertyBindingValue to ast expression
* @param {*} options
* @param {*} value
*/
const compilePropertyBindingValue = (options, value) => {
if (Array.isArray(value)) {
return {
type: TYPES.ArrayExpression,
elements: value.map(v =>
tripeOutFromProgramInPropertyBinding(
compilePropertyBindingValue(options, v)
)
)
};
} else if (typeof value === "object") {
return {
type: TYPES.ObjectExpression,
properties: Object.entries(compileProps(value, options)).map(
([key, value]) => ({
key: toValueObject(key),
value: tripeOutFromProgramInPropertyBinding(value)
})
)
};
} else if (typeof value === "string") {
return parseExpressionString(value);
}
throw new Error(`Unsupported type for property binding ${typeof value}`);
};
/**
* compile value to ast expression,

@@ -141,16 +185,11 @@ * examples see expression parsers and tests

type: ANNOTATION_TYPES.EventBinding,
value: parseExpressionString(value)
value: parseBlockExpressionString(value)
};
case ANNOTATION_TYPES.PropertyBinding:
if (typeof value === "object") {
return {
type: ANNOTATION_TYPES.PropertyBinding,
nested: true,
value: compileProps(value, options)
};
}
return {
type: ANNOTATION_TYPES.PropertyBinding,
nested: false,
value: parseExpressionString(value)
value: {
type: TYPES.Program,
body: [compilePropertyBindingValue(options, value, key)]
}
};

@@ -157,0 +196,0 @@ case ANNOTATION_TYPES.TwoWayBinding:

@@ -115,2 +115,8 @@ import { compileComponents, compileProps } from "./compileComponents";

},
"{nestedArray}": [
"n",
{
"{nestedNestedProp}": "n"
}
],
"(event)": "c",

@@ -122,30 +128,62 @@ "#template#": "a+d"

type: ANNOTATION_TYPES.PropertyBinding,
value: createProgram(createIdentifier("b")),
nested: false
value: createProgram(createIdentifier("b"))
},
nestedObject: {
type: ANNOTATION_TYPES.PropertyBinding,
nested: true,
value: {
nestedProp: {
type: ANNOTATION_TYPES.PropertyBinding,
nested: true,
value: {
nestedNestedProp: {
value: createProgram({
type: TYPES.ObjectExpression,
properties: [
{
key: createValue("nestedProp"),
value: {
type: ANNOTATION_TYPES.PropertyBinding,
value: createProgram(createIdentifier("n")),
nested: false
value: {
type: TYPES.ObjectExpression,
properties: [
{
key: createValue("nestedNestedProp"),
value: {
type: ANNOTATION_TYPES.PropertyBinding,
value: createIdentifier("n")
}
}
]
}
}
},
{
key: createValue("nestedComponent"),
value: {
type: TYPES.Components,
components: [
{
type: "Component"
}
]
}
}
},
nestedComponent: {
type: TYPES.Components,
components: [
{
type: "Component"
}
]
}
}
]
})
},
nestedArray: {
type: ANNOTATION_TYPES.PropertyBinding,
value: createProgram({
type: TYPES.ArrayExpression,
elements: [
createIdentifier("n"),
{
type: TYPES.ObjectExpression,
properties: [
{
key: createValue("nestedNestedProp"),
value: {
type: ANNOTATION_TYPES.PropertyBinding,
value: createIdentifier("n")
}
}
]
}
]
})
},
onEvent: {

@@ -152,0 +190,0 @@ type: ANNOTATION_TYPES.EventBinding,

export const TYPES = {
Numeric: "Numeric",
String: "String",
Boolean: "Boolean",
Object: "Object",
Array: "Array",
Null: "Null",
RegExp: "RegExp",
Identifier: "Identifier",
Keyword: 'Keyword',
ArrayExpression: "ArrayExpression",
AssignExpression: "AssignExpression",
ObjectExpression: "ObjectExpression",
ObjectProperty: "ObjectProperty",
ArrayExpression: "ArrayExpression",
BinaryExpression: "BinaryExpression",
UnaryExpression: "UnaryExpression",
BlockStatement: "BlockStatement",
Boolean: "Boolean",
CallExpression: "CallExpression",
TemplateLiteral: "TemplateLiteral",
Components: "Components",
ConditionalExpression: "ConditionalExpression",
EventBinding: "EventBinding",
Identifier: "Identifier",
IfStatement: "IfStatement",
Keyword: "Keyword",
MemberExpression: "MemberExpression",
IfStatement: "IfStatement",
Components: "Components",
Null: "Null",
Numeric: "Numeric",
Object: "Object",
ObjectExpression: "ObjectExpression",
Operator: "Operator",
Program: "Program",
PropertyBinding: "PropertyBinding",
Punctuation: "Punctuation",
Raw: "Raw",
Program: 'Program',
BlockStatement: 'BlockStatement',
PropertyBinding: 'PropertyBinding',
EventBinding: 'EventBinding',
RegExp: "RegExp",
String: "String",
TemplateLiteral: "TemplateLiteral",
UnaryExpression: "UnaryExpression"
};
/**
those const not used in the app, leave here for reference
export const PRIMITIVES = [

@@ -50,6 +47,7 @@ TYPES.Numeric,

TYPES.UnaryExpression,
TYPES.TemplateLiteral,
TYPES.MemberExpression,
TYPES.ConditionalExpression,
TYPES.TemplateLiteral, // special expression
];
*/

@@ -95,6 +93,6 @@ export const OPERATORS = {

export const IF_KEYWORDS = {
If: 'if',
Else: 'else',
Then: 'then'
}
If: "if",
Else: "else",
Then: "then"
};
export const KEYWORDS = [...BOOLEANS, ...Object.values(IF_KEYWORDS)];

@@ -109,3 +107,3 @@

BackQuote: "`",
SemiColon: ";",
SemiColon: ";"
};

@@ -112,0 +110,0 @@

import { TYPES } from "../const";
import evaluateIdentifier from "./evaluateIdentifier";
import evaluateProgram from "./evaluateProgram";
import evaluateUnaryExpression from "./evaluateUnaryExpression";
import evaluateArrayExpression from "./evaluateArrayExpression";
import evaluateAssignExpression from "./evaluateAssignExpression";
import evaluateBinaryExpression from "./evaluateBinaryExpression";
import evaluateCallExpression from "./evaluateCallExpression";
import evaluateConditionalExpression from "./evaluateConditionalExpression";
import evaluateEventBindingExpression from "./evaluateEventBindingExpression";
import evaluateIdentifier from "./evaluateIdentifier";
import evaluateIfStatement from "./evaluateIfStatement";
import evaluateMemberObjectExpression from "./evaluateMemberObjectExpression";
import evaluateObjectExpression from "./evaluateObjectExpression";
import evaluateArrayExpression from "./evaluateArrayExpression";
import evaluateProgram from "./evaluateProgram";
import evaluatePropertyBindingExpression from "./evaluatePropertyBindingExpression";
import evaluateTemplateLiteral from "./evaluateTemplateLiteral";
import evaluateIfStatement from "./evaluateIfStatement";
import evaluateEventBindingExpression from "./evaluateEventBindingExpression";
import evaluatePropertyBindingExpression from "./evaluatePropertyBindingExpression";
import evaluateUnaryExpression from "./evaluateUnaryExpression";
import { hasKey } from "../utils";

@@ -19,28 +20,31 @@ import Environment from "./Environment";

const getValue = ({ value }) => value;
const toRegExp = ({ pattern, flags }) => new RegExp(pattern, flags);
const evaluateComponents = (expression, env) =>
env.evaluateComponents(expression);
const getStringifyValue = ({ value }) => JSON.stringify(value);
const toRegExp = ({ pattern, flags }) =>
`new RegExp(${JSON.stringify(pattern)}, ${JSON.stringify(flags)})`;
const evaluateComponents = expression =>
`return $$env.evaluateComponents(${JSON.stringify(expression)})`;
const TypeHandlers = {
[TYPES.Numeric]: getValue,
[TYPES.String]: getValue,
[TYPES.Boolean]: getValue,
[TYPES.Null]: getValue,
[TYPES.Raw]: getValue,
[TYPES.RegExp]: toRegExp,
[TYPES.Identifier]: evaluateIdentifier,
[TYPES.UnaryExpression]: evaluateUnaryExpression,
[TYPES.ArrayExpression]: evaluateArrayExpression,
[TYPES.AssignExpression]: evaluateAssignExpression,
[TYPES.BinaryExpression]: evaluateBinaryExpression,
[TYPES.BlockStatement]: evaluateProgram,
[TYPES.Boolean]: getValue,
[TYPES.CallExpression]: evaluateCallExpression,
[TYPES.Components]: evaluateComponents,
[TYPES.ConditionalExpression]: evaluateConditionalExpression,
[TYPES.EventBinding]: evaluateEventBindingExpression,
[TYPES.Identifier]: evaluateIdentifier,
[TYPES.IfStatement]: evaluateIfStatement,
[TYPES.MemberExpression]: evaluateMemberObjectExpression,
[TYPES.Null]: getValue,
[TYPES.Numeric]: getValue,
[TYPES.ObjectExpression]: evaluateObjectExpression,
[TYPES.ArrayExpression]: evaluateArrayExpression,
[TYPES.TemplateLiteral]: evaluateTemplateLiteral,
[TYPES.Program]: evaluateProgram,
[TYPES.BlockStatement]: evaluateProgram,
[TYPES.IfStatement]: evaluateIfStatement,
[TYPES.EventBinding]: evaluateEventBindingExpression,
[TYPES.PropertyBinding]: evaluatePropertyBindingExpression,
[TYPES.Raw]: getStringifyValue,
[TYPES.RegExp]: toRegExp,
[TYPES.String]: getStringifyValue,
[TYPES.TemplateLiteral]: evaluateTemplateLiteral,
[TYPES.UnaryExpression]: evaluateUnaryExpression,
};

@@ -51,12 +55,67 @@

* @param {*} ast
* @param {Environment} environment
* @returns {*}
*/
const evaluate = ({ type, ...ast }, environment) => {
const evaluate = ast => {
const { type, ...rest } = ast;
if (hasKey(TypeHandlers, type)) {
return TypeHandlers[type](ast, environment, evaluate);
return TypeHandlers[type](rest, evaluate);
}
throw new Error(`Wrong type ${type}, ${JSON.stringify({ type, ...ast })}`);
throw new Error(`Wrong type ${type}, ${JSON.stringify(ast)}`);
};
const match = (left, right) => {
const regex = right instanceof RegExp ? right : new RegExp(right);
if (left == null) {
return regex.test("");
}
return regex.test(left);
};
const get = (obj, key) => {
if (obj == null) {
return null;
}
const value = obj[key];
if (value == null) {
return null;
}
return value;
};
const toString = obj => {
switch (typeof obj) {
case "string":
return obj;
case "number":
if (Number.isNaN(obj)) {
return "";
}
return obj.toString();
default:
// all other types will be convert to '' for convenience
return "";
}
};
const cache = new WeakMap();
const getOrCreate = ast => {
const cachedFn = cache.get(ast);
if (cachedFn) {
return cachedFn;
}
const context = [match, get, toString];
const newFn = new Function(
"$$match",
"$$get",
"$$toString",
"$$env",
evaluate(ast)
).bind(null, ...context);
cache.set(ast, newFn);
return newFn;
};
/**

@@ -72,5 +131,6 @@ * evaluateWithEnvironmentCheck

}
return evaluate(ast, environment);
return getOrCreate(ast)(environment);
};
export default evaluateWithEnvironmentCheck;
import { TYPES } from "../const";
import evaluate from "./evaluate";
import { parseExpressionString } from "../parsers";
import { parseBlockExpressionString } from "../parsers";
import {compileProps} from '../compileComponents';
import Environment from "./Environment";
const evaluateWithStringExpression = (str, env) => {
const ast = parseExpressionString(str);
const ast = parseBlockExpressionString(str);
return evaluate(ast, env);

@@ -206,7 +207,7 @@ };

env.set("test", jest.fn().mockReturnValue(false));
env.set("test2", jest.fn().mockReturnValue(false));
env.set("test2", jest.fn().mockReturnValue(true));
env.set("consequent", jest.fn());
env.set("alternate", jest.fn().mockReturnValue('foobar'));
env.set("consequent2", jest.fn().mockReturnValue('foobar'));
expect(
evaluateWithStringExpression('if test() then consequent() else if test2() else alternate()', env)
evaluateWithStringExpression('if test() then consequent() else if test2() then consequent2()', env)
).toBe('foobar');

@@ -216,3 +217,3 @@ expect(env.get("test")).toHaveBeenCalled();

expect(env.get("consequent")).not.toHaveBeenCalled();
expect(env.get("alternate")).toHaveBeenCalled();
expect(env.get("consequent2")).toHaveBeenCalled();
});

@@ -225,3 +226,3 @@

expect(
evaluateWithStringExpression('if test() then {call1(); call2();\n 123+110}', env)
evaluateWithStringExpression('if test() {call1(); call2();\n 123+110}', env)
).toBe(233);

@@ -233,2 +234,20 @@ expect(env.get("test")).toHaveBeenCalled();

});
it('should support property binding', () => {
const ast = compileProps({
'{obj}': {
'{prop1}': 'prop1'
},
'{array}': [
"prop2", {
'{prop1}': 'prop2'
}],
});
env.set("prop1", '1');
env.set("prop2", '2');
debugger;
expect(evaluate(ast.obj, env)).toEqual({prop1: '1'});
expect(evaluate(ast.array, env)).toEqual(['2', {prop1: '2'}]);
});
});

@@ -1,4 +0,6 @@

const evaluateArrayExpression = ({ elements }, env, evaluate) =>
elements.map(element => evaluate(element, env));
import { join } from "path";
const evaluateArrayExpression = ({ elements }, evaluate) =>
`[${elements.map(element => evaluate(element)).join(",")}]`;
export default evaluateArrayExpression;

@@ -1,3 +0,4 @@

const evaluateAssignExpression = ({ left, right }, env, evaluate) =>
env.set(left.name, evaluate(right, env));
const evaluateAssignExpression = ({ left: { name }, right }, evaluate) =>
`$$env.set("${name}", ${evaluate(right)})`;
export default evaluateAssignExpression;

@@ -11,53 +11,32 @@ import { OPERATORS } from "../const";

export const evaluateNonBranchableBinaryExpression = ({ operator, left, right }) => {
switch (operator) {
case OPERATORS.LessThan:
return left < right;
case OPERATORS.LessThanOrEqualTo:
return left <= right;
case OPERATORS.GreaterThan:
return left > right;
case OPERATORS.GreaterThanOrEqualTo:
return left >= right;
case OPERATORS.EqualTo:
return left === right;
case OPERATORS.NotEqualTo:
return left !== right;
case OPERATORS.Match:
return handleRegex(left, operator, right);
case OPERATORS.Add:
return left + right;
case OPERATORS.Subtract:
return left - right;
case OPERATORS.Multiply:
return left * right;
case OPERATORS.Divide:
return left / right;
case OPERATORS.Remainder:
return left % right;
default:
throw new Error(
`unknown binary expression: ${{ operator, left, right }}`
);
}
const OpMapping = {
[OPERATORS.Or]: "||",
[OPERATORS.And]: "&&",
[OPERATORS.LessThan]: "<",
[OPERATORS.LessThanOrEqualTo]: "<=",
[OPERATORS.GreaterThan]: ">",
[OPERATORS.GreaterThanOrEqualTo]: ">=",
[OPERATORS.EqualTo]: "===",
[OPERATORS.NotEqualTo]: "!==",
[OPERATORS.Add]: "+",
[OPERATORS.Subtract]: "-",
[OPERATORS.Multiply]: "*",
[OPERATORS.Divide]: "/",
[OPERATORS.Remainder]: "%"
};
const evaluateBinaryExpression = ({ operator, left, right }, env, evaluate) => {
switch (operator) {
// specially handling for OR and AND
case OPERATORS.Or:
// if left is true will ignore right
return evaluate(left, env) || evaluate(right, env);
case OPERATORS.And:
// if left is false will ignore right
return evaluate(left, env) && evaluate(right, env);
default:
return evaluateNonBranchableBinaryExpression({
operator,
left: evaluate(left, env),
right: evaluate(right, env)
});
const evaluateBinaryExpression = ({ operator, left, right }, evaluate) => {
const evaluatedLeft = evaluate(left);
const evaluatedRight = evaluate(right);
if (operator in OpMapping) {
return `(${evaluatedLeft}${OpMapping[operator]}${evaluatedRight})`;
}
if (operator === OPERATORS.Match) {
return `$$match(${evaluatedLeft},${evaluatedRight})`;
}
throw new Error(`unknown binary expression: ${{ operator, left, right }}`);
};
export default evaluateBinaryExpression;

@@ -1,16 +0,8 @@

const evaluateCallExpression = (ast, env, evaluate) => {
const callee = evaluate(ast.callee, env);
if (typeof callee !== "function") {
throw new Error(
`Wrong call expression, callee have to be function ${JSON.stringify(
ast
)}`
);
}
const evaluateCallExpression = (ast, evaluate) => {
const callee = evaluate(ast.callee);
const args = ast.arguments.map(arg => evaluate(arg));
const args = ast.arguments.map(arg => evaluate(arg, env));
return callee(...args);
return `${callee}(${args.join(",")})`;
};
export default evaluateCallExpression;

@@ -1,4 +0,6 @@

const evaluateEventBindingExpression = ({ value }, env, evaluate) =>
evaluate(value, env);
const evaluateEventBindingExpression = ({ value }, evaluate) => {
return evaluate(value);
}
export default evaluateEventBindingExpression;

@@ -1,2 +0,2 @@

const evaluateIdentifier = ({ name }, env) => env.get(name);
const evaluateIdentifier = ({ name }) => `$$env.get("${name}")`;
export default evaluateIdentifier;

@@ -1,11 +0,10 @@

const evaluateIfStatement = (
{ test, consequent, alternate },
env,
evaluate
) => {
if (evaluate(test, env)) {
return consequent ? evaluate(consequent, env) : null;
}
return alternate ? evaluate(alternate, env) : null;
import { TYPES } from "../const";
const evaluateIfStatement = ({ test, consequent, alternate }, evaluate) => {
const evaluatedTest = evaluate(test);
const evaluatedConsequent = consequent ? evaluate(consequent) : "";
const evaluatedAlternate = alternate ? evaluate(alternate) : "";
return `if(${evaluatedTest}){${evaluatedConsequent};}else{${evaluatedAlternate};}`;
};
export default evaluateIfStatement;

@@ -1,12 +0,8 @@

const evaluateMemberObjectExpression = (ast, env, evaluate) => {
const object = evaluate(ast.object, env);
const property = evaluate(ast.property, env);
const evaluateMemberObjectExpression = (ast, evaluate) => {
const evaluatedObject = evaluate(ast.object);
const evaluatedProperty = evaluate(ast.property);
if (object == null) {
return null;
}
return object[property];
return `$$get(${evaluatedObject},${evaluatedProperty})`;
};
export default evaluateMemberObjectExpression;

@@ -1,7 +0,7 @@

const evaluateObjectExpression = ({ properties }, env, evaluate) =>
properties.reduce((result, { key, value }) => {
result[evaluate(key, env)] = evaluate(value, env);
return result;
}, {});
const evaluateObjectExpression = ({ properties }, evaluate) => {
return `({${properties.map(
({ key, value }) => `[${evaluate(key)}]:${evaluate(value)}`
).join(',')}})`;
};
export default evaluateObjectExpression;

@@ -0,13 +1,26 @@

import { TYPES } from "../const";
// evaluate both block and program statement
const evaluateProgram = ({ body }, env, evaluate) => {
const evaluateProgram = ({ body }, evaluate) => {
if (body.length === 0) {
return null;
return "return null;";
}
const lstIndex = body.length - 1;
const evaluatedBody = body.map(ast => evaluate(ast));
let js = "";
for (let i = 0; i < lstIndex; i++) {
evaluate(body[i], env);
js += `${evaluatedBody[i]};`;
}
return evaluate(body[lstIndex], env); // always return the last value
if (body[lstIndex].type === TYPES.IfStatement) {
js += `${evaluatedBody[lstIndex]}`;
} else {
js += `return ${evaluatedBody[lstIndex]};`;
}
return js;
};
export default evaluateProgram;

@@ -1,10 +0,7 @@

import mapValues from 'lodash/mapValues';
import mapValues from "lodash/mapValues";
const evaluatePropertyBindingExpression = ({ value }, env, evaluate) => {
if ('type' in value) {
return evaluate(value, env);
}
return mapValues(value, (ast) => evaluate(ast, env));
}
const evaluatePropertyBindingExpression = ({ value }, evaluate) => {
return evaluate(value);
};
export default evaluatePropertyBindingExpression;

@@ -1,25 +0,11 @@

const toString = obj => {
switch (typeof obj) {
case "string":
return obj;
case "number":
if (Number.isNaN(obj)) {
return "";
}
return obj.toString();
default:
// all other types will be convert to '' for convenience
return "";
}
const evaluateTemplateLiteral = ({ expressions, quasis }, evaluate) => {
const evaluatedExpr = expressions.map(expr => evaluate(expr));
return quasis.reduce(
(retVal, quasi, i) =>
i < expressions.length
? `${retVal}+(${evaluate(quasi)})+$$toString(${evaluatedExpr[i]})`
: `${retVal}+(${evaluate(quasi)})`,
"''"
);
};
const evaluateTemplateLiteral = ({ expressions, quasis }, env, evaluate) =>
quasis.reduce(
(retVal, { value }, i) =>
retVal +
value +
toString(i < expressions.length && evaluate(expressions[i], env)),
""
);
export default evaluateTemplateLiteral;
import { OPERATORS } from "../const";
const evaluateUnaryExpression = ({ operator, argument }, env, evaluate) => {
const evaluateUnaryExpression = ({ operator, argument }, evaluate) => {
const evaluated = evaluate(argument);
switch (operator) {
case OPERATORS.Not:
return !evaluate(argument, env);
return `(!(${evaluated}))`;
case OPERATORS.Add:
return +evaluate(argument, env);
return `(+(${evaluated}))`;
case OPERATORS.Subtract:
return -evaluate(argument, env);
return `(-(${evaluated}))`;
default:

@@ -12,0 +13,0 @@ throw new Error(

@@ -0,7 +1,13 @@

import flowRight from "lodash/flowRight";
import curryRight from "lodash/curryRight";
import parseExpressionTokenStream from "./parseExpressionTokenStream";
import { createExpressionTokenStream, createInputStream } from "../tokenizers";
import flowRight from "lodash/flowRight";
import { TYPES } from "../const";
const parse = flowRight(
/**
* parse a block of expression string
* @param expressionString:string
*/
export const parseBlockExpressionString = flowRight(
parseExpressionTokenStream,

@@ -13,32 +19,18 @@ createExpressionTokenStream,

/**
* parse template string
* @param templateString:string
*/
export const parseTemplateString = templateString => {
return parse(`\`${templateString}\``);
}
/**
* parse expression string
* @param expressionString:string
*/
export const parseExpressionString = parse;
export const parseExpressionString = flowRight(
curryRight(parseExpressionTokenStream, 2)(false),
createExpressionTokenStream,
createInputStream
);
/**
* parse two way binding string
* Will throw error if TwoWayBinding is not a identifier.
* @param expressionString
* parse template string
* @param templateString:string
*/
export const parseTwoWayBindingString = expressionString => {
const ast = parse(expressionString);
const id = ast.body[0];
if (id && id.type !== TYPES.Identifier) {
throw new Error(
`data binding type have to be Identifier instead of ${
ast.type
}(${expressionString})`
);
}
export const parseTemplateString = templateString => {
return parseBlockExpressionString(`\`${templateString}\``);
}
return ast;
};

@@ -8,3 +8,6 @@ /* eslint-disable no-use-before-define */

TYPES,
IF_KEYWORDS
IF_KEYWORDS,
PRIMITIVES,
OBJECTS,
EXPRESSIONS
} from "../const";

@@ -26,4 +29,5 @@ import * as utils from "./utils";

* @param tokenStream
* @param isBlock default to true, pass as block of code if true
*/
const parseExpressionTokenStream = tokenStream => {
const parseExpressionTokenStream = (tokenStream, isBlock = true) => {
const isKeyword = keyword => utils.isKeyword(tokenStream.peek(), keyword);

@@ -131,13 +135,20 @@ const isPunctuation = paren => utils.isPunctuation(tokenStream.peek(), paren);

const token = isUnary();
if (token) {
tokenStream.next();
return {
type: TYPES.UnaryExpression,
operator: token.value,
argument: maybeUnary(expr)
};
if (!token) {
return expr();
}
return expr();
tokenStream.next();
const argument = maybeUnary(expr);
if (!isSimpleExpr(argument)) {
unexpected(token);
}
return {
type: TYPES.UnaryExpression,
operator: token.value,
argument
};
}
function isSimpleExpr({type}) {
return EXPRESSIONS.includes(type) || PRIMITIVES.includes(type) || OBJECTS.includes(type);
}
/**

@@ -151,23 +162,26 @@ * return binary expression if next token is an operator

const token = isOperator();
if (token) {
const rightOpPrec = PRECEDENCE[token.value];
const isAssign = token.value === OPERATORS.Assign;
if (rightOpPrec > leftOpPrec) {
if (isAssign && left.type !== TYPES.Identifier) {
tokenStream.croak(
`You can only assign to an identifier "${JSON.stringify(left)}"`
);
}
tokenStream.next();
const right = maybeBinary(parseAtom(), rightOpPrec);
const binary = {
type: isAssign ? TYPES.AssignExpression : TYPES.BinaryExpression,
operator: token.value,
left,
right
};
return maybeBinary(binary, leftOpPrec);
}
if (!isSimpleExpr(left) || !token) {
return left;
}
return left;
const rightOpPrec = PRECEDENCE[token.value];
const isAssign = token.value === OPERATORS.Assign;
if (rightOpPrec <= leftOpPrec) {
return left;
}
if (isAssign && left.type !== TYPES.Identifier) {
tokenStream.croak(
`You can only assign to an identifier "${JSON.stringify(left)}"`
);
}
tokenStream.next();
const right = maybeBinary(parseAtom(), rightOpPrec);
const binary = {
type: isAssign ? TYPES.AssignExpression : TYPES.BinaryExpression,
operator: token.value,
left,
right
};
return maybeBinary(binary, leftOpPrec);
}

@@ -291,6 +305,7 @@

* parse next expression
* @param {Boolean} allowBlock
* @returns {Expression}
*/
function parseExpression() {
return maybeBinary(parseAtom(), 0);
function parseExpression(allowBlock = false) {
return maybeBinary(parseAtom(allowBlock), 0);
}

@@ -300,6 +315,7 @@

* parse single expression, could be a call expression, an unary expression, an identifier or an expression inside a parentheses
* @param {Boolean} allowBlock
* @returns {Expression}
*/
function parseAtom(skipUnaryCheck = false) {
return maybeUnary(() => maybeCallOrMember(parseSimpleAtom()));
function parseAtom(allowBlock = false) {
return maybeUnary(() => maybeCallOrMember(parseSimpleAtom(allowBlock)));
}

@@ -310,3 +326,3 @@

while (!tokenStream.eof()) {
body.push(parseExpression());
body.push(parseExpression(true));
if (tokenStream.eof()) {

@@ -331,3 +347,3 @@ // skip semi colon check if tokenStream is end;

PUNCTUATIONS.SemiColon, // ;
parseExpression
() => parseExpression(true)
)

@@ -337,3 +353,7 @@ };

function parseIfStatement() {
/**
* @param {Boolean} allowBlock
*/
function parseIfStatement(allowBlock) {
debugger;
skipKeyword(IF_KEYWORDS.If);

@@ -344,9 +364,13 @@ const test = parseExpression();

let alternate = null;
let isConditionalExpression = false;
if (isKeyword(IF_KEYWORDS.Then)) {
skipKeyword(IF_KEYWORDS.Then);
if (isPunctuation(PUNCTUATIONS.Braces[0])) {
consequent = parseExpression();
isConditionalExpression = true;
} else {
if (allowBlock) {
consequent = parseBlockStatement();
} else {
consequent = parseExpression();
unexpected();
}

@@ -357,6 +381,12 @@ }

skipKeyword(IF_KEYWORDS.Else);
if (isPunctuation(PUNCTUATIONS.Braces[0])) {
alternate = parseBlockStatement();
if (isKeyword(IF_KEYWORDS.If)) {
alternate = parseExpression(allowBlock);
} else if (isConditionalExpression) {
alternate = parseExpression();
} else {
alternate = parseExpression();
if (allowBlock) {
alternate = parseBlockStatement();
} else {
unexpected();
}
}

@@ -366,3 +396,3 @@ }

return {
type: TYPES.IfStatement,
type: isConditionalExpression ? TYPES.ConditionalExpression : TYPES.IfStatement,
test,

@@ -376,5 +406,6 @@ consequent,

* parse a simple atom, e.g identifier, number, string, object, array, boolean, etc
* @param {Boolean} allowBlock
* @returns {Expression}
*/
function parseSimpleAtom() {
function parseSimpleAtom(allowBlock = false) {
if (isPunctuation(PUNCTUATIONS.Parentheses[0])) {

@@ -404,3 +435,3 @@ // if it reads parentheses, then will parse the expression inside the parentheses

if (isKeyword(IF_KEYWORDS.If)) {
return parseIfStatement();
return parseIfStatement(allowBlock);
}

@@ -422,5 +453,5 @@

return parseProgram();
return isBlock ? parseProgram() : parseExpression();
};
export default parseExpressionTokenStream;

@@ -562,8 +562,8 @@ import createInputStream from "../tokenizers/createInputStream";

describe("if statement", () => {
it("should parse if statement with only else", () => {
const ast = parse("if true and true else hello()");
describe("if statement & conditional expression", () => {
it("should parse conditional expression with only then", () => {
const ast = parse("if true and true then hello()");
expect(ast).toEqual(
createProgram({
type: TYPES.IfStatement,
type: TYPES.ConditionalExpression,
test: {

@@ -575,4 +575,4 @@ type: TYPES.BinaryExpression,

},
consequent: null,
alternate: createCallExpression(createIdentifier("hello"))
alternate: null,
consequent: createCallExpression(createIdentifier("hello"))
})

@@ -582,7 +582,7 @@ );

it("should parse if statement with only then", () => {
const ast = parse("if true and true then hello()");
it("should parse simple conditional expression", () => {
const ast = parse("if true and true then 1+2 else hello()");
expect(ast).toEqual(
createProgram({
type: TYPES.IfStatement,
type: TYPES.ConditionalExpression,
test: {

@@ -594,4 +594,9 @@ type: TYPES.BinaryExpression,

},
alternate: null,
consequent: createCallExpression(createIdentifier("hello"))
consequent: {
type: TYPES.BinaryExpression,
operator: OPERATORS.Add,
left: createValue(1),
right: createValue(2)
},
alternate: createCallExpression(createIdentifier("hello"))
})

@@ -601,7 +606,7 @@ );

it("should parse simple if statement", () => {
const ast = parse("if true and true then 1+2 else hello()");
it("should parse chained conditional expression", () => {
const ast = parse("if true and true then 1+2 else if false then hello()");
expect(ast).toEqual(
createProgram({
type: TYPES.IfStatement,
type: TYPES.ConditionalExpression,
test: {

@@ -619,4 +624,8 @@ type: TYPES.BinaryExpression,

},
alternate: createCallExpression(createIdentifier("hello"))
alternate: {
type: TYPES.ConditionalExpression,
test: createValue(false),
consequent: createCallExpression(createIdentifier("hello")),
alternate: null
}
})

@@ -626,5 +635,6 @@ );

it("should parse if statement with blocks", () => {
const ast = parse(
"if true and true then {1+2;} else {hello(); hello2();}"
"if true and true {1+2;} else {hello(); hello2();}"
);

@@ -660,14 +670,22 @@ expect(ast).toEqual(

it("should parse chained if statements ", () => {
const ast = parse("if true then 1 else if false then {2}");
it("should parse chained if statement with blocks", () => {
const ast = parse(`
if 1 {
2;
} else if 3 {
4;
} else {
5;
}
`);
expect(ast).toEqual(
createProgram({
type: TYPES.IfStatement,
test: createValue(true),
consequent: createValue(1),
test: createValue(1),
consequent: createProgram([createValue(2)], false),
alternate: {
type: TYPES.IfStatement,
test: createValue(false),
consequent: createProgram(createValue(2), false),
alternate: null
test: createValue(3),
consequent: createProgram([createValue(4)], false),
alternate: createProgram([createValue(5)], false)
}

@@ -674,0 +692,0 @@ })

SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc