Comparing version
{ | ||
"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
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
433255
6.93%7972
8.39%288
18.03%13
8.33%