Skip to content

Commit 032a583

Browse files
committed
Establishes that multi-key objects should fail
1 parent 0598b85 commit 032a583

File tree

6 files changed

+30
-12
lines changed

6 files changed

+30
-12
lines changed

asyncLogic.js

+9-4
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,13 @@ class AsyncLogicEngine {
6969
* @param {*} above The context above (can be used for handlebars-style data traversal.)
7070
* @returns {Promise<*>}
7171
*/
72-
async _parse (logic, context, above) {
73-
const [func] = Object.keys(logic)
72+
async _parse (logic, context, above, func, length) {
7473
const data = logic[func]
7574

7675
if (this.isData(logic, func)) return logic
7776

7877
// eslint-disable-next-line no-throw-literal
79-
if (!this.methods[func]) throw { type: 'Unknown Operator', key: func }
78+
if (!this.methods[func] || length > 1) throw { type: 'Unknown Operator', key: func }
8079

8180
// A small but useful micro-optimization for some of the most common functions.
8281
// Later on, I could define something to shut this off if var / val are redefined.
@@ -184,7 +183,13 @@ class AsyncLogicEngine {
184183
return res
185184
}
186185

187-
if (logic && typeof logic === 'object' && Object.keys(logic).length > 0) return this._parse(logic, data, above)
186+
if (logic && typeof logic === 'object' && Object.keys(logic).length > 0) {
187+
const keys = Object.keys(logic)
188+
if (keys.length > 0) {
189+
const func = keys[0]
190+
return this._parse(logic, data, above, func, keys.length)
191+
}
192+
}
188193

189194
return logic
190195
}

async_optimizer.js

+3
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ export function optimize (logic, engine, above = []) {
9090
const isData = engine.isData(logic, methodName)
9191
if (isData) return () => logic
9292

93+
// eslint-disable-next-line no-throw-literal
94+
if (keys.length > 1) throw { type: 'Unknown Operator' }
95+
9396
// If we have a deterministic function, we can just return the result of the evaluation,
9497
// basically inlining the operation.
9598
const deterministic = !engine.disableInline && isDeterministic(logic, engine, { engine })

compiler.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -171,11 +171,12 @@ function buildString (method, buildState = {}) {
171171
return result
172172
}
173173

174-
const func = method && Object.keys(method)[0]
175-
176174
if (method && typeof method === 'object') {
175+
const keys = Object.keys(method)
176+
const func = keys[0]
177+
177178
if (!func) return pushValue(method)
178-
if (!engine.methods[func]) {
179+
if (!engine.methods[func] || keys.length > 1) {
179180
// Check if this is supposed to be "data" rather than a function.
180181
if (engine.isData(method, func)) return pushValue(method, true)
181182
// eslint-disable-next-line no-throw-literal

logic.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,13 @@ class LogicEngine {
6060
* @param {*} above The context above (can be used for handlebars-style data traversal.)
6161
* @returns {{ result: *, func: string }}
6262
*/
63-
_parse (logic, context, above, func) {
63+
_parse (logic, context, above, func, length) {
6464
const data = logic[func]
6565

6666
if (this.isData(logic, func)) return logic
6767

6868
// eslint-disable-next-line no-throw-literal
69-
if (!this.methods[func]) throw { type: 'Unknown Operator', key: func }
69+
if (!this.methods[func] || length > 1) throw { type: 'Unknown Operator', key: func }
7070

7171
// A small but useful micro-optimization for some of the most common functions.
7272
// Later on, I could define something to shut this off if var / val are redefined.
@@ -162,7 +162,7 @@ class LogicEngine {
162162
const keys = Object.keys(logic)
163163
if (keys.length > 0) {
164164
const func = keys[0]
165-
return this._parse(logic, data, above, func)
165+
return this._parse(logic, data, above, func, keys.length)
166166
}
167167
}
168168

optimizer.js

+3
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,9 @@ export function optimize (logic, engine, above = []) {
200200
const isData = engine.isData(logic, methodName)
201201
if (isData) return () => logic
202202

203+
// eslint-disable-next-line no-throw-literal
204+
if (keys.length > 1) throw { type: 'Unknown Operator' }
205+
203206
// If we have a deterministic function, we can just return the result of the evaluation,
204207
// basically inlining the operation.
205208
const deterministic = !engine.disableInline && isDeterministic(logic, engine, { engine })

suites/bad.json

+8-2
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,18 @@
33
"description": "Single key object, does not map to operator",
44
"rule": { "UnknownOperator": true },
55
"data": null,
6-
"error": { "type": "Unknown Operator", "key": "UnknownOperator" }
6+
"error": { "type": "Unknown Operator" }
77
},
88
{
99
"description": "Multi-Key Object",
1010
"rule": { "UnknownOperator": true, "UnknownOperator2": true },
1111
"data": null,
12-
"error": {}
12+
"error": { "type": "Unknown Operator" }
13+
},
14+
{
15+
"description": "Multi-Key Object 2",
16+
"rule": { "+": true, "UnknownOperator2": true },
17+
"data": null,
18+
"error": { "type": "Unknown Operator" }
1319
}
1420
]

0 commit comments

Comments
 (0)