Comparing version 0.9.4 to 0.9.5
{ | ||
"name": "ael", | ||
"version": "0.9.4", | ||
"version": "0.9.5", | ||
"description": "Advanced Expression Language", | ||
@@ -5,0 +5,0 @@ "keywords": [ "expression", "language", "parser", "evaluator" ], |
128
README.md
@@ -38,19 +38,43 @@ | ||
$ cat sample.js | ||
const AEL = require("..") | ||
const AEL = require("ael") | ||
const ael = new AEL({ trace: (msg) => console.log(msg) }) | ||
const ael = new AEL({ | ||
trace: (msg) => console.log(msg) | ||
}) | ||
const expr = `foo.quux =~ /ux$/ && foo.bar.a == 1` | ||
const data = { | ||
foo: { | ||
bar: { a: 1, b: 2, c: 3 }, | ||
baz: [ "a", "b", "c", "d", "e" ], | ||
quux: "quux" | ||
} | ||
session: { | ||
user: { | ||
login: "rse", | ||
email: "rse@engelschall.com" | ||
}, | ||
tokens: [ | ||
"455c3026-50cf-11eb-8d93-7085c287160d", | ||
"4600b07e-50cf-11eb-8d57-7085c287160d" | ||
] | ||
}, | ||
} | ||
const expr = ` | ||
grant =~ /^login:(.+)$/ ? session.user.login =~ $1 : | ||
grant =~ /^email:(.+)$/ ? session.user.email =~ $1 : | ||
grant =~ /^token:(.+)$/ ? session.tokens >= $1 : false | ||
` | ||
const grants = [ | ||
"login:^(?:rse|foo|bar)$", | ||
"email:^.+@engelschall\\.com$", | ||
"email:^.+@example\\.com$", | ||
"token:4600b07e-50cf-11eb-8d57-7085c287160d" | ||
] | ||
try { | ||
const result = ael.evaluate(expr, data) | ||
console.log("RESULT", result) | ||
let granted = false | ||
for (const grant of grants) { | ||
if (ael.evaluate(expr, { ...data, grant })) { | ||
granted = true | ||
break | ||
} | ||
} | ||
console.log("GRANTED", granted) | ||
} | ||
@@ -63,28 +87,47 @@ catch (ex) { | ||
compile: +---(expression string)--------------------------------------------------------------------------------- | ||
compile: | foo.quux =~ /ux$/ && foo.bar.a == 1 | ||
compile: | | ||
compile: | grant =~ /^login:(.+)$/ ? session.user.login =~ $1 : | ||
compile: | grant =~ /^email:(.+)$/ ? session.user.email =~ $1 : | ||
compile: | grant =~ /^token:(.+)$/ ? session.tokens >= $1 : false | ||
compile: +---(abstract syntax tree)------------------------------------------------------------------------------ | ||
compile: | Logical (op: "&&", expr: "foo.quux =~ /ux$/ && foo.bar.a == 1") [1,1] | ||
compile: | ├── Relational (op: "=~") [1,1] | ||
compile: | │ ├── Select [1,1] | ||
compile: | │ │ ├── Variable (id: "foo") [1,1] | ||
compile: | │ │ └── SelectItem [1,4] | ||
compile: | │ │ └── Identifier (id: "quux") [1,5] | ||
compile: | │ └── LiteralRegExp (value: /ux$/) [1,13] | ||
compile: | └── Relational (op: "==") [1,22] | ||
compile: | ├── Select [1,22] | ||
compile: | │ ├── Variable (id: "foo") [1,22] | ||
compile: | │ ├── SelectItem [1,25] | ||
compile: | │ │ └── Identifier (id: "bar") [1,26] | ||
compile: | │ └── SelectItem [1,29] | ||
compile: | │ └── Identifier (id: "a") [1,30] | ||
compile: | └── LiteralNumber (value: 1) [1,35] | ||
compile: | ConditionalTernary (expr: "\n grant =~ /^login:(.+)$/ ? session.user.login =~ $1 :\n grant =~ /^email:(.+)$/ ? session.user.email =~ $1 :\n grant =~ /^token:(.+)$/ ? session.tokens >= $1 : false\n") [2,5] | ||
compile: | ├── Relational (op: "=~") [2,5] | ||
compile: | │ ├── Variable (id: "grant") [2,5] | ||
compile: | │ └── LiteralRegExp (value: /^login:(.+)$/) [2,14] | ||
compile: | ├── Relational (op: "=~") [2,31] | ||
compile: | │ ├── Select [2,31] | ||
compile: | │ │ ├── Variable (id: "session") [2,31] | ||
compile: | │ │ ├── SelectItem [2,38] | ||
compile: | │ │ │ └── Identifier (id: "user") [2,39] | ||
compile: | │ │ └── SelectItem [2,43] | ||
compile: | │ │ └── Identifier (id: "login") [2,44] | ||
compile: | │ └── Variable (id: "$1") [2,53] | ||
compile: | └── ConditionalTernary [3,5] | ||
compile: | ├── Relational (op: "=~") [3,5] | ||
compile: | │ ├── Variable (id: "grant") [3,5] | ||
compile: | │ └── LiteralRegExp (value: /^email:(.+)$/) [3,14] | ||
compile: | ├── Relational (op: "=~") [3,31] | ||
compile: | │ ├── Select [3,31] | ||
compile: | │ │ ├── Variable (id: "session") [3,31] | ||
compile: | │ │ ├── SelectItem [3,38] | ||
compile: | │ │ │ └── Identifier (id: "user") [3,39] | ||
compile: | │ │ └── SelectItem [3,43] | ||
compile: | │ │ └── Identifier (id: "email") [3,44] | ||
compile: | │ └── Variable (id: "$1") [3,53] | ||
compile: | └── ConditionalTernary [4,5] | ||
compile: | ├── Relational (op: "=~") [4,5] | ||
compile: | │ ├── Variable (id: "grant") [4,5] | ||
compile: | │ └── LiteralRegExp (value: /^token:(.+)$/) [4,14] | ||
compile: | ├── Relational (op: ">=") [4,31] | ||
compile: | │ ├── Select [4,31] | ||
compile: | │ │ ├── Variable (id: "session") [4,31] | ||
compile: | │ │ └── SelectItem [4,38] | ||
compile: | │ │ └── Identifier (id: "tokens") [4,39] | ||
compile: | │ └── Variable (id: "$1") [4,53] | ||
compile: | └── LiteralValue (value: false) [4,58] | ||
execute: +---(evaluation recursion tree)------------------------------------------------------------------------- | ||
execute: | Logical { | ||
execute: | ConditionalTernary { | ||
execute: | Relational { | ||
execute: | Select { | ||
execute: | Variable { | ||
execute: | }: {"bar":{"a":1,"b":2,"c":3},"baz":["a","b... | ||
execute: | Identifier { | ||
execute: | }: "quux" | ||
execute: | }: "quux" | ||
execute: | Variable { | ||
execute: | }: "login:^(?:rse|foo|bar)$" | ||
execute: | LiteralRegExp { | ||
@@ -96,13 +139,13 @@ execute: | }: {} | ||
execute: | Variable { | ||
execute: | }: {"bar":{"a":1,"b":2,"c":3},"baz":["a","b... | ||
execute: | }: {"user":{"login":"rse","email":"rse@enge... | ||
execute: | Identifier { | ||
execute: | }: "bar" | ||
execute: | }: "user" | ||
execute: | Identifier { | ||
execute: | }: "a" | ||
execute: | }: 1 | ||
execute: | LiteralNumber { | ||
execute: | }: 1 | ||
execute: | }: "login" | ||
execute: | }: "rse" | ||
execute: | Variable { | ||
execute: | }: "^(?:rse|foo|bar)$" | ||
execute: | }: true | ||
execute: | }: true | ||
RESULT true | ||
GRANTED true | ||
``` | ||
@@ -145,3 +188,3 @@ | ||
variable ::= id | ||
literal ::= array | object | string | regexp | number | value | ||
literal ::= array | object | template | string | regexp | number | value | ||
parenthesis ::= "(" expr ")" | ||
@@ -155,2 +198,3 @@ | ||
| id | ||
template ::= "`" ("${" expr "}" / ("\\`"|.))* "`" | ||
string ::= /"(\\"|.)*"/ | ||
@@ -157,0 +201,0 @@ | /'(\\'|.)*'/ |
const AEL = require("..") | ||
const ael = new AEL({ trace: (msg) => console.log(msg) }) | ||
const ael = new AEL({ | ||
trace: (msg) => console.log(msg) | ||
}) | ||
const expr = `foo.quux =~ /ux$/ && foo.bar.a == 1` | ||
const data = { | ||
foo: { | ||
bar: { a: 1, b: 2, c: 3 }, | ||
baz: [ "a", "b", "c", "d", "e" ], | ||
quux: "quux" | ||
} | ||
session: { | ||
user: { | ||
login: "rse", | ||
email: "rse@engelschall.com" | ||
}, | ||
tokens: [ | ||
"455c3026-50cf-11eb-8d93-7085c287160d", | ||
"4600b07e-50cf-11eb-8d57-7085c287160d" | ||
] | ||
}, | ||
} | ||
const expr = ` | ||
grant =~ /^login:(.+)$/ ? session.user.login =~ $1 : | ||
grant =~ /^email:(.+)$/ ? session.user.email =~ $1 : | ||
grant =~ /^token:(.+)$/ ? session.tokens >= $1 : false | ||
` | ||
const grants = [ | ||
"login:^(?:rse|foo|bar)$", | ||
"email:^.+@engelschall\\.com$", | ||
"email:^.+@example\\.com$", | ||
"token:4600b07e-50cf-11eb-8d57-7085c287160d" | ||
] | ||
try { | ||
const result = ael.evaluate(expr, data) | ||
console.log("RESULT", result) | ||
let granted = false | ||
for (const grant of grants) { | ||
if (ael.evaluate(expr, { ...data, grant })) { | ||
granted = true | ||
break | ||
} | ||
} | ||
console.log("GRANTED", granted) | ||
} | ||
@@ -20,0 +44,0 @@ catch (ex) { |
@@ -69,2 +69,3 @@ /* | ||
case "LiteralObjectItem": return this.evalLiteralObjectItem(N) | ||
case "LiteralTemplate": return this.evalLiteralTemplate(N) | ||
case "LiteralString": return this.evalLiteralString(N) | ||
@@ -163,2 +164,3 @@ case "LiteralRegExp": return this.evalLiteralRegExp(N) | ||
let result | ||
let match | ||
switch (N.get("op")) { | ||
@@ -280,6 +282,20 @@ case "==": | ||
case "=~": | ||
result = util.coerce(v1, "string").match(util.coerce(v2, "regexp")) !== null | ||
match = util.coerce(v1, "string").match(util.coerce(v2, "regexp")) | ||
result = (match !== null) | ||
for (let i = 0; i <= 9; i++) { | ||
if (match !== null && i < match.length) | ||
this.state[`$${i}`] = match[i] | ||
else | ||
delete this.state[`$${i}`] | ||
} | ||
break | ||
case "!~": | ||
result = util.coerce(v1, "string").match(util.coerce(v2, "regexp")) === null | ||
match = util.coerce(v1, "string").match(util.coerce(v2, "regexp")) | ||
result = (match === null) | ||
for (let i = 0; i <= 9; i++) { | ||
if (match !== null && i < match.length) | ||
this.state[`$${i}`] = match[i] | ||
else | ||
delete this.state[`$${i}`] | ||
} | ||
break | ||
@@ -516,2 +532,12 @@ } | ||
/* evaluate template literal */ | ||
evalLiteralTemplate (N) { | ||
this.traceBegin(N) | ||
const result = N.childs() | ||
.map((child) => this.eval(child)) | ||
.join("") | ||
this.traceEnd(N, result) | ||
return result | ||
} | ||
/* evaluate string literal */ | ||
@@ -518,0 +544,0 @@ evalLiteralString (N) { |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
433255
7972
288