@halleyassist/rule-templater 0.0.18 → 0.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/rule-templater.browser.js +262 -39
- package/package.json +1 -1
- package/src/GeneralTemplate.js +6 -6
- package/src/RuleTemplate.ebnf.js +0 -9
- package/src/RuleTemplate.js +87 -13
- package/src/RuleTemplate.production.ebnf.js +1 -1
- package/src/RuleTemplate.production.js +87 -13
- package/src/RuleTemplater.production.js +69 -5
- package/src/VariableValidate.js +4 -4
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.RuleTemplate = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
|
|
2
|
-
module.exports=[{"name":"statement_main","bnf":[["statement","EOF"]]},{"name":"logical_operator","bnf":[["AND"],["OR"]]},{"name":"%statement[2]","bnf":[["logical_operator","expression"]],"fragment":true},{"name":"statement","bnf":[["expression","%statement[2]*"]]},{"name":"expression","bnf":[["not_expression"],["standard_expression"],["parenthesis_expression"]]},{"name":"parenthesis_expression","bnf":[["BEGIN_PARENTHESIS","WS*","statement","WS*","END_PARENTHESIS"]]},{"name":"%not_expression[2]","bnf":[["result"],["parenthesis_expression"]],"fragment":true},{"name":"not_expression","bnf":[["NOT","%not_expression[2]"]]},{"name":"%standard_expression[2][1]","bnf":[["WS*","eq_approx"]],"fragment":true},{"name":"%standard_expression[2][2]","bnf":[["WS*","basic_rhs"]],"fragment":true},{"name":"%standard_expression[2][3][1]","bnf":[["WS+","IS"]],"fragment":true},{"name":"%standard_expression[2][3]","bnf":[["%standard_expression[2][3][1]?","WS+","between"]],"fragment":true},{"name":"%standard_expression[2][4]","bnf":[["WS+","in_expr"]],"fragment":true},{"name":"%standard_expression[2]","bnf":[["%standard_expression[2][1]"],["%standard_expression[2][2]"],["%standard_expression[2][3]"],["%standard_expression[2][4]"]],"fragment":true},{"name":"standard_expression","bnf":[["result","%standard_expression[2]?"]]},{"name":"basic_rhs","bnf":[["operator","WS*","result"]]},{"name":"eq_approx","bnf":[["eq_operator","WS*","\"~\"","WS*","result"]]},{"name":"PLUS","bnf":[["\"+\""]]},{"name":"MINUS","bnf":[["\"-\""]]},{"name":"MULTIPLY","bnf":[["\"*\""]]},{"name":"DIVIDE","bnf":[["\"/\""]]},{"name":"MODULUS","bnf":[["\"%\""]]},{"name":"DEFAULT_VAL","bnf":[["\"??\""]]},{"name":"arithmetic_operator","bnf":[["PLUS"],["MINUS"],["MULTIPLY"],["DIVIDE"],["MODULUS"],["DEFAULT_VAL"]]},{"name":"number_atom","bnf":[["number"]]},{"name":"number_time_atom","bnf":[["number_time"]]},{"name":"tod_atom","bnf":[["number_tod"]]},{"name":"dow_atom","bnf":[["dow"]]},{"name":"arithmetic_operand","bnf":[["fcall"],["number_time_atom"],["number_atom"]]},{"name":"%arithmetic_result[5]","bnf":[["arithmetic_result"],["arithmetic_operand"]],"fragment":true},{"name":"arithmetic_result","bnf":[["arithmetic_operand","WS*","arithmetic_operator","WS*","%arithmetic_result[5]"]]},{"name":"simple_result","bnf":[["fcall"],["value"]]},{"name":"result","bnf":[["arithmetic_result"],["simple_result"]]},{"name":"value_atom","bnf":[["false"],["true"],["array"],["time_period"],["number_time_atom"],["number_atom"],["tod_atom"],["string"]]},{"name":"value","bnf":[["value_atom"]]},{"name":"BEGIN_ARRAY","bnf":[["WS*",/\x5B/,"WS*"]]},{"name":"BEGIN_OBJECT","bnf":[["WS*",/\x7B/,"WS*"]]},{"name":"END_ARRAY","bnf":[["WS*",/\x5D/,"WS*"]]},{"name":"END_OBJECT","bnf":[["WS*",/\x7D/,"WS*"]]},{"name":"NAME_SEPARATOR","bnf":[["WS*",/\x3A/,"WS*"]]},{"name":"VALUE_SEPARATOR","bnf":[["WS*",/\x2C/,"WS*"]]},{"name":"WS","bnf":[[/[\x20\x09\x0A\x0D]/]]},{"name":"operator","bnf":[["GTE"],["LTE"],["GT"],["LT"],["EQ"],["NEQ"]]},{"name":"eq_operator","bnf":[["EQ"],["NEQ"]]},{"name":"BEGIN_ARGUMENT","bnf":[["\"(\""]]},{"name":"END_ARGUMENT","bnf":[["\")\""]]},{"name":"BEGIN_PARENTHESIS","bnf":[["\"(\""]]},{"name":"END_PARENTHESIS","bnf":[["\")\""]]},{"name":"BEGIN_IN","bnf":[[/[Ii]/,/[Nn]/]]},{"name":"in_expr","bnf":[["BEGIN_IN","WS*","BEGIN_PARENTHESIS","WS*","arguments","END_PARENTHESIS"]]},{"name":"argument","bnf":[["statement","WS*"]]},{"name":"%arguments[2]","bnf":[["WS*","\",\"","WS*","argument"]],"fragment":true},{"name":"arguments","bnf":[["argument","%arguments[2]*"]]},{"name":"%fname[1]","bnf":[[/[A-Za-z0-9]/]]},{"name":"fname","bnf":[["%fname[1]+"]]},{"name":"fcall","bnf":[["fname","WS*","BEGIN_ARGUMENT","WS*","arguments?","END_ARGUMENT"]]},{"name":"%between_dash_or_and[1]","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"%between_dash_or_and[2]","bnf":[["WS*",/\-/,"WS*"]],"fragment":true},{"name":"between_dash_or_and","bnf":[["%between_dash_or_and[1]"],["%between_dash_or_and[2]"]]},{"name":"between_number_inner","bnf":[["number_atom"],["number_time_atom"]]},{"name":"between_number","bnf":[["between_number_inner","between_dash_or_and","between_number_inner"]]},{"name":"between_number_time_inner","bnf":[["number_time_atom"]]},{"name":"%between_number_time[4]","bnf":[["WS+","dow_range"]],"fragment":true},{"name":"between_number_time","bnf":[["between_number_time_inner","between_dash_or_and","between_number_time_inner","%between_number_time[4]?"]]},{"name":"between_tod_inner","bnf":[["tod_atom"]]},{"name":"%between_tod[2]","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"%between_tod[4]","bnf":[["WS+","dow_range"]],"fragment":true},{"name":"between_tod","bnf":[["between_tod_inner","%between_tod[2]","between_tod_inner","%between_tod[4]?"]]},{"name":"%between[3]","bnf":[["between_number"],["between_tod"]],"fragment":true},{"name":"between","bnf":[[/[Bb]/,/[Ee]/,/[Tt]/,/[Ww]/,/[Ee]/,/[Ee]/,/[Nn]/,"WS+","%between[3]"]]},{"name":"dow","bnf":[[/[Mm]/,/[Oo]/,/[Nn]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Mm]/,/[Oo]/,/[Nn]/],[/[Tt]/,/[Uu]/,/[Ee]/,/[Ss]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Tt]/,/[Uu]/,/[Ee]/],[/[Ww]/,/[Ee]/,/[Dd]/,/[Nn]/,/[Ee]/,/[Ss]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ww]/,/[Ee]/,/[Dd]/],[/[Tt]/,/[Hh]/,/[Uu]/,/[Rr]/,/[Ss]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Tt]/,/[Hh]/,/[Uu]/],[/[Tt]/,/[Hh]/,/[Uu]/,/[Rr]/],[/[Ff]/,/[Rr]/,/[Ii]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ff]/,/[Rr]/,/[Ii]/],[/[Ss]/,/[Aa]/,/[Tt]/,/[Uu]/,/[Rr]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ss]/,/[Aa]/,/[Tt]/],[/[Ss]/,/[Uu]/,/[Nn]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ss]/,/[Uu]/,/[Nn]/]]},{"name":"dow_range_inner","bnf":[["dow_atom"]]},{"name":"%dow_range[4]","bnf":[["WS+",/[Tt]/,/[Oo]/,"WS+","dow_range_inner"]],"fragment":true},{"name":"dow_range","bnf":[[/[Oo]/,/[Nn]/,"WS+","dow_range_inner","%dow_range[4]?"]]},{"name":"between_time_only","bnf":[[/[Bb]/,/[Ee]/,/[Tt]/,/[Ww]/,/[Ee]/,/[Ee]/,/[Nn]/,"WS+","between_number_time"]]},{"name":"between_tod_only","bnf":[[/[Bb]/,/[Ee]/,/[Tt]/,/[Ww]/,/[Ee]/,/[Ee]/,/[Nn]/,"WS+","between_tod"]]},{"name":"between_time_only_atom","bnf":[["between_time_only"]]},{"name":"between_tod_only_atom","bnf":[["between_tod_only"]]},{"name":"%AND[1]","bnf":[["WS*",/&/,/&/,"WS*"]],"fragment":true},{"name":"%AND[2]","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"AND","bnf":[["%AND[1]"],["%AND[2]"]]},{"name":"%OR[1]","bnf":[["WS*",/\|/,/\|/,"WS*"]],"fragment":true},{"name":"%OR[2]","bnf":[["WS+",/[Oo]/,/[Rr]/,"WS+"]],"fragment":true},{"name":"OR","bnf":[["%OR[1]"],["%OR[2]"]]},{"name":"AGO","bnf":[[/[Aa]/,/[Gg]/,/[Oo]/]]},{"name":"GT","bnf":[["\">\""]]},{"name":"LT","bnf":[["\"<\""]]},{"name":"GTE","bnf":[["\">=\""]]},{"name":"LTE","bnf":[["\"<=\""]]},{"name":"IS","bnf":[[/[Ii]/,/[Ss]/]]},{"name":"EQ","bnf":[["\"==\""],["\"=\""]]},{"name":"NEQ","bnf":[["\"!=\""]]},{"name":"%NOT[1]","bnf":[[/!/,"WS*"]],"fragment":true},{"name":"%NOT[2]","bnf":[[/[Nn]/,/[Oo]/,/[Tt]/,"WS+"]],"fragment":true},{"name":"NOT","bnf":[["%NOT[1]"],["%NOT[2]"]]},{"name":"false","bnf":[[/[Ff]/,/[Aa]/,/[Ll]/,/[Ss]/,/[Ee]/]]},{"name":"null","bnf":[[/[Nn]/,/[Uu]/,/[Ll]/,/[Ll]/]]},{"name":"true","bnf":[[/[Tt]/,/[Rr]/,/[Uu]/,/[Ee]/]]},{"name":"%array[2][2]","bnf":[["VALUE_SEPARATOR","value"]],"fragment":true},{"name":"%array[2]","bnf":[["value","%array[2][2]*"]],"fragment":true},{"name":"array","bnf":[["BEGIN_ARRAY","%array[2]?","END_ARRAY"]]},{"name":"unit","bnf":[[/[Ss]/,/[Ee]/,/[Cc]/,/[Oo]/,/[Nn]/,/[Dd]/,/[Ss]/],[/[Mm]/,/[Ii]/,/[Nn]/,/[Uu]/,/[Tt]/,/[Ee]/,/[Ss]/],[/[Hh]/,/[Oo]/,/[Uu]/,/[Rr]/,/[Ss]/],[/[Ww]/,/[Ee]/,/[Ee]/,/[Kk]/,/[Ss]/],[/[Dd]/,/[Aa]/,/[Yy]/,/[Ss]/],[/[Ss]/,/[Ee]/,/[Cc]/,/[Oo]/,/[Nn]/,/[Dd]/],[/[Mm]/,/[Ii]/,/[Nn]/,/[Uu]/,/[Tt]/,/[Ee]/],[/[Ww]/,/[Ee]/,/[Ee]/,/[Kk]/],[/[Hh]/,/[Oo]/,/[Uu]/,/[Rr]/],[/[Dd]/,/[Aa]/,/[Yy]/],[/[Mm]/,/[Ii]/,/[Nn]/,/[Ss]/],[/[Mm]/,/[Ii]/,/[Nn]/]]},{"name":"%number[2][1]","bnf":[[/[0-9]/]]},{"name":"%number[2]","bnf":[["%number[2][1]+"]],"fragment":true},{"name":"%number[3][2]","bnf":[[/[0-9]/]]},{"name":"%number[3]","bnf":[["\".\"","%number[3][2]+"]],"fragment":true},{"name":"%number[4][2]","bnf":[["\"-\""],["\"+\""]],"fragment":true},{"name":"%number[4][3][2]","bnf":[[/[0-9]/]]},{"name":"%number[4][3]","bnf":[["\"0\""],[/[1-9]/,"%number[4][3][2]*"]],"fragment":true},{"name":"%number[4]","bnf":[["\"e\"","%number[4][2]?","%number[4][3]"]],"fragment":true},{"name":"number","bnf":[["\"-\"?","%number[2]","%number[3]?","%number[4]?"]]},{"name":"number_time","bnf":[["number","WS+","unit"]]},{"name":"%number_tod[1][1]","bnf":[[/[0-9]/]]},{"name":"%number_tod[1]","bnf":[["%number_tod[1][1]+"]],"fragment":true},{"name":"%number_tod[3][1]","bnf":[[/[0-9]/]]},{"name":"%number_tod[3]","bnf":[["%number_tod[3][1]+"]],"fragment":true},{"name":"number_tod","bnf":[["%number_tod[1]","\":\"","%number_tod[3]"]]},{"name":"%time_period_ago[2]","bnf":[["WS+","number_time_atom"]],"fragment":true},{"name":"time_period_ago","bnf":[["number_time_atom","%time_period_ago[2]*","WS+","AGO"]]},{"name":"%time_period_ago_between[2]","bnf":[["WS+","number_time_atom"]],"fragment":true},{"name":"%time_period_ago_between[6]","bnf":[["between_time_only_atom"],["between_tod_only_atom"]],"fragment":true},{"name":"time_period_ago_between","bnf":[["number_time_atom","%time_period_ago_between[2]*","WS+","AGO","WS+","%time_period_ago_between[6]"]]},{"name":"time_period_const","bnf":[[/[Tt]/,/[Oo]/,/[Dd]/,/[Aa]/,/[Yy]/],["time_period_ago"]]},{"name":"time_period","bnf":[["time_period_ago_between"],["time_period_const"],["between_tod_only"],["between_time_only"]]},{"name":"%string[2][1]","bnf":[[/[\x20-\x21]/],[/[\x23-\x5B]/],[/[\x5D-\uFFFF]/]],"fragment":true},{"name":"%string[2][2]","bnf":[[/\x22/],[/\x5C/],[/\x2F/],[/\x62/],[/\x66/],[/\x6E/],[/\x72/],[/\x74/],[/\x75/,"HEXDIG","HEXDIG","HEXDIG","HEXDIG"]],"fragment":true},{"name":"%string[2]","bnf":[["%string[2][1]"],[/\x5C/,"%string[2][2]"]],"fragment":true},{"name":"string","bnf":[["'\"'","%string[2]*","'\"'"]]},{"name":"HEXDIG","bnf":[[/[a-fA-F0-9]/]]}]
|
|
2
|
+
module.exports=[{"name":"statement_main","bnf":[["statement","EOF"]]},{"name":"logical_operator","bnf":[["AND"],["OR"]]},{"name":"%statement[2]","bnf":[["logical_operator","expression"]],"fragment":true},{"name":"statement","bnf":[["expression","%statement[2]*"]]},{"name":"expression","bnf":[["not_expression"],["standard_expression"],["parenthesis_expression"]]},{"name":"parenthesis_expression","bnf":[["BEGIN_PARENTHESIS","WS*","statement","WS*","END_PARENTHESIS"]]},{"name":"%not_expression[2]","bnf":[["result"],["parenthesis_expression"]],"fragment":true},{"name":"not_expression","bnf":[["NOT","%not_expression[2]"]]},{"name":"%standard_expression[2][1]","bnf":[["WS*","eq_approx"]],"fragment":true},{"name":"%standard_expression[2][2]","bnf":[["WS*","basic_rhs"]],"fragment":true},{"name":"%standard_expression[2][3][1]","bnf":[["WS+","IS"]],"fragment":true},{"name":"%standard_expression[2][3]","bnf":[["%standard_expression[2][3][1]?","WS+","between"]],"fragment":true},{"name":"%standard_expression[2][4]","bnf":[["WS+","in_expr"]],"fragment":true},{"name":"%standard_expression[2]","bnf":[["%standard_expression[2][1]"],["%standard_expression[2][2]"],["%standard_expression[2][3]"],["%standard_expression[2][4]"]],"fragment":true},{"name":"standard_expression","bnf":[["result","%standard_expression[2]?"]]},{"name":"basic_rhs","bnf":[["operator","WS*","result"]]},{"name":"eq_approx","bnf":[["eq_operator","WS*","\"~\"","WS*","result"]]},{"name":"PLUS","bnf":[["\"+\""]]},{"name":"MINUS","bnf":[["\"-\""]]},{"name":"MULTIPLY","bnf":[["\"*\""]]},{"name":"DIVIDE","bnf":[["\"/\""]]},{"name":"MODULUS","bnf":[["\"%\""]]},{"name":"DEFAULT_VAL","bnf":[["\"??\""]]},{"name":"arithmetic_operator","bnf":[["PLUS"],["MINUS"],["MULTIPLY"],["DIVIDE"],["MODULUS"],["DEFAULT_VAL"]]},{"name":"number_atom","bnf":[["number"]]},{"name":"number_time_atom","bnf":[["number_time"]]},{"name":"tod_atom","bnf":[["number_tod"]]},{"name":"dow_atom","bnf":[["dow"]]},{"name":"arithmetic_operand","bnf":[["fcall"],["parenthesis_expression"],["number_time_atom"],["number_atom"]]},{"name":"%arithmetic_result[5]","bnf":[["arithmetic_result"],["arithmetic_operand"]],"fragment":true},{"name":"arithmetic_result","bnf":[["arithmetic_operand","WS*","arithmetic_operator","WS*","%arithmetic_result[5]"]]},{"name":"simple_result","bnf":[["fcall"],["value"]]},{"name":"result","bnf":[["arithmetic_result"],["simple_result"]]},{"name":"value_atom","bnf":[["false"],["true"],["array"],["time_period"],["number_time_atom"],["number_atom"],["tod_atom"],["string"]]},{"name":"value","bnf":[["value_atom"]]},{"name":"BEGIN_ARRAY","bnf":[["WS*",/\x5B/,"WS*"]]},{"name":"BEGIN_OBJECT","bnf":[["WS*",/\x7B/,"WS*"]]},{"name":"END_ARRAY","bnf":[["WS*",/\x5D/,"WS*"]]},{"name":"END_OBJECT","bnf":[["WS*",/\x7D/,"WS*"]]},{"name":"NAME_SEPARATOR","bnf":[["WS*",/\x3A/,"WS*"]]},{"name":"VALUE_SEPARATOR","bnf":[["WS*",/\x2C/,"WS*"]]},{"name":"WS","bnf":[[/[\x20\x09\x0A\x0D]/]]},{"name":"operator","bnf":[["GTE"],["LTE"],["GT"],["LT"],["EQ"],["NEQ"]]},{"name":"eq_operator","bnf":[["EQ"],["NEQ"]]},{"name":"BEGIN_ARGUMENT","bnf":[["\"(\""]]},{"name":"END_ARGUMENT","bnf":[["\")\""]]},{"name":"BEGIN_PARENTHESIS","bnf":[["\"(\""]]},{"name":"END_PARENTHESIS","bnf":[["\")\""]]},{"name":"BEGIN_IN","bnf":[[/[Ii]/,/[Nn]/]]},{"name":"in_expr","bnf":[["BEGIN_IN","WS*","BEGIN_PARENTHESIS","WS*","arguments","END_PARENTHESIS"]]},{"name":"argument","bnf":[["statement","WS*"]]},{"name":"%arguments[2]","bnf":[["WS*","\",\"","WS*","argument"]],"fragment":true},{"name":"arguments","bnf":[["argument","%arguments[2]*"]]},{"name":"%fname[1]","bnf":[[/[A-Za-z0-9]/]]},{"name":"fname","bnf":[["%fname[1]+"]]},{"name":"fcall","bnf":[["fname","WS*","BEGIN_ARGUMENT","WS*","arguments?","END_ARGUMENT"]]},{"name":"%between_dash_or_and[1]","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"%between_dash_or_and[2]","bnf":[["WS*",/\-/,"WS*"]],"fragment":true},{"name":"between_dash_or_and","bnf":[["%between_dash_or_and[1]"],["%between_dash_or_and[2]"]]},{"name":"between_number_inner","bnf":[["number_atom"],["number_time_atom"]]},{"name":"between_number","bnf":[["between_number_inner","between_dash_or_and","between_number_inner"]]},{"name":"between_number_time_inner","bnf":[["number_time_atom"]]},{"name":"%between_number_time[4]","bnf":[["WS+","dow_range"]],"fragment":true},{"name":"between_number_time","bnf":[["between_number_time_inner","between_dash_or_and","between_number_time_inner","%between_number_time[4]?"]]},{"name":"between_tod_inner","bnf":[["tod_atom"]]},{"name":"%between_tod[2]","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"%between_tod[4]","bnf":[["WS+","dow_range"]],"fragment":true},{"name":"between_tod","bnf":[["between_tod_inner","%between_tod[2]","between_tod_inner","%between_tod[4]?"]]},{"name":"%between[3]","bnf":[["between_number"],["between_tod"]],"fragment":true},{"name":"between","bnf":[[/[Bb]/,/[Ee]/,/[Tt]/,/[Ww]/,/[Ee]/,/[Ee]/,/[Nn]/,"WS+","%between[3]"]]},{"name":"dow","bnf":[[/[Mm]/,/[Oo]/,/[Nn]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Mm]/,/[Oo]/,/[Nn]/],[/[Tt]/,/[Uu]/,/[Ee]/,/[Ss]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Tt]/,/[Uu]/,/[Ee]/],[/[Ww]/,/[Ee]/,/[Dd]/,/[Nn]/,/[Ee]/,/[Ss]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ww]/,/[Ee]/,/[Dd]/],[/[Tt]/,/[Hh]/,/[Uu]/,/[Rr]/,/[Ss]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Tt]/,/[Hh]/,/[Uu]/],[/[Tt]/,/[Hh]/,/[Uu]/,/[Rr]/],[/[Ff]/,/[Rr]/,/[Ii]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ff]/,/[Rr]/,/[Ii]/],[/[Ss]/,/[Aa]/,/[Tt]/,/[Uu]/,/[Rr]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ss]/,/[Aa]/,/[Tt]/],[/[Ss]/,/[Uu]/,/[Nn]/,/[Dd]/,/[Aa]/,/[Yy]/],[/[Ss]/,/[Uu]/,/[Nn]/]]},{"name":"dow_range_inner","bnf":[["dow_atom"]]},{"name":"%dow_range[4]","bnf":[["WS+",/[Tt]/,/[Oo]/,"WS+","dow_range_inner"]],"fragment":true},{"name":"dow_range","bnf":[[/[Oo]/,/[Nn]/,"WS+","dow_range_inner","%dow_range[4]?"]]},{"name":"between_time_only","bnf":[[/[Bb]/,/[Ee]/,/[Tt]/,/[Ww]/,/[Ee]/,/[Ee]/,/[Nn]/,"WS+","between_number_time"]]},{"name":"between_tod_only","bnf":[[/[Bb]/,/[Ee]/,/[Tt]/,/[Ww]/,/[Ee]/,/[Ee]/,/[Nn]/,"WS+","between_tod"]]},{"name":"between_time_only_atom","bnf":[["between_time_only"]]},{"name":"between_tod_only_atom","bnf":[["between_tod_only"]]},{"name":"time_period_atom","bnf":[["between_tod_only"],["between_time_only"]]},{"name":"time_period_ago_atom","bnf":[["time_period_ago_between"]]},{"name":"%AND[1]","bnf":[["WS*",/&/,/&/,"WS*"]],"fragment":true},{"name":"%AND[2]","bnf":[["WS+",/[Aa]/,/[Nn]/,/[Dd]/,"WS+"]],"fragment":true},{"name":"AND","bnf":[["%AND[1]"],["%AND[2]"]]},{"name":"%OR[1]","bnf":[["WS*",/\|/,/\|/,"WS*"]],"fragment":true},{"name":"%OR[2]","bnf":[["WS+",/[Oo]/,/[Rr]/,"WS+"]],"fragment":true},{"name":"OR","bnf":[["%OR[1]"],["%OR[2]"]]},{"name":"AGO","bnf":[[/[Aa]/,/[Gg]/,/[Oo]/]]},{"name":"GT","bnf":[["\">\""]]},{"name":"LT","bnf":[["\"<\""]]},{"name":"GTE","bnf":[["\">=\""]]},{"name":"LTE","bnf":[["\"<=\""]]},{"name":"IS","bnf":[[/[Ii]/,/[Ss]/]]},{"name":"EQ","bnf":[["\"==\""],["\"=\""]]},{"name":"NEQ","bnf":[["\"!=\""]]},{"name":"%NOT[1]","bnf":[[/!/,"WS*"]],"fragment":true},{"name":"%NOT[2]","bnf":[[/[Nn]/,/[Oo]/,/[Tt]/,"WS+"]],"fragment":true},{"name":"NOT","bnf":[["%NOT[1]"],["%NOT[2]"]]},{"name":"false","bnf":[[/[Ff]/,/[Aa]/,/[Ll]/,/[Ss]/,/[Ee]/]]},{"name":"null","bnf":[[/[Nn]/,/[Uu]/,/[Ll]/,/[Ll]/]]},{"name":"true","bnf":[[/[Tt]/,/[Rr]/,/[Uu]/,/[Ee]/]]},{"name":"%array[2][2]","bnf":[["VALUE_SEPARATOR","value"]],"fragment":true},{"name":"%array[2]","bnf":[["value","%array[2][2]*"]],"fragment":true},{"name":"array","bnf":[["BEGIN_ARRAY","%array[2]?","END_ARRAY"]]},{"name":"unit","bnf":[[/[Ss]/,/[Ee]/,/[Cc]/,/[Oo]/,/[Nn]/,/[Dd]/,/[Ss]/],[/[Mm]/,/[Ii]/,/[Nn]/,/[Uu]/,/[Tt]/,/[Ee]/,/[Ss]/],[/[Hh]/,/[Oo]/,/[Uu]/,/[Rr]/,/[Ss]/],[/[Ww]/,/[Ee]/,/[Ee]/,/[Kk]/,/[Ss]/],[/[Dd]/,/[Aa]/,/[Yy]/,/[Ss]/],[/[Ss]/,/[Ee]/,/[Cc]/,/[Oo]/,/[Nn]/,/[Dd]/],[/[Mm]/,/[Ii]/,/[Nn]/,/[Uu]/,/[Tt]/,/[Ee]/],[/[Ww]/,/[Ee]/,/[Ee]/,/[Kk]/],[/[Hh]/,/[Oo]/,/[Uu]/,/[Rr]/],[/[Dd]/,/[Aa]/,/[Yy]/],[/[Mm]/,/[Ii]/,/[Nn]/,/[Ss]/],[/[Mm]/,/[Ii]/,/[Nn]/]]},{"name":"%number[2][1]","bnf":[[/[0-9]/]]},{"name":"%number[2]","bnf":[["%number[2][1]+"]],"fragment":true},{"name":"%number[3][2]","bnf":[[/[0-9]/]]},{"name":"%number[3]","bnf":[["\".\"","%number[3][2]+"]],"fragment":true},{"name":"%number[4][2]","bnf":[["\"-\""],["\"+\""]],"fragment":true},{"name":"%number[4][3][2]","bnf":[[/[0-9]/]]},{"name":"%number[4][3]","bnf":[["\"0\""],[/[1-9]/,"%number[4][3][2]*"]],"fragment":true},{"name":"%number[4]","bnf":[["\"e\"","%number[4][2]?","%number[4][3]"]],"fragment":true},{"name":"number","bnf":[["\"-\"?","%number[2]","%number[3]?","%number[4]?"]]},{"name":"number_time","bnf":[["number","WS+","unit"]]},{"name":"%number_tod[1][1]","bnf":[[/[0-9]/]]},{"name":"%number_tod[1]","bnf":[["%number_tod[1][1]+"]],"fragment":true},{"name":"%number_tod[3][1]","bnf":[[/[0-9]/]]},{"name":"%number_tod[3]","bnf":[["%number_tod[3][1]+"]],"fragment":true},{"name":"number_tod","bnf":[["%number_tod[1]","\":\"","%number_tod[3]"]]},{"name":"%time_period_ago[2]","bnf":[["WS+","number_time_atom"]],"fragment":true},{"name":"time_period_ago","bnf":[["number_time_atom","%time_period_ago[2]*","WS+","AGO"]]},{"name":"%time_period_ago_between[2]","bnf":[["WS+","number_time_atom"]],"fragment":true},{"name":"%time_period_ago_between[6]","bnf":[["between_time_only_atom"],["between_tod_only_atom"]],"fragment":true},{"name":"time_period_ago_between","bnf":[["number_time_atom","%time_period_ago_between[2]*","WS+","AGO","WS+","%time_period_ago_between[6]"]]},{"name":"time_period_const","bnf":[[/[Tt]/,/[Oo]/,/[Dd]/,/[Aa]/,/[Yy]/],["time_period_ago"]]},{"name":"time_period","bnf":[["time_period_ago_atom"],["time_period_const"],["time_period_atom"]]},{"name":"%string[2][1]","bnf":[[/[\x20-\x21]/],[/[\x23-\x5B]/],[/[\x5D-\uFFFF]/]],"fragment":true},{"name":"%string[2][2]","bnf":[[/\x22/],[/\x5C/],[/\x2F/],[/\x62/],[/\x66/],[/\x6E/],[/\x72/],[/\x74/],[/\x75/,"HEXDIG","HEXDIG","HEXDIG","HEXDIG"]],"fragment":true},{"name":"%string[2]","bnf":[["%string[2][1]"],[/\x5C/,"%string[2][2]"]],"fragment":true},{"name":"string","bnf":[["'\"'","%string[2]*","'\"'"]]},{"name":"HEXDIG","bnf":[[/[a-fA-F0-9]/]]}]
|
|
3
3
|
},{}],2:[function(require,module,exports){
|
|
4
4
|
const {Parser} = require('ebnf/dist/Parser.js'), {ParsingError} = require('ebnf'), RuleParseError = require('./errors/RuleParseError');
|
|
5
5
|
let ParserRules = require('./RuleParser.production.ebnf.js');
|
|
@@ -28,6 +28,31 @@ const LogicalOperators = {
|
|
|
28
28
|
'||': 'Or',
|
|
29
29
|
'OR': 'Or'
|
|
30
30
|
};
|
|
31
|
+
const ILReservedNames = new Set([
|
|
32
|
+
'Value',
|
|
33
|
+
'Array',
|
|
34
|
+
'ArrayIn',
|
|
35
|
+
'Between',
|
|
36
|
+
'Not',
|
|
37
|
+
'And',
|
|
38
|
+
'Or',
|
|
39
|
+
'Gt',
|
|
40
|
+
'Lt',
|
|
41
|
+
'Gte',
|
|
42
|
+
'Lte',
|
|
43
|
+
'Eq',
|
|
44
|
+
'Neq',
|
|
45
|
+
'MathAdd',
|
|
46
|
+
'MathSub',
|
|
47
|
+
'MathDiv',
|
|
48
|
+
'MathMul',
|
|
49
|
+
'MathMod',
|
|
50
|
+
'Default',
|
|
51
|
+
'TimePeriodConst',
|
|
52
|
+
'TimePeriodConstAgo',
|
|
53
|
+
'TimePeriodBetween',
|
|
54
|
+
'TimePeriodBetweenAgo'
|
|
55
|
+
]);
|
|
31
56
|
const DOW_MAP = {
|
|
32
57
|
'MON': 'MONDAY',
|
|
33
58
|
'TUE': 'TUESDAY',
|
|
@@ -122,6 +147,9 @@ class RuleParser {
|
|
|
122
147
|
}
|
|
123
148
|
static _parseTimePeriod(tp) {
|
|
124
149
|
switch (tp.type) {
|
|
150
|
+
case 'time_period_atom':
|
|
151
|
+
case 'time_period_ago_atom':
|
|
152
|
+
return RuleParser._parseTimePeriod(tp.children[0]);
|
|
125
153
|
case 'time_period_const':
|
|
126
154
|
if (tp.children && tp.children.length > 0 && tp.children[0].type === 'time_period_ago') {
|
|
127
155
|
const timePeriodAgo = tp.children[0];
|
|
@@ -366,7 +394,7 @@ class RuleParser {
|
|
|
366
394
|
switch (type) {
|
|
367
395
|
case 'value_atom': {
|
|
368
396
|
const atomChild = child.children[0];
|
|
369
|
-
if (atomChild.type === 'time_period') {
|
|
397
|
+
if (atomChild.type === 'time_period' || atomChild.type === 'time_period_atom' || atomChild.type === 'time_period_ago_atom') {
|
|
370
398
|
const tp = atomChild.children[0];
|
|
371
399
|
return RuleParser._parseTimePeriod(tp);
|
|
372
400
|
}
|
|
@@ -379,6 +407,9 @@ class RuleParser {
|
|
|
379
407
|
const tp = child.children[0];
|
|
380
408
|
return RuleParser._parseTimePeriod(tp);
|
|
381
409
|
}
|
|
410
|
+
case 'time_period_atom':
|
|
411
|
+
case 'time_period_ago_atom':
|
|
412
|
+
return RuleParser._parseTimePeriod(child);
|
|
382
413
|
default:
|
|
383
414
|
return [
|
|
384
415
|
'Value',
|
|
@@ -403,6 +434,8 @@ class RuleParser {
|
|
|
403
434
|
switch (type) {
|
|
404
435
|
case 'fcall':
|
|
405
436
|
return RuleParser._parseFcall(child);
|
|
437
|
+
case 'parenthesis_expression':
|
|
438
|
+
return RuleParser._parseParenthesisExpression(child);
|
|
406
439
|
case 'number_atom':
|
|
407
440
|
case 'number_time_atom': {
|
|
408
441
|
return [
|
|
@@ -686,6 +719,29 @@ class RuleParser {
|
|
|
686
719
|
throw new Error(`unknown type of expression ${ eInner.type }`);
|
|
687
720
|
}
|
|
688
721
|
}
|
|
722
|
+
static _collectFunctions(il, names) {
|
|
723
|
+
if (!Array.isArray(il) || il.length === 0) {
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
const [head, ...tail] = il;
|
|
727
|
+
if (typeof head === 'string') {
|
|
728
|
+
if (!ILReservedNames.has(head)) {
|
|
729
|
+
names.add(head);
|
|
730
|
+
}
|
|
731
|
+
for (const child of tail) {
|
|
732
|
+
RuleParser._collectFunctions(child, names);
|
|
733
|
+
}
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
for (const child of il) {
|
|
737
|
+
RuleParser._collectFunctions(child, names);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
static getFunctions(il) {
|
|
741
|
+
const names = new Set();
|
|
742
|
+
RuleParser._collectFunctions(il, names);
|
|
743
|
+
return [...names];
|
|
744
|
+
}
|
|
689
745
|
static toIL(txt) {
|
|
690
746
|
try {
|
|
691
747
|
const ast = RuleParser.toAst(txt);
|
|
@@ -781,10 +837,14 @@ class ErrorAnalyzer {
|
|
|
781
837
|
|
|
782
838
|
// Get snippet (last 50 chars or the whole input if shorter)
|
|
783
839
|
const snippetStart = Math.max(0, trimmedInput.length - 50);
|
|
784
|
-
const
|
|
840
|
+
const snippetEnd = trimmedInput.length;
|
|
841
|
+
let snippet = this._buildSnippet(trimmedInput, snippetStart, snippetEnd);
|
|
785
842
|
|
|
786
843
|
// Analyze the error pattern
|
|
787
844
|
const errorInfo = this._detectErrorPattern(trimmedInput, position, snippet);
|
|
845
|
+
this._enrichBadFunctionCallError(trimmedInput, position, errorInfo, (value) => {
|
|
846
|
+
snippet = value;
|
|
847
|
+
}, snippetStart, snippetEnd);
|
|
788
848
|
|
|
789
849
|
return new RuleParseError(
|
|
790
850
|
errorInfo.code,
|
|
@@ -810,12 +870,13 @@ class ErrorAnalyzer {
|
|
|
810
870
|
// Get snippet around error position
|
|
811
871
|
const snippetStart = Math.max(0, position.offset - 20);
|
|
812
872
|
const snippetEnd = Math.min(input.length, position.offset + 30);
|
|
813
|
-
|
|
814
|
-
input.substring(snippetStart, snippetEnd) +
|
|
815
|
-
(snippetEnd < input.length ? '...' : '');
|
|
873
|
+
let snippet = this._buildSnippet(input, snippetStart, snippetEnd);
|
|
816
874
|
|
|
817
875
|
// Analyze what was expected to determine error type using failureTree
|
|
818
876
|
const errorInfo = this._detectErrorFromFailureTree(input, position, expected, found, failureTree);
|
|
877
|
+
this._enrichBadFunctionCallError(input, position, errorInfo, (value) => {
|
|
878
|
+
snippet = value;
|
|
879
|
+
}, snippetStart, snippetEnd);
|
|
819
880
|
|
|
820
881
|
return new RuleParseError(
|
|
821
882
|
errorInfo.code,
|
|
@@ -1329,6 +1390,109 @@ class ErrorAnalyzer {
|
|
|
1329
1390
|
};
|
|
1330
1391
|
}
|
|
1331
1392
|
|
|
1393
|
+
static _enrichBadFunctionCallError(input, position, errorInfo, setSnippet, snippetStart, snippetEnd) {
|
|
1394
|
+
if (!errorInfo || errorInfo.code !== "BAD_FUNCTION_CALL") {
|
|
1395
|
+
return;
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
const functionContext = this._findFunctionContext(input, position.offset);
|
|
1399
|
+
errorInfo.hint = this._getBadFunctionCallHint(input, position, functionContext);
|
|
1400
|
+
|
|
1401
|
+
if (!functionContext) {
|
|
1402
|
+
return;
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
errorInfo.message = `Invalid function call syntax for ${functionContext.name}.`;
|
|
1406
|
+
setSnippet(this._buildBadFunctionCallSnippet(input, functionContext, snippetStart, snippetEnd));
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
static _buildSnippet(input, start, end) {
|
|
1410
|
+
return (start > 0 ? '...' : '') +
|
|
1411
|
+
input.substring(start, end) +
|
|
1412
|
+
(end < input.length ? '...' : '');
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
static _getBadFunctionCallHint(input, position, functionContext) {
|
|
1416
|
+
const genericHint = "Function calls must have matching parentheses, e.g. func() or func(arg1, arg2).";
|
|
1417
|
+
|
|
1418
|
+
if (!functionContext || !this._isArgumentRelatedFunctionCallError(input, position, functionContext)) {
|
|
1419
|
+
return genericHint;
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
return "Function calls must have matching parentheses, e.g. func() or func(arg1, arg2). Please check function arguments for invalid syntax.";
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
static _isArgumentRelatedFunctionCallError(input, position, functionContext) {
|
|
1426
|
+
const endOffset = Math.max(functionContext.openParenIndex + 1, Math.min(position.offset, input.length));
|
|
1427
|
+
const argumentText = input.substring(functionContext.openParenIndex + 1, endOffset).trim();
|
|
1428
|
+
return argumentText.length > 0;
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
static _buildBadFunctionCallSnippet(input, functionContext, snippetStart, snippetEnd) {
|
|
1432
|
+
if (snippetStart <= functionContext.start) {
|
|
1433
|
+
return this._buildSnippet(input, snippetStart, snippetEnd);
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
const functionPrefix = input.substring(functionContext.start, functionContext.openParenIndex + 1);
|
|
1437
|
+
const suffix = input.substring(snippetStart, snippetEnd);
|
|
1438
|
+
return functionPrefix + '...' + suffix + (snippetEnd < input.length ? '...' : '');
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
static _findFunctionContext(input, offset) {
|
|
1442
|
+
const scanLimit = Math.max(0, Math.min(typeof offset === 'number' ? offset : input.length, input.length));
|
|
1443
|
+
const stack = [];
|
|
1444
|
+
let inString = false;
|
|
1445
|
+
|
|
1446
|
+
for (let i = 0; i < scanLimit; i++) {
|
|
1447
|
+
const char = input[i];
|
|
1448
|
+
|
|
1449
|
+
if (char === '"') {
|
|
1450
|
+
if (!inString) {
|
|
1451
|
+
inString = true;
|
|
1452
|
+
} else {
|
|
1453
|
+
let backslashCount = 0;
|
|
1454
|
+
let j = i - 1;
|
|
1455
|
+
while (j >= 0 && input[j] === '\\') {
|
|
1456
|
+
backslashCount++;
|
|
1457
|
+
j--;
|
|
1458
|
+
}
|
|
1459
|
+
if (backslashCount % 2 === 0) {
|
|
1460
|
+
inString = false;
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
continue;
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
if (inString) {
|
|
1467
|
+
continue;
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
if (char === '(') {
|
|
1471
|
+
const prefix = input.substring(0, i);
|
|
1472
|
+
const match = /([a-zA-Z_][a-zA-Z0-9_]*)\s*$/.exec(prefix);
|
|
1473
|
+
if (match) {
|
|
1474
|
+
stack.push({
|
|
1475
|
+
name: match[1],
|
|
1476
|
+
start: i - match[1].length,
|
|
1477
|
+
openParenIndex: i
|
|
1478
|
+
});
|
|
1479
|
+
} else {
|
|
1480
|
+
stack.push(null);
|
|
1481
|
+
}
|
|
1482
|
+
} else if (char === ')' && stack.length > 0) {
|
|
1483
|
+
stack.pop();
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
1488
|
+
if (stack[i]) {
|
|
1489
|
+
return stack[i];
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
return null;
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1332
1496
|
/**
|
|
1333
1497
|
* Check if string is properly terminated
|
|
1334
1498
|
* @private
|
|
@@ -1700,12 +1864,6 @@ class RuleParseError extends Error {
|
|
|
1700
1864
|
if (this.hint) {
|
|
1701
1865
|
msg += ` Hint: ${this.hint}\n`;
|
|
1702
1866
|
}
|
|
1703
|
-
if (this.found) {
|
|
1704
|
-
msg += ` Found: ${this.found}\n`;
|
|
1705
|
-
}
|
|
1706
|
-
if (this.expected && this.expected.length) {
|
|
1707
|
-
msg += ` Expected: ${this.expected.join(', ')}`;
|
|
1708
|
-
}
|
|
1709
1867
|
return msg;
|
|
1710
1868
|
}
|
|
1711
1869
|
|
|
@@ -3671,18 +3829,9 @@ const grammar = `
|
|
|
3671
3829
|
|
|
3672
3830
|
template_filter_arg ::= value | template_value
|
|
3673
3831
|
|
|
3674
|
-
number_atom ::= number | template_value
|
|
3675
|
-
number_time_atom ::= number_time | template_value WS+ unit | template_value
|
|
3676
|
-
tod_atom ::= number_tod | template_value
|
|
3677
|
-
dow_atom ::= dow | template_value
|
|
3678
|
-
between_time_only_atom ::= between_time_only | template_value
|
|
3679
|
-
between_tod_only_atom ::= between_tod_only | template_value
|
|
3680
|
-
|
|
3681
3832
|
string_atom ::= string
|
|
3682
3833
|
boolean_atom ::= false | true
|
|
3683
3834
|
time_value_atom ::= number_tod
|
|
3684
|
-
time_period_atom ::= time_value_atom WS* "TO" WS* time_value_atom
|
|
3685
|
-
time_period_ago_atom ::= time_value_atom WS* "TO" WS* time_value_atom WS+ AGO WS+ number WS+ unit
|
|
3686
3835
|
|
|
3687
3836
|
object_atom ::= json_object
|
|
3688
3837
|
json_value ::= string | number | false | true | null | json_array | json_object
|
|
@@ -3699,7 +3848,7 @@ const grammar = `
|
|
|
3699
3848
|
module.exports = Grammars.W3C.getRules(grammar);
|
|
3700
3849
|
|
|
3701
3850
|
},{"ebnf":13}],16:[function(require,module,exports){
|
|
3702
|
-
module.exports=[{"name":"TEMPLATE_BEGIN","bnf":[["\"${\""]]},{"name":"TEMPLATE_END","bnf":[["\"}\""]]},{"name":"PIPE","bnf":[["\"|\""]]},{"name":"%IDENT[2]","bnf":[[/[A-Za-z0-9_]/]]},{"name":"IDENT","bnf":[[/[A-Za-z_]/,"%IDENT[2]*"]]},{"name":"DOT","bnf":[["\".\""]]},{"name":"template_value","bnf":[["TEMPLATE_BEGIN","WS*","template_expr","WS*","TEMPLATE_END"]]},{"name":"%template_expr[2]","bnf":[["WS*","template_pipe","WS*","template_filter_call"]],"fragment":true},{"name":"template_expr","bnf":[["template_path","%template_expr[2]*"]]},{"name":"template_pipe","bnf":[["PIPE"]]},{"name":"%template_path[2]","bnf":[["WS*","DOT","WS*","IDENT"]],"fragment":true},{"name":"template_path","bnf":[["IDENT","%template_path[2]*"]]},{"name":"%template_filter_call[2]","bnf":[["WS*","BEGIN_ARGUMENT","WS*","template_filter_args?","WS*","END_ARGUMENT"]],"fragment":true},{"name":"template_filter_call","bnf":[["template_filter_name","%template_filter_call[2]?"]]},{"name":"template_filter_name","bnf":[["IDENT"]]},{"name":"%template_filter_args[2]","bnf":[["WS*","\",\"","WS*","template_filter_arg"]],"fragment":true},{"name":"template_filter_args","bnf":[["template_filter_arg","%template_filter_args[2]*"]]},{"name":"template_filter_arg","bnf":[["value"],["template_value"]]},{"name":"
|
|
3851
|
+
module.exports=[{"name":"TEMPLATE_BEGIN","bnf":[["\"${\""]]},{"name":"TEMPLATE_END","bnf":[["\"}\""]]},{"name":"PIPE","bnf":[["\"|\""]]},{"name":"%IDENT[2]","bnf":[[/[A-Za-z0-9_]/]]},{"name":"IDENT","bnf":[[/[A-Za-z_]/,"%IDENT[2]*"]]},{"name":"DOT","bnf":[["\".\""]]},{"name":"template_value","bnf":[["TEMPLATE_BEGIN","WS*","template_expr","WS*","TEMPLATE_END"]]},{"name":"%template_expr[2]","bnf":[["WS*","template_pipe","WS*","template_filter_call"]],"fragment":true},{"name":"template_expr","bnf":[["template_path","%template_expr[2]*"]]},{"name":"template_pipe","bnf":[["PIPE"]]},{"name":"%template_path[2]","bnf":[["WS*","DOT","WS*","IDENT"]],"fragment":true},{"name":"template_path","bnf":[["IDENT","%template_path[2]*"]]},{"name":"%template_filter_call[2]","bnf":[["WS*","BEGIN_ARGUMENT","WS*","template_filter_args?","WS*","END_ARGUMENT"]],"fragment":true},{"name":"template_filter_call","bnf":[["template_filter_name","%template_filter_call[2]?"]]},{"name":"template_filter_name","bnf":[["IDENT"]]},{"name":"%template_filter_args[2]","bnf":[["WS*","\",\"","WS*","template_filter_arg"]],"fragment":true},{"name":"template_filter_args","bnf":[["template_filter_arg","%template_filter_args[2]*"]]},{"name":"template_filter_arg","bnf":[["value"],["template_value"]]},{"name":"string_atom","bnf":[["string"]]},{"name":"boolean_atom","bnf":[["false"],["true"]]},{"name":"time_value_atom","bnf":[["number_tod"]]},{"name":"object_atom","bnf":[["json_object"]]},{"name":"json_value","bnf":[["string"],["number"],["false"],["true"],["null"],["json_array"],["json_object"]]},{"name":"json_member","bnf":[["string","NAME_SEPARATOR","json_value"]]},{"name":"%json_object[2][2]","bnf":[["VALUE_SEPARATOR","json_member"]],"fragment":true},{"name":"%json_object[2]","bnf":[["json_member","%json_object[2][2]*"]],"fragment":true},{"name":"json_object","bnf":[["BEGIN_OBJECT","%json_object[2]?","END_OBJECT"]]},{"name":"%json_array[2][2]","bnf":[["VALUE_SEPARATOR","json_value"]],"fragment":true},{"name":"%json_array[2]","bnf":[["json_value","%json_array[2][2]*"]],"fragment":true},{"name":"json_array","bnf":[["BEGIN_ARRAY","%json_array[2]?","END_ARRAY"]]},{"name":"%string_array[2][2]","bnf":[["VALUE_SEPARATOR","string"]],"fragment":true},{"name":"%string_array[2]","bnf":[["string","%string_array[2][2]*"]],"fragment":true},{"name":"string_array","bnf":[["BEGIN_ARRAY","%string_array[2]?","END_ARRAY"]]},{"name":"%number_array[2][2]","bnf":[["VALUE_SEPARATOR","number"]],"fragment":true},{"name":"%number_array[2]","bnf":[["number","%number_array[2][2]*"]],"fragment":true},{"name":"number_array","bnf":[["BEGIN_ARRAY","%number_array[2]?","END_ARRAY"]]},{"name":"%boolean_array[2][2]","bnf":[["VALUE_SEPARATOR","boolean_atom"]],"fragment":true},{"name":"%boolean_array[2]","bnf":[["boolean_atom","%boolean_array[2][2]*"]],"fragment":true},{"name":"boolean_array","bnf":[["BEGIN_ARRAY","%boolean_array[2]?","END_ARRAY"]]},{"name":"%object_array[2][2]","bnf":[["VALUE_SEPARATOR","json_object"]],"fragment":true},{"name":"%object_array[2]","bnf":[["json_object","%object_array[2][2]*"]],"fragment":true},{"name":"object_array","bnf":[["BEGIN_ARRAY","%object_array[2]?","END_ARRAY"]]}]
|
|
3703
3852
|
},{}],17:[function(require,module,exports){
|
|
3704
3853
|
// Note: We are coupled closely with the ebnf grammar structure of rule-parser
|
|
3705
3854
|
const TemplateGrammar = require('./RuleTemplate.production.ebnf.js'),
|
|
@@ -3731,7 +3880,7 @@ const AllowedTypeMapping = {
|
|
|
3731
3880
|
'number': ['number_atom', 'math_expr'],
|
|
3732
3881
|
'boolean': ['boolean_atom', 'boolean_expr'],
|
|
3733
3882
|
'time period': ['time_period_atom'],
|
|
3734
|
-
'time period ago': ['time_period_atom'],
|
|
3883
|
+
'time period ago': ['time_period_ago_atom', 'time_period_atom'],
|
|
3735
3884
|
'time value': ['time_value_atom', 'tod_atom'],
|
|
3736
3885
|
'number time': ['number_atom'],
|
|
3737
3886
|
'string array': ['string_array'],
|
|
@@ -3752,12 +3901,69 @@ for(const rule of TemplateGrammar){
|
|
|
3752
3901
|
}
|
|
3753
3902
|
}
|
|
3754
3903
|
|
|
3755
|
-
|
|
3756
|
-
const
|
|
3757
|
-
if (
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3904
|
+
const cloneRule = (ruleName) => {
|
|
3905
|
+
const idx = extendedGrammar.findIndex(rule => rule.name === ruleName);
|
|
3906
|
+
if (idx === -1) {
|
|
3907
|
+
return null;
|
|
3908
|
+
}
|
|
3909
|
+
|
|
3910
|
+
extendedGrammar[idx] = Object.assign({}, extendedGrammar[idx], {
|
|
3911
|
+
bnf: extendedGrammar[idx].bnf.map(alt => Array.isArray(alt) ? alt.slice() : alt)
|
|
3912
|
+
});
|
|
3913
|
+
|
|
3914
|
+
return extendedGrammar[idx];
|
|
3915
|
+
};
|
|
3916
|
+
|
|
3917
|
+
const appendAlternative = (ruleName, alternative) => {
|
|
3918
|
+
const rule = cloneRule(ruleName);
|
|
3919
|
+
if (!rule) {
|
|
3920
|
+
return;
|
|
3921
|
+
}
|
|
3922
|
+
|
|
3923
|
+
const exists = rule.bnf.some(existing => JSON.stringify(existing) === JSON.stringify(alternative));
|
|
3924
|
+
if (!exists) {
|
|
3925
|
+
rule.bnf.push(alternative);
|
|
3926
|
+
}
|
|
3927
|
+
};
|
|
3928
|
+
|
|
3929
|
+
const replaceRule = (ruleName, bnf) => {
|
|
3930
|
+
const idx = extendedGrammar.findIndex(rule => rule.name === ruleName);
|
|
3931
|
+
if (idx === -1) {
|
|
3932
|
+
extendedGrammar.push({name: ruleName, bnf});
|
|
3933
|
+
return;
|
|
3934
|
+
}
|
|
3935
|
+
|
|
3936
|
+
extendedGrammar[idx] = Object.assign({}, extendedGrammar[idx], {
|
|
3937
|
+
bnf: bnf.map(alt => alt.slice())
|
|
3938
|
+
});
|
|
3939
|
+
};
|
|
3940
|
+
|
|
3941
|
+
appendAlternative('number_atom', ['template_value']);
|
|
3942
|
+
appendAlternative('number_time_atom', ['template_value', 'WS+', 'unit']);
|
|
3943
|
+
appendAlternative('number_time_atom', ['template_value']);
|
|
3944
|
+
appendAlternative('tod_atom', ['template_value']);
|
|
3945
|
+
appendAlternative('dow_atom', ['template_value']);
|
|
3946
|
+
appendAlternative('between_time_only_atom', ['template_value']);
|
|
3947
|
+
appendAlternative('between_tod_only_atom', ['template_value']);
|
|
3948
|
+
appendAlternative('string_atom', ['template_value']);
|
|
3949
|
+
appendAlternative('boolean_atom', ['template_value']);
|
|
3950
|
+
appendAlternative('time_value_atom', ['template_value']);
|
|
3951
|
+
appendAlternative('object_atom', ['template_value']);
|
|
3952
|
+
appendAlternative('string_array', ['template_value']);
|
|
3953
|
+
appendAlternative('number_array', ['template_value']);
|
|
3954
|
+
appendAlternative('boolean_array', ['template_value']);
|
|
3955
|
+
appendAlternative('object_array', ['template_value']);
|
|
3956
|
+
|
|
3957
|
+
replaceRule('argument', [
|
|
3958
|
+
['number_time_atom', 'WS*'],
|
|
3959
|
+
['statement', 'WS*']
|
|
3960
|
+
]);
|
|
3961
|
+
|
|
3962
|
+
replaceRule('simple_result', [
|
|
3963
|
+
['fcall'],
|
|
3964
|
+
['value'],
|
|
3965
|
+
['number_time_atom']
|
|
3966
|
+
]);
|
|
3761
3967
|
|
|
3762
3968
|
// Export the parser rules for potential external use
|
|
3763
3969
|
const ParserRules = extendedGrammar;
|
|
@@ -4054,6 +4260,23 @@ class RuleTemplate {
|
|
|
4054
4260
|
}
|
|
4055
4261
|
}
|
|
4056
4262
|
|
|
4263
|
+
const canValidatePreparedRule = errors.length === 0
|
|
4264
|
+
&& Array.from(seenVariables).every(varName => {
|
|
4265
|
+
const varData = variables[varName];
|
|
4266
|
+
return varData
|
|
4267
|
+
&& typeof varData === 'object'
|
|
4268
|
+
&& Object.prototype.hasOwnProperty.call(varData, 'type')
|
|
4269
|
+
&& Object.prototype.hasOwnProperty.call(varData, 'value');
|
|
4270
|
+
});
|
|
4271
|
+
|
|
4272
|
+
if (canValidatePreparedRule) {
|
|
4273
|
+
try {
|
|
4274
|
+
RuleParser.toAst(this.prepare(variables));
|
|
4275
|
+
} catch (error) {
|
|
4276
|
+
errors.push(`Prepared rule is invalid: ${error.message}`);
|
|
4277
|
+
}
|
|
4278
|
+
}
|
|
4279
|
+
|
|
4057
4280
|
if (functionBlob && typeof functionBlob.validate === 'function') {
|
|
4058
4281
|
for (const functionCall of this._extractFunctionCalls()) {
|
|
4059
4282
|
warnings.push(...functionBlob.validate(functionCall.name, functionCall.arguments));
|
|
@@ -4262,12 +4485,12 @@ class RuleTemplate {
|
|
|
4262
4485
|
return value ? 'true' : 'false';
|
|
4263
4486
|
}
|
|
4264
4487
|
|
|
4265
|
-
if (type === 'time period'
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
return
|
|
4488
|
+
if (type === 'time period') {
|
|
4489
|
+
return `BETWEEN ${value.from} AND ${value.to}`;
|
|
4490
|
+
}
|
|
4491
|
+
|
|
4492
|
+
if (type === 'time period ago') {
|
|
4493
|
+
return `${value.ago[0]} ${value.ago[1]} AGO BETWEEN ${value.from} AND ${value.to}`;
|
|
4271
4494
|
}
|
|
4272
4495
|
|
|
4273
4496
|
if (type === 'object' || type === 'string array' || type === 'number array' || type === 'boolean array' || type === 'object array') {
|
|
@@ -4762,7 +4985,7 @@ class VariableValidate {
|
|
|
4762
4985
|
return null;
|
|
4763
4986
|
}
|
|
4764
4987
|
|
|
4765
|
-
return
|
|
4988
|
+
return `BETWEEN ${value.from.trim()} AND ${value.to.trim()}`;
|
|
4766
4989
|
}
|
|
4767
4990
|
|
|
4768
4991
|
static _serializeTimePeriodAgo(value) {
|
|
@@ -4779,7 +5002,7 @@ class VariableValidate {
|
|
|
4779
5002
|
return null;
|
|
4780
5003
|
}
|
|
4781
5004
|
|
|
4782
|
-
return `${
|
|
5005
|
+
return `${amount} ${unit.trim()} AGO BETWEEN ${value.from.trim()} AND ${value.to.trim()}`;
|
|
4783
5006
|
}
|
|
4784
5007
|
|
|
4785
5008
|
static _serializeNumberTime(value) {
|
|
@@ -4896,7 +5119,7 @@ VariableValidate.validators = Object.freeze({
|
|
|
4896
5119
|
'time period': (value) => VariableValidate._validateWithRule(value, 'time_period_atom', {
|
|
4897
5120
|
normalize: VariableValidate._serializeTimePeriod,
|
|
4898
5121
|
emptyMessage: 'Time period variables must be objects with string from/to properties',
|
|
4899
|
-
parseMessage: 'Time period variables must serialize to FROM
|
|
5122
|
+
parseMessage: 'Time period variables must serialize to BETWEEN FROM AND TO syntax',
|
|
4900
5123
|
semanticCheck: (rawValue) => {
|
|
4901
5124
|
const fromError = VariableValidate._validateTimeOfDay(rawValue?.from);
|
|
4902
5125
|
if (fromError) return `Invalid time period from value: ${fromError}`;
|
|
@@ -4910,7 +5133,7 @@ VariableValidate.validators = Object.freeze({
|
|
|
4910
5133
|
'time period ago': (value) => VariableValidate._validateWithRule(value, 'time_period_ago_atom', {
|
|
4911
5134
|
normalize: VariableValidate._serializeTimePeriodAgo,
|
|
4912
5135
|
emptyMessage: 'Time period ago variables must be objects with from, to, and ago properties',
|
|
4913
|
-
parseMessage: 'Time period ago variables must serialize to
|
|
5136
|
+
parseMessage: 'Time period ago variables must serialize to AMOUNT UNIT AGO BETWEEN FROM AND TO syntax',
|
|
4914
5137
|
semanticCheck: (rawValue) => {
|
|
4915
5138
|
const fromError = VariableValidate._validateTimeOfDay(rawValue?.from);
|
|
4916
5139
|
if (fromError) return `Invalid time period ago from value: ${fromError}`;
|
package/package.json
CHANGED
package/src/GeneralTemplate.js
CHANGED
|
@@ -190,12 +190,12 @@ class GeneralTemplate {
|
|
|
190
190
|
return '';
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
if (varData.type === 'time period'
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
return
|
|
193
|
+
if (varData.type === 'time period') {
|
|
194
|
+
return `BETWEEN ${varData.value.from} AND ${varData.value.to}`;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (varData.type === 'time period ago') {
|
|
198
|
+
return `${varData.value.ago[0]} ${varData.value.ago[1]} AGO BETWEEN ${varData.value.from} AND ${varData.value.to}`;
|
|
199
199
|
}
|
|
200
200
|
|
|
201
201
|
return String(varData.value);
|
package/src/RuleTemplate.ebnf.js
CHANGED
|
@@ -23,18 +23,9 @@ const grammar = `
|
|
|
23
23
|
|
|
24
24
|
template_filter_arg ::= value | template_value
|
|
25
25
|
|
|
26
|
-
number_atom ::= number | template_value
|
|
27
|
-
number_time_atom ::= number_time | template_value WS+ unit | template_value
|
|
28
|
-
tod_atom ::= number_tod | template_value
|
|
29
|
-
dow_atom ::= dow | template_value
|
|
30
|
-
between_time_only_atom ::= between_time_only | template_value
|
|
31
|
-
between_tod_only_atom ::= between_tod_only | template_value
|
|
32
|
-
|
|
33
26
|
string_atom ::= string
|
|
34
27
|
boolean_atom ::= false | true
|
|
35
28
|
time_value_atom ::= number_tod
|
|
36
|
-
time_period_atom ::= time_value_atom WS* "TO" WS* time_value_atom
|
|
37
|
-
time_period_ago_atom ::= time_value_atom WS* "TO" WS* time_value_atom WS+ AGO WS+ number WS+ unit
|
|
38
29
|
|
|
39
30
|
object_atom ::= json_object
|
|
40
31
|
json_value ::= string | number | false | true | null | json_array | json_object
|
package/src/RuleTemplate.js
CHANGED
|
@@ -28,7 +28,7 @@ const AllowedTypeMapping = {
|
|
|
28
28
|
'number': ['number_atom', 'math_expr'],
|
|
29
29
|
'boolean': ['boolean_atom', 'boolean_expr'],
|
|
30
30
|
'time period': ['time_period_atom'],
|
|
31
|
-
'time period ago': ['time_period_atom'],
|
|
31
|
+
'time period ago': ['time_period_ago_atom', 'time_period_atom'],
|
|
32
32
|
'time value': ['time_value_atom', 'tod_atom'],
|
|
33
33
|
'number time': ['number_atom'],
|
|
34
34
|
'string array': ['string_array'],
|
|
@@ -49,12 +49,69 @@ for(const rule of TemplateGrammar){
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
const cloneRule = (ruleName) => {
|
|
53
|
+
const idx = extendedGrammar.findIndex(rule => rule.name === ruleName);
|
|
54
|
+
if (idx === -1) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
extendedGrammar[idx] = Object.assign({}, extendedGrammar[idx], {
|
|
59
|
+
bnf: extendedGrammar[idx].bnf.map(alt => Array.isArray(alt) ? alt.slice() : alt)
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
return extendedGrammar[idx];
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const appendAlternative = (ruleName, alternative) => {
|
|
66
|
+
const rule = cloneRule(ruleName);
|
|
67
|
+
if (!rule) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const exists = rule.bnf.some(existing => JSON.stringify(existing) === JSON.stringify(alternative));
|
|
72
|
+
if (!exists) {
|
|
73
|
+
rule.bnf.push(alternative);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const replaceRule = (ruleName, bnf) => {
|
|
78
|
+
const idx = extendedGrammar.findIndex(rule => rule.name === ruleName);
|
|
79
|
+
if (idx === -1) {
|
|
80
|
+
extendedGrammar.push({name: ruleName, bnf});
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
extendedGrammar[idx] = Object.assign({}, extendedGrammar[idx], {
|
|
85
|
+
bnf: bnf.map(alt => alt.slice())
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
appendAlternative('number_atom', ['template_value']);
|
|
90
|
+
appendAlternative('number_time_atom', ['template_value', 'WS+', 'unit']);
|
|
91
|
+
appendAlternative('number_time_atom', ['template_value']);
|
|
92
|
+
appendAlternative('tod_atom', ['template_value']);
|
|
93
|
+
appendAlternative('dow_atom', ['template_value']);
|
|
94
|
+
appendAlternative('between_time_only_atom', ['template_value']);
|
|
95
|
+
appendAlternative('between_tod_only_atom', ['template_value']);
|
|
96
|
+
appendAlternative('string_atom', ['template_value']);
|
|
97
|
+
appendAlternative('boolean_atom', ['template_value']);
|
|
98
|
+
appendAlternative('time_value_atom', ['template_value']);
|
|
99
|
+
appendAlternative('object_atom', ['template_value']);
|
|
100
|
+
appendAlternative('string_array', ['template_value']);
|
|
101
|
+
appendAlternative('number_array', ['template_value']);
|
|
102
|
+
appendAlternative('boolean_array', ['template_value']);
|
|
103
|
+
appendAlternative('object_array', ['template_value']);
|
|
104
|
+
|
|
105
|
+
replaceRule('argument', [
|
|
106
|
+
['number_time_atom', 'WS*'],
|
|
107
|
+
['statement', 'WS*']
|
|
108
|
+
]);
|
|
109
|
+
|
|
110
|
+
replaceRule('simple_result', [
|
|
111
|
+
['fcall'],
|
|
112
|
+
['value'],
|
|
113
|
+
['number_time_atom']
|
|
114
|
+
]);
|
|
58
115
|
|
|
59
116
|
// Export the parser rules for potential external use
|
|
60
117
|
const ParserRules = extendedGrammar;
|
|
@@ -351,6 +408,23 @@ class RuleTemplate {
|
|
|
351
408
|
}
|
|
352
409
|
}
|
|
353
410
|
|
|
411
|
+
const canValidatePreparedRule = errors.length === 0
|
|
412
|
+
&& Array.from(seenVariables).every(varName => {
|
|
413
|
+
const varData = variables[varName];
|
|
414
|
+
return varData
|
|
415
|
+
&& typeof varData === 'object'
|
|
416
|
+
&& Object.prototype.hasOwnProperty.call(varData, 'type')
|
|
417
|
+
&& Object.prototype.hasOwnProperty.call(varData, 'value');
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
if (canValidatePreparedRule) {
|
|
421
|
+
try {
|
|
422
|
+
RuleParser.toAst(this.prepare(variables));
|
|
423
|
+
} catch (error) {
|
|
424
|
+
errors.push(`Prepared rule is invalid: ${error.message}`);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
354
428
|
if (functionBlob && typeof functionBlob.validate === 'function') {
|
|
355
429
|
for (const functionCall of this._extractFunctionCalls()) {
|
|
356
430
|
warnings.push(...functionBlob.validate(functionCall.name, functionCall.arguments));
|
|
@@ -559,12 +633,12 @@ class RuleTemplate {
|
|
|
559
633
|
return value ? 'true' : 'false';
|
|
560
634
|
}
|
|
561
635
|
|
|
562
|
-
if (type === 'time period'
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
return
|
|
636
|
+
if (type === 'time period') {
|
|
637
|
+
return `BETWEEN ${value.from} AND ${value.to}`;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
if (type === 'time period ago') {
|
|
641
|
+
return `${value.ago[0]} ${value.ago[1]} AGO BETWEEN ${value.from} AND ${value.to}`;
|
|
568
642
|
}
|
|
569
643
|
|
|
570
644
|
if (type === 'object' || type === 'string array' || type === 'number array' || type === 'boolean array' || type === 'object array') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
module.exports=[{"name":"TEMPLATE_BEGIN","bnf":[["\"${\""]]},{"name":"TEMPLATE_END","bnf":[["\"}\""]]},{"name":"PIPE","bnf":[["\"|\""]]},{"name":"%IDENT[2]","bnf":[[/[A-Za-z0-9_]/]]},{"name":"IDENT","bnf":[[/[A-Za-z_]/,"%IDENT[2]*"]]},{"name":"DOT","bnf":[["\".\""]]},{"name":"template_value","bnf":[["TEMPLATE_BEGIN","WS*","template_expr","WS*","TEMPLATE_END"]]},{"name":"%template_expr[2]","bnf":[["WS*","template_pipe","WS*","template_filter_call"]],"fragment":true},{"name":"template_expr","bnf":[["template_path","%template_expr[2]*"]]},{"name":"template_pipe","bnf":[["PIPE"]]},{"name":"%template_path[2]","bnf":[["WS*","DOT","WS*","IDENT"]],"fragment":true},{"name":"template_path","bnf":[["IDENT","%template_path[2]*"]]},{"name":"%template_filter_call[2]","bnf":[["WS*","BEGIN_ARGUMENT","WS*","template_filter_args?","WS*","END_ARGUMENT"]],"fragment":true},{"name":"template_filter_call","bnf":[["template_filter_name","%template_filter_call[2]?"]]},{"name":"template_filter_name","bnf":[["IDENT"]]},{"name":"%template_filter_args[2]","bnf":[["WS*","\",\"","WS*","template_filter_arg"]],"fragment":true},{"name":"template_filter_args","bnf":[["template_filter_arg","%template_filter_args[2]*"]]},{"name":"template_filter_arg","bnf":[["value"],["template_value"]]},{"name":"
|
|
1
|
+
module.exports=[{"name":"TEMPLATE_BEGIN","bnf":[["\"${\""]]},{"name":"TEMPLATE_END","bnf":[["\"}\""]]},{"name":"PIPE","bnf":[["\"|\""]]},{"name":"%IDENT[2]","bnf":[[/[A-Za-z0-9_]/]]},{"name":"IDENT","bnf":[[/[A-Za-z_]/,"%IDENT[2]*"]]},{"name":"DOT","bnf":[["\".\""]]},{"name":"template_value","bnf":[["TEMPLATE_BEGIN","WS*","template_expr","WS*","TEMPLATE_END"]]},{"name":"%template_expr[2]","bnf":[["WS*","template_pipe","WS*","template_filter_call"]],"fragment":true},{"name":"template_expr","bnf":[["template_path","%template_expr[2]*"]]},{"name":"template_pipe","bnf":[["PIPE"]]},{"name":"%template_path[2]","bnf":[["WS*","DOT","WS*","IDENT"]],"fragment":true},{"name":"template_path","bnf":[["IDENT","%template_path[2]*"]]},{"name":"%template_filter_call[2]","bnf":[["WS*","BEGIN_ARGUMENT","WS*","template_filter_args?","WS*","END_ARGUMENT"]],"fragment":true},{"name":"template_filter_call","bnf":[["template_filter_name","%template_filter_call[2]?"]]},{"name":"template_filter_name","bnf":[["IDENT"]]},{"name":"%template_filter_args[2]","bnf":[["WS*","\",\"","WS*","template_filter_arg"]],"fragment":true},{"name":"template_filter_args","bnf":[["template_filter_arg","%template_filter_args[2]*"]]},{"name":"template_filter_arg","bnf":[["value"],["template_value"]]},{"name":"string_atom","bnf":[["string"]]},{"name":"boolean_atom","bnf":[["false"],["true"]]},{"name":"time_value_atom","bnf":[["number_tod"]]},{"name":"object_atom","bnf":[["json_object"]]},{"name":"json_value","bnf":[["string"],["number"],["false"],["true"],["null"],["json_array"],["json_object"]]},{"name":"json_member","bnf":[["string","NAME_SEPARATOR","json_value"]]},{"name":"%json_object[2][2]","bnf":[["VALUE_SEPARATOR","json_member"]],"fragment":true},{"name":"%json_object[2]","bnf":[["json_member","%json_object[2][2]*"]],"fragment":true},{"name":"json_object","bnf":[["BEGIN_OBJECT","%json_object[2]?","END_OBJECT"]]},{"name":"%json_array[2][2]","bnf":[["VALUE_SEPARATOR","json_value"]],"fragment":true},{"name":"%json_array[2]","bnf":[["json_value","%json_array[2][2]*"]],"fragment":true},{"name":"json_array","bnf":[["BEGIN_ARRAY","%json_array[2]?","END_ARRAY"]]},{"name":"%string_array[2][2]","bnf":[["VALUE_SEPARATOR","string"]],"fragment":true},{"name":"%string_array[2]","bnf":[["string","%string_array[2][2]*"]],"fragment":true},{"name":"string_array","bnf":[["BEGIN_ARRAY","%string_array[2]?","END_ARRAY"]]},{"name":"%number_array[2][2]","bnf":[["VALUE_SEPARATOR","number"]],"fragment":true},{"name":"%number_array[2]","bnf":[["number","%number_array[2][2]*"]],"fragment":true},{"name":"number_array","bnf":[["BEGIN_ARRAY","%number_array[2]?","END_ARRAY"]]},{"name":"%boolean_array[2][2]","bnf":[["VALUE_SEPARATOR","boolean_atom"]],"fragment":true},{"name":"%boolean_array[2]","bnf":[["boolean_atom","%boolean_array[2][2]*"]],"fragment":true},{"name":"boolean_array","bnf":[["BEGIN_ARRAY","%boolean_array[2]?","END_ARRAY"]]},{"name":"%object_array[2][2]","bnf":[["VALUE_SEPARATOR","json_object"]],"fragment":true},{"name":"%object_array[2]","bnf":[["json_object","%object_array[2][2]*"]],"fragment":true},{"name":"object_array","bnf":[["BEGIN_ARRAY","%object_array[2]?","END_ARRAY"]]}]
|
|
@@ -28,7 +28,7 @@ const AllowedTypeMapping = {
|
|
|
28
28
|
'number': ['number_atom', 'math_expr'],
|
|
29
29
|
'boolean': ['boolean_atom', 'boolean_expr'],
|
|
30
30
|
'time period': ['time_period_atom'],
|
|
31
|
-
'time period ago': ['time_period_atom'],
|
|
31
|
+
'time period ago': ['time_period_ago_atom', 'time_period_atom'],
|
|
32
32
|
'time value': ['time_value_atom', 'tod_atom'],
|
|
33
33
|
'number time': ['number_atom'],
|
|
34
34
|
'string array': ['string_array'],
|
|
@@ -49,12 +49,69 @@ for(const rule of TemplateGrammar){
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
const cloneRule = (ruleName) => {
|
|
53
|
+
const idx = extendedGrammar.findIndex(rule => rule.name === ruleName);
|
|
54
|
+
if (idx === -1) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
extendedGrammar[idx] = Object.assign({}, extendedGrammar[idx], {
|
|
59
|
+
bnf: extendedGrammar[idx].bnf.map(alt => Array.isArray(alt) ? alt.slice() : alt)
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
return extendedGrammar[idx];
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const appendAlternative = (ruleName, alternative) => {
|
|
66
|
+
const rule = cloneRule(ruleName);
|
|
67
|
+
if (!rule) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const exists = rule.bnf.some(existing => JSON.stringify(existing) === JSON.stringify(alternative));
|
|
72
|
+
if (!exists) {
|
|
73
|
+
rule.bnf.push(alternative);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const replaceRule = (ruleName, bnf) => {
|
|
78
|
+
const idx = extendedGrammar.findIndex(rule => rule.name === ruleName);
|
|
79
|
+
if (idx === -1) {
|
|
80
|
+
extendedGrammar.push({name: ruleName, bnf});
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
extendedGrammar[idx] = Object.assign({}, extendedGrammar[idx], {
|
|
85
|
+
bnf: bnf.map(alt => alt.slice())
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
appendAlternative('number_atom', ['template_value']);
|
|
90
|
+
appendAlternative('number_time_atom', ['template_value', 'WS+', 'unit']);
|
|
91
|
+
appendAlternative('number_time_atom', ['template_value']);
|
|
92
|
+
appendAlternative('tod_atom', ['template_value']);
|
|
93
|
+
appendAlternative('dow_atom', ['template_value']);
|
|
94
|
+
appendAlternative('between_time_only_atom', ['template_value']);
|
|
95
|
+
appendAlternative('between_tod_only_atom', ['template_value']);
|
|
96
|
+
appendAlternative('string_atom', ['template_value']);
|
|
97
|
+
appendAlternative('boolean_atom', ['template_value']);
|
|
98
|
+
appendAlternative('time_value_atom', ['template_value']);
|
|
99
|
+
appendAlternative('object_atom', ['template_value']);
|
|
100
|
+
appendAlternative('string_array', ['template_value']);
|
|
101
|
+
appendAlternative('number_array', ['template_value']);
|
|
102
|
+
appendAlternative('boolean_array', ['template_value']);
|
|
103
|
+
appendAlternative('object_array', ['template_value']);
|
|
104
|
+
|
|
105
|
+
replaceRule('argument', [
|
|
106
|
+
['number_time_atom', 'WS*'],
|
|
107
|
+
['statement', 'WS*']
|
|
108
|
+
]);
|
|
109
|
+
|
|
110
|
+
replaceRule('simple_result', [
|
|
111
|
+
['fcall'],
|
|
112
|
+
['value'],
|
|
113
|
+
['number_time_atom']
|
|
114
|
+
]);
|
|
58
115
|
|
|
59
116
|
// Export the parser rules for potential external use
|
|
60
117
|
const ParserRules = extendedGrammar;
|
|
@@ -351,6 +408,23 @@ class RuleTemplate {
|
|
|
351
408
|
}
|
|
352
409
|
}
|
|
353
410
|
|
|
411
|
+
const canValidatePreparedRule = errors.length === 0
|
|
412
|
+
&& Array.from(seenVariables).every(varName => {
|
|
413
|
+
const varData = variables[varName];
|
|
414
|
+
return varData
|
|
415
|
+
&& typeof varData === 'object'
|
|
416
|
+
&& Object.prototype.hasOwnProperty.call(varData, 'type')
|
|
417
|
+
&& Object.prototype.hasOwnProperty.call(varData, 'value');
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
if (canValidatePreparedRule) {
|
|
421
|
+
try {
|
|
422
|
+
RuleParser.toAst(this.prepare(variables));
|
|
423
|
+
} catch (error) {
|
|
424
|
+
errors.push(`Prepared rule is invalid: ${error.message}`);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
354
428
|
if (functionBlob && typeof functionBlob.validate === 'function') {
|
|
355
429
|
for (const functionCall of this._extractFunctionCalls()) {
|
|
356
430
|
warnings.push(...functionBlob.validate(functionCall.name, functionCall.arguments));
|
|
@@ -559,12 +633,12 @@ class RuleTemplate {
|
|
|
559
633
|
return value ? 'true' : 'false';
|
|
560
634
|
}
|
|
561
635
|
|
|
562
|
-
if (type === 'time period'
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
return
|
|
636
|
+
if (type === 'time period') {
|
|
637
|
+
return `BETWEEN ${value.from} AND ${value.to}`;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
if (type === 'time period ago') {
|
|
641
|
+
return `${value.ago[0]} ${value.ago[1]} AGO BETWEEN ${value.from} AND ${value.to}`;
|
|
568
642
|
}
|
|
569
643
|
|
|
570
644
|
if (type === 'object' || type === 'string array' || type === 'number array' || type === 'boolean array' || type === 'object array') {
|
|
@@ -13,6 +13,7 @@ const VariableTypes = [
|
|
|
13
13
|
'boolean',
|
|
14
14
|
'object',
|
|
15
15
|
'time period',
|
|
16
|
+
'time period ago',
|
|
16
17
|
'time value',
|
|
17
18
|
'string array',
|
|
18
19
|
'number array',
|
|
@@ -25,6 +26,7 @@ const AllowedTypeMapping = {
|
|
|
25
26
|
'number': ['number_atom', 'math_expr'],
|
|
26
27
|
'boolean': ['boolean_atom', 'boolean_expr'],
|
|
27
28
|
'time period': ['time_period_atom'],
|
|
29
|
+
'time period ago': ['time_period_ago_atom', 'time_period_atom'],
|
|
28
30
|
'time value': ['time_value_atom', 'tod_atom'],
|
|
29
31
|
'string array': ['string_array'],
|
|
30
32
|
'number array': ['number_array'],
|
|
@@ -44,11 +46,69 @@ for(const rule of TemplateGrammar){
|
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
48
|
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
if (
|
|
50
|
-
|
|
51
|
-
}
|
|
49
|
+
const cloneRule = (ruleName) => {
|
|
50
|
+
const idx = extendedGrammar.findIndex(rule => rule.name === ruleName);
|
|
51
|
+
if (idx === -1) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
extendedGrammar[idx] = Object.assign({}, extendedGrammar[idx], {
|
|
56
|
+
bnf: extendedGrammar[idx].bnf.map(alt => Array.isArray(alt) ? alt.slice() : alt)
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return extendedGrammar[idx];
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const appendAlternative = (ruleName, alternative) => {
|
|
63
|
+
const rule = cloneRule(ruleName);
|
|
64
|
+
if (!rule) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const exists = rule.bnf.some(existing => JSON.stringify(existing) === JSON.stringify(alternative));
|
|
69
|
+
if (!exists) {
|
|
70
|
+
rule.bnf.push(alternative);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const replaceRule = (ruleName, bnf) => {
|
|
75
|
+
const idx = extendedGrammar.findIndex(rule => rule.name === ruleName);
|
|
76
|
+
if (idx === -1) {
|
|
77
|
+
extendedGrammar.push({name: ruleName, bnf});
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
extendedGrammar[idx] = Object.assign({}, extendedGrammar[idx], {
|
|
82
|
+
bnf: bnf.map(alt => alt.slice())
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
appendAlternative('number_atom', ['template_value']);
|
|
87
|
+
appendAlternative('number_time_atom', ['template_value', 'WS+', 'unit']);
|
|
88
|
+
appendAlternative('number_time_atom', ['template_value']);
|
|
89
|
+
appendAlternative('tod_atom', ['template_value']);
|
|
90
|
+
appendAlternative('dow_atom', ['template_value']);
|
|
91
|
+
appendAlternative('between_time_only_atom', ['template_value']);
|
|
92
|
+
appendAlternative('between_tod_only_atom', ['template_value']);
|
|
93
|
+
appendAlternative('string_atom', ['template_value']);
|
|
94
|
+
appendAlternative('boolean_atom', ['template_value']);
|
|
95
|
+
appendAlternative('time_value_atom', ['template_value']);
|
|
96
|
+
appendAlternative('object_atom', ['template_value']);
|
|
97
|
+
appendAlternative('string_array', ['template_value']);
|
|
98
|
+
appendAlternative('number_array', ['template_value']);
|
|
99
|
+
appendAlternative('boolean_array', ['template_value']);
|
|
100
|
+
appendAlternative('object_array', ['template_value']);
|
|
101
|
+
|
|
102
|
+
replaceRule('argument', [
|
|
103
|
+
['number_time_atom', 'WS*'],
|
|
104
|
+
['statement', 'WS*']
|
|
105
|
+
]);
|
|
106
|
+
|
|
107
|
+
replaceRule('simple_result', [
|
|
108
|
+
['fcall'],
|
|
109
|
+
['value'],
|
|
110
|
+
['number_time_atom']
|
|
111
|
+
]);
|
|
52
112
|
|
|
53
113
|
// Export the parser rules for potential external use
|
|
54
114
|
const ParserRules = extendedGrammar;
|
|
@@ -374,6 +434,10 @@ class RuleTemplate {
|
|
|
374
434
|
return String(value);
|
|
375
435
|
} else if (type === 'boolean') {
|
|
376
436
|
return value ? 'true' : 'false';
|
|
437
|
+
} else if (type === 'time period') {
|
|
438
|
+
return `BETWEEN ${value.from} AND ${value.to}`;
|
|
439
|
+
} else if (type === 'time period ago') {
|
|
440
|
+
return `${value.ago[0]} ${value.ago[1]} AGO BETWEEN ${value.from} AND ${value.to}`;
|
|
377
441
|
} else {
|
|
378
442
|
// Default behavior - just insert the value as-is
|
|
379
443
|
return String(value);
|
package/src/VariableValidate.js
CHANGED
|
@@ -207,7 +207,7 @@ class VariableValidate {
|
|
|
207
207
|
return null;
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
-
return
|
|
210
|
+
return `BETWEEN ${value.from.trim()} AND ${value.to.trim()}`;
|
|
211
211
|
}
|
|
212
212
|
|
|
213
213
|
static _serializeTimePeriodAgo(value) {
|
|
@@ -224,7 +224,7 @@ class VariableValidate {
|
|
|
224
224
|
return null;
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
return `${
|
|
227
|
+
return `${amount} ${unit.trim()} AGO BETWEEN ${value.from.trim()} AND ${value.to.trim()}`;
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
static _serializeNumberTime(value) {
|
|
@@ -341,7 +341,7 @@ VariableValidate.validators = Object.freeze({
|
|
|
341
341
|
'time period': (value) => VariableValidate._validateWithRule(value, 'time_period_atom', {
|
|
342
342
|
normalize: VariableValidate._serializeTimePeriod,
|
|
343
343
|
emptyMessage: 'Time period variables must be objects with string from/to properties',
|
|
344
|
-
parseMessage: 'Time period variables must serialize to FROM
|
|
344
|
+
parseMessage: 'Time period variables must serialize to BETWEEN FROM AND TO syntax',
|
|
345
345
|
semanticCheck: (rawValue) => {
|
|
346
346
|
const fromError = VariableValidate._validateTimeOfDay(rawValue?.from);
|
|
347
347
|
if (fromError) return `Invalid time period from value: ${fromError}`;
|
|
@@ -355,7 +355,7 @@ VariableValidate.validators = Object.freeze({
|
|
|
355
355
|
'time period ago': (value) => VariableValidate._validateWithRule(value, 'time_period_ago_atom', {
|
|
356
356
|
normalize: VariableValidate._serializeTimePeriodAgo,
|
|
357
357
|
emptyMessage: 'Time period ago variables must be objects with from, to, and ago properties',
|
|
358
|
-
parseMessage: 'Time period ago variables must serialize to
|
|
358
|
+
parseMessage: 'Time period ago variables must serialize to AMOUNT UNIT AGO BETWEEN FROM AND TO syntax',
|
|
359
359
|
semanticCheck: (rawValue) => {
|
|
360
360
|
const fromError = VariableValidate._validateTimeOfDay(rawValue?.from);
|
|
361
361
|
if (fromError) return `Invalid time period ago from value: ${fromError}`;
|