This is an automated email from the ASF dual-hosted git repository.

hsluoyz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/casbin-node-casbin.git


The following commit(s) were added to refs/heads/master by this push:
     new 4e9da19  fix: give in operator the same precedence as comparison 
operators
4e9da19 is described below

commit 4e9da1908ab82ff917f1ab8ca91fce69d6fd0ec0
Author: Yang Luo <[email protected]>
AuthorDate: Tue Oct 20 21:57:39 2026 +0800

    fix: give in operator the same precedence as comparison operators
---
 src/coreEnforcer.ts |  2 +-
 test/model.test.ts  | 19 ++++++++++++++++++-
 2 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/src/coreEnforcer.ts b/src/coreEnforcer.ts
index a18494f..824fc95 100644
--- a/src/coreEnforcer.ts
+++ b/src/coreEnforcer.ts
@@ -82,7 +82,7 @@ export class CoreEnforcer {
   private getExpression(asyncCompile: boolean, exp: string): Matcher {
     const matcherKey = `${asyncCompile ? 'ASYNC[' : 'SYNC['}${exp}]`;
 
-    addBinaryOp('in', 1, customIn);
+    addBinaryOp('in', 6, customIn);
 
     let expression = this.matcherMap.get(matcherKey);
     if (!expression) {
diff --git a/test/model.test.ts b/test/model.test.ts
index 4fccab4..a847fb2 100644
--- a/test/model.test.ts
+++ b/test/model.test.ts
@@ -13,7 +13,7 @@
 // limitations under the License.
 // noinspection JSMismatchedCollectionQueryUpdate
 
-import { DefaultRoleManager, Enforcer, newEnforcer, newModel } from '../src';
+import { DefaultRoleManager, Enforcer, newEnforcer, newModel, StringAdapter } 
from '../src';
 import { keyMatch2Func, keyMatch3Func, keyMatchFunc } from '../src/util';
 
 async function testEnforce(e: Enforcer, sub: string, obj: any, act: string, 
res: boolean): Promise<void> {
@@ -459,3 +459,20 @@ test('ABACModelWithInOperator', async () => {
 
   await expect(e.enforce(rule1, rule2)).resolves.toBe(true);
 });
+
+test('InOperatorPrecedence', async () => {
+  const run = async (matcher: string, sub: string, obj: any): Promise<boolean> 
=> {
+    const m = newModel();
+    m.addDef('r', 'r', 'sub, obj');
+    m.addDef('p', 'p', 'sub');
+    m.addDef('e', 'e', 'some(where (p.eft == allow))');
+    m.addDef('m', 'm', matcher);
+    return newEnforcer(m, new StringAdapter('p, admin')).then((e) => 
e.enforce(sub, obj));
+  };
+
+  await expect(run('r.sub == p.sub && r.obj.IsPublic in [false]', 'guest', { 
IsPublic: false })).resolves.toBe(false);
+  await expect(run('r.sub == p.sub && r.obj.IsPublic in [false]', 'admin', { 
IsPublic: false })).resolves.toBe(true);
+  await expect(run('r.sub == p.sub || r.obj.Name in ["a"]', 'admin', { Name: 
'b' })).resolves.toBe(true);
+  await expect(run('r.sub == p.sub || r.obj.Name in ["a"]', 'guest', { Name: 
'a' })).resolves.toBe(true);
+  await expect(run('r.sub == p.sub || r.obj.Name in ["a"]', 'guest', { Name: 
'b' })).resolves.toBe(false);
+});


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to