@halleyassist/rule-templater 0.0.17 → 0.0.19
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/README.md +16 -1
- package/dist/rule-templater.browser.js +489 -57
- package/index.d.ts +8 -1
- package/package.json +1 -1
- package/src/GeneralTemplate.js +91 -11
- package/src/RuleTemplate.ebnf.js +0 -9
- package/src/RuleTemplate.js +219 -27
- package/src/RuleTemplate.production.ebnf.js +1 -1
- package/src/RuleTemplate.production.js +219 -27
- package/src/RuleTemplater.production.js +71 -5
- package/src/TemplateFilters.js +88 -0
- package/src/VariableTemplate.js +74 -6
- package/src/VariableValidate.js +11 -8
|
@@ -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': ['
|
|
3883
|
+
'time period ago': ['time_period_ago_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,71 @@ 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('time_period_atom', ['template_value']);
|
|
3952
|
+
appendAlternative('time_period_ago_atom', ['template_value']);
|
|
3953
|
+
appendAlternative('object_atom', ['template_value']);
|
|
3954
|
+
appendAlternative('string_array', ['template_value']);
|
|
3955
|
+
appendAlternative('number_array', ['template_value']);
|
|
3956
|
+
appendAlternative('boolean_array', ['template_value']);
|
|
3957
|
+
appendAlternative('object_array', ['template_value']);
|
|
3958
|
+
|
|
3959
|
+
replaceRule('argument', [
|
|
3960
|
+
['number_time_atom', 'WS*'],
|
|
3961
|
+
['statement', 'WS*']
|
|
3962
|
+
]);
|
|
3963
|
+
|
|
3964
|
+
replaceRule('simple_result', [
|
|
3965
|
+
['fcall'],
|
|
3966
|
+
['number_time_atom'],
|
|
3967
|
+
['value']
|
|
3968
|
+
]);
|
|
3761
3969
|
|
|
3762
3970
|
// Export the parser rules for potential external use
|
|
3763
3971
|
const ParserRules = extendedGrammar;
|
|
@@ -3888,11 +4096,13 @@ class RuleTemplate {
|
|
|
3888
4096
|
|
|
3889
4097
|
// Extract filters
|
|
3890
4098
|
const filters = [];
|
|
4099
|
+
const filterCalls = [];
|
|
3891
4100
|
for (const child of templateExpr.children || []) {
|
|
3892
4101
|
if (child.type === 'template_filter_call') {
|
|
3893
|
-
const
|
|
3894
|
-
if (
|
|
3895
|
-
filters.push(
|
|
4102
|
+
const filterCall = this._extractFilterCall(child);
|
|
4103
|
+
if (filterCall) {
|
|
4104
|
+
filters.push(filterCall.name);
|
|
4105
|
+
filterCalls.push(filterCall);
|
|
3896
4106
|
}
|
|
3897
4107
|
}
|
|
3898
4108
|
}
|
|
@@ -3901,18 +4111,84 @@ class RuleTemplate {
|
|
|
3901
4111
|
const start = node.start;
|
|
3902
4112
|
const end = node.end;
|
|
3903
4113
|
|
|
3904
|
-
return { name, filters, start, end };
|
|
4114
|
+
return { name, filters, filterCalls, start, end };
|
|
3905
4115
|
}
|
|
3906
4116
|
|
|
3907
4117
|
/**
|
|
3908
|
-
* Extract filter
|
|
4118
|
+
* Extract filter call from template_filter_call node
|
|
3909
4119
|
* @private
|
|
3910
4120
|
*/
|
|
3911
|
-
|
|
4121
|
+
_extractFilterCall(node) {
|
|
3912
4122
|
const filterNameNode = node.children?.find(c => c.type === 'template_filter_name');
|
|
3913
4123
|
if (!filterNameNode || !filterNameNode.text) return null;
|
|
3914
|
-
|
|
3915
|
-
|
|
4124
|
+
|
|
4125
|
+
const argsNode = node.children?.find(c => c.type === 'template_filter_args');
|
|
4126
|
+
|
|
4127
|
+
return {
|
|
4128
|
+
name: filterNameNode.text.trim(),
|
|
4129
|
+
args: this._extractFilterArgs(argsNode)
|
|
4130
|
+
};
|
|
4131
|
+
}
|
|
4132
|
+
|
|
4133
|
+
_extractFilterArgs(node) {
|
|
4134
|
+
if (!node || !Array.isArray(node.children)) {
|
|
4135
|
+
return [];
|
|
4136
|
+
}
|
|
4137
|
+
|
|
4138
|
+
return node.children
|
|
4139
|
+
.filter(child => child.type === 'template_filter_arg')
|
|
4140
|
+
.map(child => this._extractFilterArgValue(child));
|
|
4141
|
+
}
|
|
4142
|
+
|
|
4143
|
+
_extractFilterArgValue(node) {
|
|
4144
|
+
if (!node || !Array.isArray(node.children) || node.children.length === 0) {
|
|
4145
|
+
return this._normalizeFilterArgText(node?.text?.trim() || '');
|
|
4146
|
+
}
|
|
4147
|
+
|
|
4148
|
+
const child = node.children[0];
|
|
4149
|
+
if (!child) {
|
|
4150
|
+
return this._normalizeFilterArgText(node.text?.trim() || '');
|
|
4151
|
+
}
|
|
4152
|
+
|
|
4153
|
+
if (child.type === 'value' && Array.isArray(child.children) && child.children.length > 0) {
|
|
4154
|
+
return this._extractFilterArgValue(child);
|
|
4155
|
+
}
|
|
4156
|
+
|
|
4157
|
+
if (child.type === 'string') {
|
|
4158
|
+
try {
|
|
4159
|
+
return JSON.parse(child.text);
|
|
4160
|
+
} catch (error) {
|
|
4161
|
+
return this._normalizeFilterArgText(child.text);
|
|
4162
|
+
}
|
|
4163
|
+
}
|
|
4164
|
+
|
|
4165
|
+
if (child.type === 'number') {
|
|
4166
|
+
return Number(child.text);
|
|
4167
|
+
}
|
|
4168
|
+
|
|
4169
|
+
if (child.type === 'true') {
|
|
4170
|
+
return true;
|
|
4171
|
+
}
|
|
4172
|
+
|
|
4173
|
+
if (child.type === 'false') {
|
|
4174
|
+
return false;
|
|
4175
|
+
}
|
|
4176
|
+
|
|
4177
|
+
if (child.type === 'null') {
|
|
4178
|
+
return null;
|
|
4179
|
+
}
|
|
4180
|
+
|
|
4181
|
+
return this._normalizeFilterArgText(child.text?.trim() || node.text?.trim() || '');
|
|
4182
|
+
}
|
|
4183
|
+
|
|
4184
|
+
_normalizeFilterArgText(text) {
|
|
4185
|
+
const normalizedText = String(text).trim();
|
|
4186
|
+
|
|
4187
|
+
if ((normalizedText.startsWith('"') && normalizedText.endsWith('"')) || (normalizedText.startsWith("'") && normalizedText.endsWith("'"))) {
|
|
4188
|
+
return normalizedText.slice(1, -1);
|
|
4189
|
+
}
|
|
4190
|
+
|
|
4191
|
+
return normalizedText;
|
|
3916
4192
|
}
|
|
3917
4193
|
|
|
3918
4194
|
/**
|
|
@@ -3932,10 +4208,31 @@ class RuleTemplate {
|
|
|
3932
4208
|
|
|
3933
4209
|
const errors = [];
|
|
3934
4210
|
const warnings = [];
|
|
3935
|
-
const extractedVars = this.
|
|
4211
|
+
const extractedVars = this._extractTemplateVariables();
|
|
4212
|
+
const seenVariables = new Set();
|
|
4213
|
+
const seenFilterErrors = new Set();
|
|
3936
4214
|
|
|
3937
4215
|
for (const varInfo of extractedVars) {
|
|
3938
4216
|
const varName = varInfo.name;
|
|
4217
|
+
|
|
4218
|
+
for (const filter of (varInfo.filterCalls || varInfo.filters || [])) {
|
|
4219
|
+
const filterName = typeof filter === 'string' ? filter : filter?.name;
|
|
4220
|
+
if (filterName && TemplateFilters[filterName]) {
|
|
4221
|
+
continue;
|
|
4222
|
+
}
|
|
4223
|
+
|
|
4224
|
+
const errorMessage = `Unknown filter '${filterName || filter}' for variable '${varName}'`;
|
|
4225
|
+
if (!seenFilterErrors.has(errorMessage)) {
|
|
4226
|
+
errors.push(errorMessage);
|
|
4227
|
+
seenFilterErrors.add(errorMessage);
|
|
4228
|
+
}
|
|
4229
|
+
}
|
|
4230
|
+
|
|
4231
|
+
if (seenVariables.has(varName)) {
|
|
4232
|
+
continue;
|
|
4233
|
+
}
|
|
4234
|
+
|
|
4235
|
+
seenVariables.add(varName);
|
|
3939
4236
|
|
|
3940
4237
|
// Check if variable is provided
|
|
3941
4238
|
if (!variables.hasOwnProperty(varName)) {
|
|
@@ -3965,6 +4262,23 @@ class RuleTemplate {
|
|
|
3965
4262
|
}
|
|
3966
4263
|
}
|
|
3967
4264
|
|
|
4265
|
+
const canValidatePreparedRule = errors.length === 0
|
|
4266
|
+
&& Array.from(seenVariables).every(varName => {
|
|
4267
|
+
const varData = variables[varName];
|
|
4268
|
+
return varData
|
|
4269
|
+
&& typeof varData === 'object'
|
|
4270
|
+
&& Object.prototype.hasOwnProperty.call(varData, 'type')
|
|
4271
|
+
&& Object.prototype.hasOwnProperty.call(varData, 'value');
|
|
4272
|
+
});
|
|
4273
|
+
|
|
4274
|
+
if (canValidatePreparedRule) {
|
|
4275
|
+
try {
|
|
4276
|
+
RuleParser.toAst(this.prepare(variables));
|
|
4277
|
+
} catch (error) {
|
|
4278
|
+
errors.push(`Prepared rule is invalid: ${error.message}`);
|
|
4279
|
+
}
|
|
4280
|
+
}
|
|
4281
|
+
|
|
3968
4282
|
if (functionBlob && typeof functionBlob.validate === 'function') {
|
|
3969
4283
|
for (const functionCall of this._extractFunctionCalls()) {
|
|
3970
4284
|
warnings.push(...functionBlob.validate(functionCall.name, functionCall.arguments));
|
|
@@ -4008,6 +4322,30 @@ class RuleTemplate {
|
|
|
4008
4322
|
return functionCalls;
|
|
4009
4323
|
}
|
|
4010
4324
|
|
|
4325
|
+
_extractTemplateVariables() {
|
|
4326
|
+
const variables = [];
|
|
4327
|
+
|
|
4328
|
+
const traverse = (node) => {
|
|
4329
|
+
if (!node) return;
|
|
4330
|
+
|
|
4331
|
+
if (node.type === 'template_value') {
|
|
4332
|
+
const variableInfo = this._extractVariableFromNode(node);
|
|
4333
|
+
if (variableInfo) {
|
|
4334
|
+
variables.push(variableInfo);
|
|
4335
|
+
}
|
|
4336
|
+
}
|
|
4337
|
+
|
|
4338
|
+
if (node.children) {
|
|
4339
|
+
for (const child of node.children) {
|
|
4340
|
+
traverse(child);
|
|
4341
|
+
}
|
|
4342
|
+
}
|
|
4343
|
+
};
|
|
4344
|
+
|
|
4345
|
+
traverse(this.ast);
|
|
4346
|
+
return variables;
|
|
4347
|
+
}
|
|
4348
|
+
|
|
4011
4349
|
/**
|
|
4012
4350
|
* Prepare the template by replacing variables with their values
|
|
4013
4351
|
* Rebuilds from AST by iterating through children
|
|
@@ -4110,12 +4448,15 @@ class RuleTemplate {
|
|
|
4110
4448
|
|
|
4111
4449
|
// Apply filters if present
|
|
4112
4450
|
if (templateInfo.filters && templateInfo.filters.length > 0) {
|
|
4113
|
-
for (const
|
|
4114
|
-
|
|
4115
|
-
|
|
4451
|
+
for (const filter of (templateInfo.filterCalls || templateInfo.filters)) {
|
|
4452
|
+
const filterName = typeof filter === 'string' ? filter : filter?.name;
|
|
4453
|
+
const filterArgs = typeof filter === 'string' ? [] : (Array.isArray(filter?.args) ? filter.args : []);
|
|
4454
|
+
|
|
4455
|
+
if (!filterName || !TemplateFilters[filterName]) {
|
|
4456
|
+
throw new Error(`Unknown filter '${filterName || filter}'`);
|
|
4116
4457
|
}
|
|
4117
|
-
|
|
4118
|
-
TemplateFilters[filterName](varData);
|
|
4458
|
+
|
|
4459
|
+
TemplateFilters[filterName](varData, ...filterArgs);
|
|
4119
4460
|
}
|
|
4120
4461
|
}
|
|
4121
4462
|
|
|
@@ -4146,12 +4487,12 @@ class RuleTemplate {
|
|
|
4146
4487
|
return value ? 'true' : 'false';
|
|
4147
4488
|
}
|
|
4148
4489
|
|
|
4149
|
-
if (type === 'time period'
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
return
|
|
4490
|
+
if (type === 'time period') {
|
|
4491
|
+
return `BETWEEN ${value.from} AND ${value.to}`;
|
|
4492
|
+
}
|
|
4493
|
+
|
|
4494
|
+
if (type === 'time period ago') {
|
|
4495
|
+
return `${value.ago[0]} ${value.ago[1]} AGO BETWEEN ${value.from} AND ${value.to}`;
|
|
4155
4496
|
}
|
|
4156
4497
|
|
|
4157
4498
|
if (type === 'object' || type === 'string array' || type === 'number array' || type === 'boolean array' || type === 'object array') {
|
|
@@ -4193,6 +4534,31 @@ module.exports = RuleTemplate;
|
|
|
4193
4534
|
Template filters are functions that transform variable values.
|
|
4194
4535
|
They are applied in the template syntax as ${variable|filter} or ${variable|filter1|filter2}
|
|
4195
4536
|
*/
|
|
4537
|
+
const HUMANISE_TIME_UNITS = [
|
|
4538
|
+
{ name: 'year', seconds: 31536000, aliases: ['year', 'years', 'yr', 'yrs', 'y'] },
|
|
4539
|
+
{ name: 'month', seconds: 2592000, aliases: ['month', 'months', 'mo', 'mos'] },
|
|
4540
|
+
{ name: 'week', seconds: 604800, aliases: ['week', 'weeks', 'wk', 'wks', 'w'] },
|
|
4541
|
+
{ name: 'day', seconds: 86400, aliases: ['day', 'days', 'd'] },
|
|
4542
|
+
{ name: 'hour', seconds: 3600, aliases: ['hour', 'hours', 'hr', 'hrs', 'h'] },
|
|
4543
|
+
{ name: 'minute', seconds: 60, aliases: ['minute', 'minutes', 'min', 'mins'] },
|
|
4544
|
+
{ name: 'second', seconds: 1, aliases: ['second', 'seconds', 'sec', 'secs', 's'] }
|
|
4545
|
+
];
|
|
4546
|
+
|
|
4547
|
+
const getHumaniseTimeUnit = minUnit => {
|
|
4548
|
+
if (minUnit === null || minUnit === undefined || minUnit === '') {
|
|
4549
|
+
return null;
|
|
4550
|
+
}
|
|
4551
|
+
|
|
4552
|
+
const normalizedMinUnit = String(minUnit).trim().toLowerCase();
|
|
4553
|
+
const unit = HUMANISE_TIME_UNITS.find(candidate => candidate.aliases.includes(normalizedMinUnit));
|
|
4554
|
+
|
|
4555
|
+
if (!unit) {
|
|
4556
|
+
throw new Error(`Unknown humanise_time min_unit \"${minUnit}\"`);
|
|
4557
|
+
}
|
|
4558
|
+
|
|
4559
|
+
return unit;
|
|
4560
|
+
};
|
|
4561
|
+
|
|
4196
4562
|
const TemplateFilters = {
|
|
4197
4563
|
// Convert value to JSON string representation
|
|
4198
4564
|
string: varData => {
|
|
@@ -4316,6 +4682,69 @@ const TemplateFilters = {
|
|
|
4316
4682
|
|
|
4317
4683
|
},
|
|
4318
4684
|
|
|
4685
|
+
humanise_list: (varData, joiner = 'and') => {
|
|
4686
|
+
if (typeof varData.value === 'string') {
|
|
4687
|
+
varData.type = 'string';
|
|
4688
|
+
return;
|
|
4689
|
+
}
|
|
4690
|
+
|
|
4691
|
+
if (!Array.isArray(varData.value)) {
|
|
4692
|
+
varData.value = String(varData.value);
|
|
4693
|
+
varData.type = 'string';
|
|
4694
|
+
return;
|
|
4695
|
+
}
|
|
4696
|
+
|
|
4697
|
+
const items = varData.value.map(item => String(item));
|
|
4698
|
+
|
|
4699
|
+
if (items.length === 0) {
|
|
4700
|
+
varData.value = '';
|
|
4701
|
+
} else if (items.length === 1) {
|
|
4702
|
+
[varData.value] = items;
|
|
4703
|
+
} else if (items.length === 2) {
|
|
4704
|
+
varData.value = `${items[0]} ${joiner} ${items[1]}`;
|
|
4705
|
+
} else {
|
|
4706
|
+
varData.value = `${items.slice(0, -1).join(', ')} ${joiner} ${items[items.length - 1]}`;
|
|
4707
|
+
}
|
|
4708
|
+
|
|
4709
|
+
varData.type = 'string';
|
|
4710
|
+
|
|
4711
|
+
},
|
|
4712
|
+
|
|
4713
|
+
humanise_time: (varData, minUnit = null) => {
|
|
4714
|
+
const rawSeconds = Number(varData.value);
|
|
4715
|
+
|
|
4716
|
+
if (isNaN(rawSeconds)) {
|
|
4717
|
+
throw new Error(`Value "${varData.value}" cannot be converted to seconds`);
|
|
4718
|
+
}
|
|
4719
|
+
|
|
4720
|
+
const isNegative = rawSeconds < 0;
|
|
4721
|
+
const absoluteSeconds = Math.abs(rawSeconds);
|
|
4722
|
+
const minimumUnit = getHumaniseTimeUnit(minUnit);
|
|
4723
|
+
const minimumUnitIndex = minimumUnit
|
|
4724
|
+
? HUMANISE_TIME_UNITS.findIndex(unit => unit.name === minimumUnit.name)
|
|
4725
|
+
: HUMANISE_TIME_UNITS.length - 1;
|
|
4726
|
+
const candidateUnits = HUMANISE_TIME_UNITS.slice(0, minimumUnitIndex + 1);
|
|
4727
|
+
let selectedUnit = candidateUnits.find(unit => absoluteSeconds % unit.seconds === 0);
|
|
4728
|
+
let quantity;
|
|
4729
|
+
|
|
4730
|
+
if (selectedUnit) {
|
|
4731
|
+
quantity = absoluteSeconds / selectedUnit.seconds;
|
|
4732
|
+
} else if (minimumUnit) {
|
|
4733
|
+
selectedUnit = minimumUnit;
|
|
4734
|
+
quantity = Math.floor(absoluteSeconds / selectedUnit.seconds);
|
|
4735
|
+
} else {
|
|
4736
|
+
selectedUnit = HUMANISE_TIME_UNITS[HUMANISE_TIME_UNITS.length - 1];
|
|
4737
|
+
quantity = absoluteSeconds;
|
|
4738
|
+
}
|
|
4739
|
+
|
|
4740
|
+
const signedQuantity = isNegative ? -quantity : quantity;
|
|
4741
|
+
const label = Math.abs(signedQuantity) === 1 ? selectedUnit.name : `${selectedUnit.name}s`;
|
|
4742
|
+
|
|
4743
|
+
varData.value = `${signedQuantity} ${label}`;
|
|
4744
|
+
varData.type = 'string';
|
|
4745
|
+
|
|
4746
|
+
},
|
|
4747
|
+
|
|
4319
4748
|
// Extract start time from time period/time period ago as time value
|
|
4320
4749
|
time_start: varData => {
|
|
4321
4750
|
if (varData.type === 'time period' || varData.type === 'time period ago') {
|
|
@@ -4490,12 +4919,15 @@ class VariableValidate {
|
|
|
4490
4919
|
throw new Error('Variable data filters must be an array');
|
|
4491
4920
|
}
|
|
4492
4921
|
|
|
4493
|
-
for (const
|
|
4494
|
-
|
|
4495
|
-
|
|
4922
|
+
for (const filter of normalizedVarData.filters) {
|
|
4923
|
+
const filterName = typeof filter === 'string' ? filter : filter?.name;
|
|
4924
|
+
const filterArgs = typeof filter === 'string' ? [] : (Array.isArray(filter?.args) ? filter.args : []);
|
|
4925
|
+
|
|
4926
|
+
if (!filterName || !TemplateFilters[filterName]) {
|
|
4927
|
+
throw new Error(`Unknown filter '${filterName || filter}'`);
|
|
4496
4928
|
}
|
|
4497
4929
|
|
|
4498
|
-
TemplateFilters[filterName](normalizedVarData);
|
|
4930
|
+
TemplateFilters[filterName](normalizedVarData, ...filterArgs);
|
|
4499
4931
|
}
|
|
4500
4932
|
|
|
4501
4933
|
return normalizedVarData;
|
|
@@ -4555,7 +4987,7 @@ class VariableValidate {
|
|
|
4555
4987
|
return null;
|
|
4556
4988
|
}
|
|
4557
4989
|
|
|
4558
|
-
return
|
|
4990
|
+
return `BETWEEN ${value.from.trim()} AND ${value.to.trim()}`;
|
|
4559
4991
|
}
|
|
4560
4992
|
|
|
4561
4993
|
static _serializeTimePeriodAgo(value) {
|
|
@@ -4572,7 +5004,7 @@ class VariableValidate {
|
|
|
4572
5004
|
return null;
|
|
4573
5005
|
}
|
|
4574
5006
|
|
|
4575
|
-
return `${
|
|
5007
|
+
return `${amount} ${unit.trim()} AGO BETWEEN ${value.from.trim()} AND ${value.to.trim()}`;
|
|
4576
5008
|
}
|
|
4577
5009
|
|
|
4578
5010
|
static _serializeNumberTime(value) {
|
|
@@ -4689,7 +5121,7 @@ VariableValidate.validators = Object.freeze({
|
|
|
4689
5121
|
'time period': (value) => VariableValidate._validateWithRule(value, 'time_period_atom', {
|
|
4690
5122
|
normalize: VariableValidate._serializeTimePeriod,
|
|
4691
5123
|
emptyMessage: 'Time period variables must be objects with string from/to properties',
|
|
4692
|
-
parseMessage: 'Time period variables must serialize to FROM
|
|
5124
|
+
parseMessage: 'Time period variables must serialize to BETWEEN FROM AND TO syntax',
|
|
4693
5125
|
semanticCheck: (rawValue) => {
|
|
4694
5126
|
const fromError = VariableValidate._validateTimeOfDay(rawValue?.from);
|
|
4695
5127
|
if (fromError) return `Invalid time period from value: ${fromError}`;
|
|
@@ -4703,7 +5135,7 @@ VariableValidate.validators = Object.freeze({
|
|
|
4703
5135
|
'time period ago': (value) => VariableValidate._validateWithRule(value, 'time_period_ago_atom', {
|
|
4704
5136
|
normalize: VariableValidate._serializeTimePeriodAgo,
|
|
4705
5137
|
emptyMessage: 'Time period ago variables must be objects with from, to, and ago properties',
|
|
4706
|
-
parseMessage: 'Time period ago variables must serialize to
|
|
5138
|
+
parseMessage: 'Time period ago variables must serialize to AMOUNT UNIT AGO BETWEEN FROM AND TO syntax',
|
|
4707
5139
|
semanticCheck: (rawValue) => {
|
|
4708
5140
|
const fromError = VariableValidate._validateTimeOfDay(rawValue?.from);
|
|
4709
5141
|
if (fromError) return `Invalid time period ago from value: ${fromError}`;
|