@axi-engine/expressions 0.2.4 → 0.3.0
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 +3 -3
- package/dist/index.js +27 -24
- package/dist/index.mjs +8 -5
- package/package.json +4 -6
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ npm install @axi-engine/expressions
|
|
|
25
25
|
- **`DataSource`**: A simple interface (`{ get(path), has(path) }`) that provides the data against which expressions are evaluated. This can be your game's state manager, a local scope, or any other data source.
|
|
26
26
|
- **`ExpressionEvaluator`**: The main class that takes an `Expression` and a `DataSource` and resolves them to a boolean result.
|
|
27
27
|
|
|
28
|
-
##
|
|
28
|
+
## Usage
|
|
29
29
|
|
|
30
30
|
Here's how to set up the evaluator and resolve a simple expression.
|
|
31
31
|
|
|
@@ -34,8 +34,8 @@ import { createExpressionEvaluator } from '@axi-engine/expressions';
|
|
|
34
34
|
import type { Expression } from '@axi-engine/expressions';
|
|
35
35
|
import type { DataSource } from '@axi-engine/utils';
|
|
36
36
|
|
|
37
|
-
// 1.
|
|
38
|
-
const evaluator =
|
|
37
|
+
// 1. Use the builder to create an CoreExpressionEvaluator.
|
|
38
|
+
const evaluator = configureExpressions().withDefaults().build();
|
|
39
39
|
|
|
40
40
|
// 2. Define a data source that provides the state
|
|
41
41
|
const myGameDataSource: DataSource = {
|
package/dist/index.js
CHANGED
|
@@ -42,25 +42,25 @@ __export(index_exports, {
|
|
|
42
42
|
module.exports = __toCommonJS(index_exports);
|
|
43
43
|
|
|
44
44
|
// src/guards.ts
|
|
45
|
-
var
|
|
45
|
+
var import_ensure = require("@axijs/ensure");
|
|
46
46
|
function isValueOperand(val) {
|
|
47
|
-
return !(0,
|
|
47
|
+
return !(0, import_ensure.isNullOrUndefined)(val) && typeof val === "object" && "value" in val;
|
|
48
48
|
}
|
|
49
49
|
function isReferenceOperand(val) {
|
|
50
|
-
return !(0,
|
|
50
|
+
return !(0, import_ensure.isNullOrUndefined)(val) && typeof val === "object" && "path" in val;
|
|
51
51
|
}
|
|
52
52
|
function isArithmeticOperand(val) {
|
|
53
|
-
return !(0,
|
|
53
|
+
return !(0, import_ensure.isNullOrUndefined)(val) && typeof val === "object" && "arithmetic" in val;
|
|
54
54
|
}
|
|
55
55
|
function isOperand(val) {
|
|
56
56
|
return isValueOperand(val) || isReferenceOperand(val) || isArithmeticOperand(val);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
// src/resolve-math.ts
|
|
60
|
-
var
|
|
60
|
+
var import_ensure2 = require("@axijs/ensure");
|
|
61
61
|
function resolveMath(op, left, right) {
|
|
62
|
-
(0,
|
|
63
|
-
!(0,
|
|
62
|
+
(0, import_ensure2.throwIf)(
|
|
63
|
+
!(0, import_ensure2.isNumber)(left) || !(0, import_ensure2.isNumber)(right),
|
|
64
64
|
`Require number operands, but got ${typeof left} and ${typeof right}.`
|
|
65
65
|
);
|
|
66
66
|
switch (op) {
|
|
@@ -73,12 +73,13 @@ function resolveMath(op, left, right) {
|
|
|
73
73
|
case "/":
|
|
74
74
|
return Number(left) / Number(right);
|
|
75
75
|
default:
|
|
76
|
-
return (0,
|
|
76
|
+
return (0, import_ensure2.throwError)(`Unknown arithmetic operator: ${op}`);
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
// src/resolve-operand.ts
|
|
81
|
-
var
|
|
81
|
+
var import_utils = require("@axi-engine/utils");
|
|
82
|
+
var import_ensure3 = require("@axijs/ensure");
|
|
82
83
|
function resolveOperand(op, source) {
|
|
83
84
|
if (isValueOperand(op)) {
|
|
84
85
|
return op.value;
|
|
@@ -91,22 +92,22 @@ function resolveOperand(op, source) {
|
|
|
91
92
|
const rightVal = resolveOperand(op.arithmetic.right, source);
|
|
92
93
|
return resolveMath(op.arithmetic.op, leftVal, rightVal);
|
|
93
94
|
}
|
|
94
|
-
return (0,
|
|
95
|
+
return (0, import_ensure3.throwError)(`Unknown operand type: ${JSON.stringify(op)}`);
|
|
95
96
|
}
|
|
96
97
|
function resolveOperandAsScalar(op, source) {
|
|
97
98
|
const value = resolveOperand(op, source);
|
|
98
|
-
(0,
|
|
99
|
-
!(0,
|
|
99
|
+
(0, import_ensure3.throwIf)(
|
|
100
|
+
!(0, import_utils.isScalar)(value),
|
|
100
101
|
`Expected a scalar value (string, number, boolean), but got ${typeof value}.`
|
|
101
102
|
);
|
|
102
103
|
return value;
|
|
103
104
|
}
|
|
104
105
|
|
|
105
106
|
// src/core-expression-evaluator.ts
|
|
106
|
-
var
|
|
107
|
+
var import_utils2 = require("@axi-engine/utils");
|
|
107
108
|
var CoreExpressionEvaluator = class {
|
|
108
109
|
/** @internal A map of registered expression handlers. */
|
|
109
|
-
handlers = new
|
|
110
|
+
handlers = new import_utils2.Registry();
|
|
110
111
|
/**
|
|
111
112
|
* Registers a new `ExpressionHandler` with the evaluator.
|
|
112
113
|
* This is the primary mechanism for extending the expression language with
|
|
@@ -133,7 +134,7 @@ var CoreExpressionEvaluator = class {
|
|
|
133
134
|
* evaluation result.
|
|
134
135
|
*/
|
|
135
136
|
async resolve(expression, data) {
|
|
136
|
-
const key = (0,
|
|
137
|
+
const key = (0, import_utils2.firstKeyOf)(expression);
|
|
137
138
|
const handler = this.handlers.getOrThrow(key);
|
|
138
139
|
const context = {
|
|
139
140
|
resolve: (expression2) => this.resolve(expression2, data),
|
|
@@ -156,7 +157,8 @@ var AndExpressionHandler = class {
|
|
|
156
157
|
};
|
|
157
158
|
|
|
158
159
|
// src/handlers/chance-expression-handler.ts
|
|
159
|
-
var
|
|
160
|
+
var import_utils3 = require("@axi-engine/utils");
|
|
161
|
+
var import_ensure4 = require("@axijs/ensure");
|
|
160
162
|
var ChanceExpressionHandler = class {
|
|
161
163
|
type = "chance";
|
|
162
164
|
/**
|
|
@@ -177,16 +179,16 @@ var ChanceExpressionHandler = class {
|
|
|
177
179
|
async resolve(exp, context) {
|
|
178
180
|
const resolvedValue = resolveOperandAsScalar(exp.chance, context.source());
|
|
179
181
|
let numericValue;
|
|
180
|
-
if ((0,
|
|
182
|
+
if ((0, import_ensure4.isNumber)(resolvedValue)) {
|
|
181
183
|
numericValue = resolvedValue;
|
|
182
|
-
} else if ((0,
|
|
184
|
+
} else if ((0, import_ensure4.isString)(resolvedValue)) {
|
|
183
185
|
const parsed = parseFloat(resolvedValue.replace("%", "").trim());
|
|
184
|
-
(0,
|
|
186
|
+
(0, import_ensure4.throwIf)(isNaN(parsed), `Chance value as a string must be a valid number, but got '${resolvedValue}'.`);
|
|
185
187
|
numericValue = parsed;
|
|
186
188
|
} else {
|
|
187
|
-
(0,
|
|
189
|
+
(0, import_ensure4.throwError)(`Chance value must be a number or a string, but got a boolean.`);
|
|
188
190
|
}
|
|
189
|
-
const randomRoll = (0,
|
|
191
|
+
const randomRoll = (0, import_utils3.randInt)(0, 100);
|
|
190
192
|
return randomRoll < numericValue;
|
|
191
193
|
}
|
|
192
194
|
};
|
|
@@ -223,7 +225,8 @@ var ExistsExpressionHandler = class {
|
|
|
223
225
|
};
|
|
224
226
|
|
|
225
227
|
// src/handlers/in-expression-handler.ts
|
|
226
|
-
var
|
|
228
|
+
var import_utils4 = require("@axi-engine/utils");
|
|
229
|
+
var import_ensure5 = require("@axijs/ensure");
|
|
227
230
|
var InExpressionHandler = class {
|
|
228
231
|
type = "in";
|
|
229
232
|
/**
|
|
@@ -247,13 +250,13 @@ var InExpressionHandler = class {
|
|
|
247
250
|
async resolve(exp, context) {
|
|
248
251
|
const value = resolveOperandAsScalar(exp.in.value, context.source());
|
|
249
252
|
const rawArray = Array.isArray(exp.in.array) ? exp.in.array : resolveOperand(exp.in.array, context.source());
|
|
250
|
-
(0,
|
|
253
|
+
(0, import_ensure5.throwIf)(
|
|
251
254
|
!Array.isArray(rawArray),
|
|
252
255
|
`The 'in' expression requires an array, but the provided source resolved to ${typeof rawArray}.`
|
|
253
256
|
);
|
|
254
257
|
const typedArray = rawArray;
|
|
255
258
|
const resolvedArray = typedArray.map(
|
|
256
|
-
(item) => (0,
|
|
259
|
+
(item) => (0, import_utils4.isScalar)(item) ? item : resolveOperandAsScalar(item, context.source())
|
|
257
260
|
);
|
|
258
261
|
return resolvedArray.includes(value);
|
|
259
262
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/guards.ts
|
|
2
|
-
import { isNullOrUndefined } from "@
|
|
2
|
+
import { isNullOrUndefined } from "@axijs/ensure";
|
|
3
3
|
function isValueOperand(val) {
|
|
4
4
|
return !isNullOrUndefined(val) && typeof val === "object" && "value" in val;
|
|
5
5
|
}
|
|
@@ -14,7 +14,7 @@ function isOperand(val) {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
// src/resolve-math.ts
|
|
17
|
-
import { isNumber, throwError, throwIf } from "@
|
|
17
|
+
import { isNumber, throwError, throwIf } from "@axijs/ensure";
|
|
18
18
|
function resolveMath(op, left, right) {
|
|
19
19
|
throwIf(
|
|
20
20
|
!isNumber(left) || !isNumber(right),
|
|
@@ -35,7 +35,8 @@ function resolveMath(op, left, right) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
// src/resolve-operand.ts
|
|
38
|
-
import { isScalar
|
|
38
|
+
import { isScalar } from "@axi-engine/utils";
|
|
39
|
+
import { throwError as throwError2, throwIf as throwIf2 } from "@axijs/ensure";
|
|
39
40
|
function resolveOperand(op, source) {
|
|
40
41
|
if (isValueOperand(op)) {
|
|
41
42
|
return op.value;
|
|
@@ -116,7 +117,8 @@ var AndExpressionHandler = class {
|
|
|
116
117
|
};
|
|
117
118
|
|
|
118
119
|
// src/handlers/chance-expression-handler.ts
|
|
119
|
-
import {
|
|
120
|
+
import { randInt } from "@axi-engine/utils";
|
|
121
|
+
import { isString, isNumber as isNumber2, throwIf as throwIf3, throwError as throwError3 } from "@axijs/ensure";
|
|
120
122
|
var ChanceExpressionHandler = class {
|
|
121
123
|
type = "chance";
|
|
122
124
|
/**
|
|
@@ -183,7 +185,8 @@ var ExistsExpressionHandler = class {
|
|
|
183
185
|
};
|
|
184
186
|
|
|
185
187
|
// src/handlers/in-expression-handler.ts
|
|
186
|
-
import { isScalar as isScalar2
|
|
188
|
+
import { isScalar as isScalar2 } from "@axi-engine/utils";
|
|
189
|
+
import { throwIf as throwIf4 } from "@axijs/ensure";
|
|
187
190
|
var InExpressionHandler = class {
|
|
188
191
|
type = "in";
|
|
189
192
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axi-engine/expressions",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -26,16 +26,14 @@
|
|
|
26
26
|
"scripts": {
|
|
27
27
|
"build": "tsup",
|
|
28
28
|
"prebuild": "npm test",
|
|
29
|
-
"test": "vitest run
|
|
29
|
+
"test": "vitest run",
|
|
30
30
|
"docs": "typedoc src/index.ts --out docs/api --options ../../typedoc.json"
|
|
31
31
|
},
|
|
32
32
|
"files": [
|
|
33
33
|
"dist"
|
|
34
34
|
],
|
|
35
|
-
"devDependencies": {
|
|
36
|
-
"@axi-engine/utils": "^0.2.6"
|
|
37
|
-
},
|
|
38
35
|
"peerDependencies": {
|
|
39
|
-
"@
|
|
36
|
+
"@axijs/ensure": "^1.0.1",
|
|
37
|
+
"@axi-engine/utils": "^0.3.0"
|
|
40
38
|
}
|
|
41
39
|
}
|