@via-profit/ability 3.7.4 → 3.7.5
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/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";const t={or:"or",and:"and"};class e extends Error{constructor(t,e){super(t,e),this.name="AbilityError",Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}}class s extends Error{constructor(t,e){super(t,e),this.name="AbilityParserError",Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}}const i={equals:"=",defined:"defined",not_defined:"not_defined",not_equals:"<>",greater_than:">",less_than:"<",less_or_equal:"<=",greater_or_equal:">=",in:"in",not_in:"not in",contains:"contains",not_contains:"not contains",length_greater_than:"length greater than",length_less_than:"length less than",length_equals:"length equals",always:"always",never:"never"};function r(t){switch(t){case i.equals:return"equals";case i.not_equals:return"not_equals";case i.greater_than:return"greater_than";case i.less_than:return"less_than";case i.less_or_equal:return"less_or_equal";case i.greater_or_equal:return"greater_or_equal";case i.in:return"in";case i.not_in:return"not_in";case i.contains:return"contains";case i.not_contains:return"not_contains";case i.length_greater_than:return"length_greater_than";case i.length_less_than:return"length_less_than";case i.length_equals:return"length_equals";case i.always:return"always";case i.never:return"never";case i.defined:return"defined";case i.not_defined:return"not_defined";default:return"never"}}function n(t,e){return null!==t&&null!==e&&t===e}const a={pending:"pending",match:"match",mismatch:"mismatch",exceptMismatch:"except-mismatch",disabled:"disabled"};class o{type;children;_name;match;debugInfo;constructor(t,e=[]){this.type=t.type,this.children=e,this._name=t.name,this.match=t.match,this.debugInfo=t.debugInfo}get name(){const t=this._name.substring(0,60);return`${t}${t.length<this._name.length?"...":""}`}toString(t="",e=!0){const s=this.match===a.match,i=this.match===a.mismatch,r=this.match===a.pending,n=`[${s?"MATCH ✓":i?"MISMATCH ✗":r?"PENDING …":"DISABLED ⊘"}]`.padEnd(15," "),o=("policy"===this.type?"POLICY":"ruleSet"===this.type?"RULESET":"RULE").padEnd(10," ");let c=`${t}${0===t.length?"":e?"└─ ":"├─ "}${n}${o}${this.name}`;this.debugInfo&&(c+=` (${this.debugInfo})`);const h=t+(e?" ":"│ ");return this.children.forEach((t,e)=>{c+="\n"+t.toString(h,e===this.children.length-1)}),c}}class c extends o{constructor(t){super({type:"rule",match:t.state,name:t.name,debugInfo:`${t.subject} ${t.condition} ${JSON.stringify(t.resource)}`})}}class h extends o{constructor(t){const e=t.rules.map(t=>new c(t));super({type:"ruleSet",match:t.state,name:t.name},e)}}class l extends o{constructor(t){const e=t.ruleSet.map(t=>new h(t));super({type:"policy",name:t.priority>-1?`@priority ${t.priority} <${t.effect}> ${t.name}`:`<${t.effect}> ${t.name}`,match:t.matchState},e)}}class u{effect;strategy;constructor(t,e){this.effect=t,this.strategy=e}explain(){return`${this.strategy.isDenied()?"== DENIED==":"== ALLOWED =="}\n${this.strategy.policies.map(t=>new l(t).toString()).join("\n")}\n`}decisive(){return this.strategy.decisivePolicy()}explainDecisive(){const t=this.decisive();return t?new l(t).toString():null}isAllowed=()=>this.strategy.isAllowed();isDenied=()=>this.strategy.isDenied()}const d={deny:"deny",permit:"permit"};class m{onDeny;onAllow;StrategyClass;policyEntries;constructor(t,e,s={}){const i=this.toArray(t);this.onDeny=s.onDeny,this.onAllow=s.onAllow;const r=[...s.tags?i.filter(t=>t.tags.some(t=>s.tags.includes(t))):i].sort((t,e)=>e.priority-t.priority);this.policyEntries=r.map(t=>({policy:t,normalizedPermission:m.normalizePermission(t.permission),segments:m.normalizePermission(t.permission).split(".")})),this.StrategyClass=e}resolve(t,s,i){const r=m.normalizePermission(String(t)).split("."),n=this.policyEntries.filter(t=>m.matchPermissions(t.segments,r)).map(t=>t.policy);for(const t of n)if(!t.disabled&&t.check(s,i)===a.pending)throw new e(`The policy "${t.name}" is still in a pending state. Make sure to call "check" to evaluate the policy before resolving permissions.`);const o=new this.StrategyClass(n),c=o.evaluate(),h=new u(c,o);return c===d.deny&&this.onDeny&&this.onDeny(h),c===d.permit&&this.onAllow&&this.onAllow(h),h}enforce(t,s,i,r){const n=this.resolve(t,s,i);if(n.isDenied())throw r?.onDeny&&r?.onDeny(n),new e("Permission denied")}static isInPermissionContain(t,e){const s=t.split("."),i=e.split("."),[r,n]=s.length>=i.length?[s,i]:[i,s];return n.every((t,e)=>"*"===t||"*"===r[e]||t===r[e])}toArray(t){return[...Array.isArray(t)?t:[t]]}static normalizePermission(t){return t.trim().replace(/^permission\./,"").replace(/\.+/g,".").toLowerCase()}static matchPermissions(t,e){let s=0;for(;s<t.length;s++){const i=t[s],r=e[s];if("*"===i)return!0;if(void 0===r)return!1;if(i!==r)return!1}return s===e.length}}class p{static sha1(t){const e=p.stringToBytes(t),s=8*e.length,i=new Uint8Array(e.length+1);i.set(e,0),i[e.length]=128;let r=(56-i.length%64+64)%64;const n=new Uint8Array(i.length+r+8);n.set(i,0);const a=Math.floor(s/4294967296),o=s>>>0;n[n.length-8]=a>>>24&255,n[n.length-7]=a>>>16&255,n[n.length-6]=a>>>8&255,n[n.length-5]=255&a,n[n.length-4]=o>>>24&255,n[n.length-3]=o>>>16&255,n[n.length-2]=o>>>8&255,n[n.length-1]=255&o;let c=1732584193,h=4023233417,l=2562383102,u=271733878,d=3285377520;const m=new Array(80);for(let t=0;t<n.length;t+=64){for(let e=0;e<16;e++){const s=t+4*e;m[e]=n[s]<<24|n[s+1]<<16|n[s+2]<<8|n[s+3]}for(let t=16;t<80;t++)m[t]=p.leftRotate(m[t-3]^m[t-8]^m[t-14]^m[t-16],1);let e=c,s=h,i=l,r=u,a=d;for(let t=0;t<80;t++){let n,o;t<20?(n=s&i|~s&r,o=1518500249):t<40?(n=s^i^r,o=1859775393):t<60?(n=s&i|s&r|i&r,o=2400959708):(n=s^i^r,o=3395469782);const c=p.leftRotate(e,5)+n+a+o+(0|m[t])|0;a=r,r=i,i=p.leftRotate(s,30),s=e,e=c}c=c+e|0,h=h+s|0,l=l+i|0,u=u+r|0,d=d+a|0}return[p.toHex32(c),p.toHex32(h),p.toHex32(l),p.toHex32(u),p.toHex32(d)].join("")}static leftRotate(t,e){return(t<<e|t>>>32-e)>>>0}static toHex32(t){return(t>>>0).toString(16).padStart(8,"0")}static stringToBytes(t){if("undefined"!=typeof TextEncoder)return(new TextEncoder).encode(t);{const e=Buffer.from(t,"utf8");return new Uint8Array(e.buffer,e.byteOffset,e.byteLength)}}}class f{matchState=a.pending;ruleSet=[];effect;compareMethod=t.and;id;name;description;permission;priority=-1;disabled;tags;constructor(e){const{name:s,description:i,id:r,permission:n,effect:a,compareMethod:o=t.and,priority:c,disabled:h,tags:l}=e;this.permission=n,this.description=i,this.effect=a,this.compareMethod=o,this.priority="number"==typeof c?c:-1,this.disabled="boolean"==typeof h&&h,this.tags=l||[],this.id=r||`p_${this.hash().slice(0,10)}`,this.name=s||this.id}addRuleSet(t){return this.ruleSet.push(t),this}addRuleSets(t){for(const e of t)this.ruleSet.push(e);return this}extractRules(){const t=[];for(const e of this.ruleSet)for(const s of e.rules)t.push(s);return t}check(e,s){if(this.matchState=a.mismatch,this.disabled)return this.matchState=a.disabled,this.matchState;if(!this.ruleSet.length)return this.matchState;const i=this.ruleSet.filter(t=>!t.isExcept),r=this.ruleSet.filter(t=>t.isExcept),n=[];for(const r of i){if(r.disabled)continue;const i=r.check(e,s);if(n.push(i),t.and===this.compareMethod&&a.mismatch===i)return this.matchState=a.mismatch,this.matchState;if(t.or===this.compareMethod&&a.match===i){this.matchState=a.match;break}}let o=!1;if(o=t.and===this.compareMethod?n.every(t=>a.match===t):n.some(t=>a.match===t),!o)return this.matchState=a.mismatch,this.matchState;for(const t of r){if(t.disabled)continue;const i=t.check(e,s);if(a.match===i)return this.matchState=a.exceptMismatch,this.matchState}return this.matchState=a.match,this.matchState}explain(){if(this.matchState===a.pending)throw new e("First, run the check method, then explain");return new l(this)}copyWith(t){const e=new f({id:t.id??this.id,name:t.name??this.name,description:t.description??this.description,priority:void 0!==t.priority?t.priority:this.priority,permission:t.permission??this.permission,effect:t.effect??this.effect,compareMethod:t.compareMethod??this.compareMethod}),s=t.ruleSet??this.ruleSet;for(const t of s)e.addRuleSet(t);return e}hash(){const t=[`permission:${this.permission}`,`effect:${this.effect}`,`compareMethod:${this.compareMethod}`,`priority:${this.priority}`,`disabled:${this.disabled}`];if(this.tags&&this.tags.length>0&&t.push(`tags:${[...this.tags].sort().join(",")}`),this.ruleSet&&this.ruleSet.length>0){const e=this.ruleSet.map(t=>t.hash());t.push(`rules:${e.sort().join("|")}`)}const e=t.join(";");return p.sha1(e)}}class y{subject;resource;condition;name;description;id;state=a.pending;disabled;constructor(t){const{id:e,name:s,subject:i,resource:r,condition:n,disabled:o,description:c}=t;this.description=c,this.disabled="boolean"==typeof o&&o,this.subject=i,this.resource=r,this.condition=n,this.state=this.disabled?a.disabled:this.state,this.id=e||`r_${this.hash().slice(0,10)}`,this.name=s||this.id}static isPrimitive(t){return"string"==typeof t||"number"==typeof t||"boolean"==typeof t||null===t}static isNumber(t){return"number"==typeof t}static isString(t){return"string"==typeof t}static valueLen=t=>this.isString(t)||Array.isArray(t)?t.length:null;static operatorHandlers={[r(i.always)]:()=>!0,[r(i.defined)]:t=>void 0!==t,[r(i.not_defined)]:t=>void 0===t,[r(i.never)]:()=>!1,[r(i.equals)]:(t,e)=>t===e,[r(i.not_equals)]:(t,e)=>t!==e,[r(i.contains)]:(t,e)=>Array.isArray(t)&&y.isPrimitive(e)?t.includes(e):!(!Array.isArray(t)||!Array.isArray(e))&&t.some(t=>e.includes(t)),[r(i.not_contains)]:(t,e)=>Array.isArray(t)&&y.isPrimitive(e)?!t.includes(e):!(!Array.isArray(t)||!Array.isArray(e)||t.some(t=>e.includes(t))),[r(i.in)]:(t,e)=>y.isPrimitive(t)&&Array.isArray(e)?e.includes(t):!(!Array.isArray(t)||!Array.isArray(e))&&t.some(t=>e.includes(t)),[r(i.not_in)]:(t,e)=>y.isPrimitive(t)&&Array.isArray(e)?!e.includes(t):!(!Array.isArray(t)||!Array.isArray(e)||t.some(t=>e.includes(t))),[r(i.greater_than)]:(t,e)=>!(!y.isNumber(t)||!y.isNumber(e))&&t>e,[r(i.less_than)]:(t,e)=>!(!y.isNumber(t)||!y.isNumber(e))&&t<e,[r(i.greater_or_equal)]:(t,e)=>!(!y.isNumber(t)||!y.isNumber(e))&&t>=e,[r(i.less_or_equal)]:(t,e)=>!(!y.isNumber(t)||!y.isNumber(e))&&t<=e,[r(i.length_greater_than)]:(t,e)=>{const s=y.valueLen(t);if(null===s)return!1;if(y.isNumber(e))return s>e;const i=y.valueLen(e);return null!==i&&s>i},[r(i.length_less_than)]:(t,e)=>{const s=y.valueLen(t);if(null===s)return!1;if(y.isNumber(e))return s<e;const i=y.valueLen(e);return null!==i&&s<i},[r(i.length_equals)]:(t,e)=>{const s=y.valueLen(t);if(null===s)return!1;if(y.isNumber(e))return s===e;const i=y.valueLen(e);return null!==i&&s===i}};check(t,e){if(this.disabled)return this.state=a.disabled,this.state;const[s,i]=this.extractValues(t,e),n=(0,y.operatorHandlers[r(this.condition)])(s,i);return this.state=n?a.match:a.mismatch,this.state}extractValues(t,e){let s,i;return null==t&&null==e?[NaN,NaN]:(s=this.subject.includes(".")?this.subject.startsWith("env.")&&void 0!==e?this.getDotNotationValue(e,this.subject.replace(/^env\./,"")):this.getDotNotationValue(t,this.subject):this.subject,i="string"==typeof this.resource&&this.resource.includes(".")?this.resource.startsWith("env.")&&void 0!==e?this.getDotNotationValue(e,this.resource.replace(/^env\./,"")):this.getDotNotationValue(t,this.resource):this.resource,[s,i])}static _pathCache=new Map;static _parsePath(t){const e=y._pathCache.get(t);if(e)return e;const s=t.split("."),i=[];for(const t of s){const e=t.indexOf("[");if(-1!==e){const s=t.slice(0,e),r=t.slice(e+1,-1),n=Number(r);i.push({prop:s,index:n})}else i.push(t)}return y._pathCache.set(t,i),i}getDotNotationValue(t,e){if(null==t)return;const s=y._parsePath(e);let i=t;for(const t of s){if(null==i)return;if("string"==typeof t)i=i[t];else{const e=i[t.prop];i=Array.isArray(e)?e[t.index]:void 0}}return i}toString(){return`AbilityRule: ${this.name} condition: ${r(this.condition)} subject: "${this.subject?.toString()}" resource: "${this.resource?.toString()}"`}copyWith(t){return new y({id:t.id??this.id,name:t.name??this.name,description:t.description??this.description,subject:t.subject??this.subject,resource:t.resource??this.resource,condition:t.condition??this.condition})}hash(){const t=[];return t.push(`subject:${this.subject}`),t.push(`resource:${JSON.stringify(this.resource)}`),t.push(`condition:${this.condition}`),t.push(`disabled:${this.disabled}`),p.sha1(t.join(";"))}static equals(t,e){return new y({condition:i.equals,subject:t,resource:e})}static notEquals(t,e){return new y({condition:i.not_equals,subject:t,resource:e})}static contains(t,e){return new y({condition:i.contains,subject:t,resource:e})}static notContains(t,e){return new y({condition:i.not_contains,subject:t,resource:e})}static notIn(t,e){return new y({condition:i.not_in,subject:t,resource:e})}static in(t,e){return new y({condition:i.in,subject:t,resource:e})}static notEqual(t,e){return new y({condition:i.not_equals,subject:t,resource:e})}static lessThan(t,e){return new y({condition:i.less_than,subject:t,resource:e})}static lessOrEqual(t,e){return new y({condition:i.less_or_equal,subject:t,resource:e})}static moreThan(t,e){return new y({condition:i.greater_than,subject:t,resource:e})}static moreOrEqual(t,e){return new y({condition:i.greater_or_equal,subject:t,resource:e})}}class g{state=a.pending;rules=[];compareMethod=t.and;name;description;id;isExcept=!1;disabled;constructor(t){const{name:e,id:s,compareMethod:i,isExcept:r,disabled:n,description:o}=t;this.description=o,this.compareMethod=i,this.isExcept=r,this.disabled="boolean"==typeof n&&n,this.state=this.disabled?a.disabled:this.state,this.id=s||`g_${this.hash().slice(0,10)}`,this.name=e||this.id}addRule(t){return this.rules.push(t),this}addRules(t){return t.forEach(t=>this.addRule(t)),this}check(e,s){if(this.state=a.mismatch,this.disabled)return this.state=a.disabled,this.state;if(!this.rules.length)return this.state;const i=[];for(const r of this.rules){if(r.disabled)continue;const n=r.check(e,s);if(i.push(n),t.and===this.compareMethod&&a.mismatch===n)return this.state;if(t.or===this.compareMethod&&a.match===n)return this.state=a.match,this.state}return t.and===this.compareMethod&&i.every(t=>a.match===t)&&(this.state=a.match),t.or===this.compareMethod&&i.some(t=>a.match===t)&&(this.state=a.match),this.state}toString(){return`AbilityRuleSet: ${this.name} compareMethod: ${this.compareMethod}, rules: ${this.rules.map(t=>t.toString()).join("\n")}`}copyWith(t){const e=new g({id:t.id??this.id,name:t.name??this.name,description:t.description??this.description,compareMethod:t.compareMethod??this.compareMethod}),s=t.rules??this.rules;for(const t of s)e.addRule(t);return e}hash(){const t=this.rules.map(t=>t.hash()).sort(),e=[`compareMethod:${this.compareMethod}`,`isExcept:${this.isExcept}`,`disabled:${this.disabled}`,`rules:${t.join("|")}`];return p.sha1(e.join(";"))}static and(e){return new g({compareMethod:t.and}).addRules(e)}static or(e){return new g({compareMethod:t.or}).addRules(e)}}class E{static parse(t){return t.map(t=>E.parsePolicy(t))}static parsePolicy(t){const{id:e,name:s,ruleSet:i,compareMethod:r,permission:n,effect:a,priority:o,disabled:c,tags:h}=t,l=new f({name:s,id:e,permission:n,priority:o,effect:a,disabled:c,tags:h});return l.compareMethod=r,i.forEach(t=>{l.addRuleSet(E.parseRuleSet(t))}),l}static parseRule(t){const{id:e,name:s,subject:i,resource:r,condition:n,disabled:a}=t;return new y({id:e,name:s,subject:i,resource:r,disabled:a,condition:n})}static parseRuleSet(t){const{id:e,name:s,rules:i,compareMethod:r,disabled:n}=t,a=new g({disabled:n,compareMethod:r,name:s,id:e});if(i&&i.length>0){const t=i.map(t=>E.parseRule(t));a.addRules(t)}return a}static ruleToJSON(t){return{id:t.id,name:t.name,disabled:t.disabled,subject:t.subject,resource:t.resource,condition:t.condition}}static ruleSetToJSON(t){return{id:t.id.toString(),name:t.name.toString(),disabled:t.disabled,compareMethod:t.compareMethod,rules:t.rules.map(t=>E.ruleToJSON(t))}}static policyToJSON(t){return{id:t.id.toString(),name:t.name.toString(),disabled:t.disabled,priority:t.priority,permission:t.permission,effect:t.effect,compareMethod:t.compareMethod,tags:t.tags,ruleSet:t.ruleSet.map(t=>E.ruleSetToJSON(t))}}static toJSON(t){return t.map(t=>E.policyToJSON(t))}}const _={EFFECT:"EFFECT",IF:"IF",PERMISSION:"PERMISSION",IDENTIFIER:"IDENTIFIER",COLON:"COLON",COMMA:"COMMA",DOT:"DOT",LBRACKET:"LBRACKET",RBRACKET:"RBRACKET",ALL:"ALL",ANY:"ANY",OF:"OF",EOF:"EOF",COMMENT:"COMMENT",EQ:"EQ",CONTAINS:"CONTAINS",IN:"IN",NOT_IN:"NOT_IN",NOT_CONTAINS:"NOT_CONTAINS",GT:"GT",GTE:"GTE",LT:"LT",LTE:"LTE",NULL:"NULL",EQ_NULL:"EQ_NULL",NOT_EQ_NULL:"NOT_EQ_NULL",DEFINED:"DEFINED",NOT_EQ:"NOT_EQ",LEN_GT:"LEN_GT",LEN_LT:"LEN_LT",LEN_EQ:"LEN_EQ",ALWAYS:"ALWAYS",NEVER:"NEVER",EXCEPT:"EXCEPT",ANNOTATION:"ANNOTATION",STRING:"STRING",NUMBER:"NUMBER",BOOLEAN:"BOOLEAN",SYMBOL:"SYMBOL",KEYWORD:"KEYWORD",ALIAS:"ALIAS",UNKNOWN:"UNKNOWN"};class A{type;value;line;column;constructor(t,e,s,i){this.type=t,this.value=e,this.line=s,this.column=i}toString(){return`AbilityDSLToken([${this.type}] "${this.value}" at ${this.line}:${this.column})`}}class v{input;pos=0;tokens=[];line=1;column=1;keywords=new Set(["if","all","any","of","permit","allow","deny","forbidden","true","false","null","defined","contains","includes","length","len","has","in","gt","lt","gte","lte","equals","greater","less","not","is","or","than","always","never","except","alias"]);constructor(t){this.input=t}tokenize(){for(;!this.isAtEnd()&&(this.skipWhitespace(),!this.isAtEnd());){const t=this.peek();if("@"!==t)if("#"!==t)if('"'!==t&&"'"!==t)if(this.isDigit(t))this.tokens.push(this.readNumber());else if(this.isSymbol(t))this.tokens.push(this.readSymbol());else{if(!this.isAlpha(t))throw new Error(`Unexpected character '${t}' at ${this.line}:${this.column}`);this.tokens.push(this.readWord())}else this.tokens.push(this.readString());else this.tokens.push(this.readComment());else this.tokens.push(this.readAnnotation())}return this.tokens.push(new A(_.EOF,"",this.line,this.column)),this.tokens}readComment(){const t=this.line,e=this.column;this.advance();let s="";for(;!this.isAtEnd()&&!this.isNewline();)s+=this.advance();return new A(_.COMMENT,s.trim(),t,e)}readAnnotation(){const t=this.line,e=this.column;let s="";for(;!this.isAtEnd()&&!this.isNewline();)s+=this.advance();s=s.trim();let i="",r=0,n=!1,a=null,o=!1;for(;r<s.length;){const t=s[r];n?(o?(i+=t,o=!1):"\\"===t?o=!0:t===a?(n=!1,a=null):i+=t,r++):'"'!==t&&"'"!==t?(i+=t,r++):(n=!0,a=t,r++)}return new A(_.ANNOTATION,i.trim(),t,e)}readString(){const t=this.line,e=this.column,s=this.advance();let i="",r=!1;for(;!this.isAtEnd();){const n=this.advance();if(r)i+=n,r=!1;else if("\\"!==n){if(n===s)return new A(_.STRING,i,t,e);i+=n}else r=!0}throw new Error(`Unterminated string at ${t}:${e}`)}readNumber(){const t=this.line,e=this.column,s=this.pos;for(;!this.isAtEnd()&&this.isDigit(this.peek());)this.advance();const i=this.input.slice(s,this.pos);return new A(_.NUMBER,i,t,e)}readSymbol(){const t=this.line,e=this.column,s=this.advance();switch(s){case".":return new A(_.DOT,s,t,e);case":":return new A(_.COLON,s,t,e);case",":return new A(_.COMMA,s,t,e);case"[":return new A(_.LBRACKET,s,t,e);case"]":return new A(_.RBRACKET,s,t,e);case">":return"="===this.peek()?(this.advance(),new A(_.SYMBOL,">=",t,e)):new A(_.SYMBOL,">",t,e);case"<":return"="===this.peek()?(this.advance(),new A(_.SYMBOL,"<=",t,e)):">"===this.peek()?(this.advance(),new A(_.SYMBOL,"<>",t,e)):new A(_.SYMBOL,"<",t,e);case"=":return"="===this.peek()?(this.advance(),new A(_.SYMBOL,"==",t,e)):new A(_.SYMBOL,"=",t,e);case"!":if("="===this.peek())return this.advance(),new A(_.SYMBOL,"!=",t,e);throw new Error(`Unexpected symbol '!' at ${this.line}:${this.column}`);default:throw new Error(`Unknown symbol '${s}' at ${this.line}:${this.column}`)}}readWord(){const t=this.line,e=this.column,s=this.pos;for(;!this.isAtEnd()&&/[a-zA-Z0-9_*]/.test(this.peek());)this.advance();for(;!this.isAtEnd()&&"."===this.peek()&&(this.advance(),/[a-zA-Z_*]/.test(this.peek()));)for(;!this.isAtEnd()&&/[a-zA-Z0-9_*]/.test(this.peek());)this.advance();const i=this.input.slice(s,this.pos);if("always"===i)return new A(_.ALWAYS,i,t,e);if("never"===i)return new A(_.NEVER,i,t,e);if(i.includes(".")){const s=this.tokens[this.tokens.length-1];return s?.type===_.EFFECT&&i.startsWith("permission.")?new A(_.PERMISSION,i,t,e):new A(_.IDENTIFIER,i,t,e)}if(this.keywords.has(i))return"permit"===i||"allow"===i?new A(_.EFFECT,"permit",t,e):"deny"===i||"forbidden"===i?new A(_.EFFECT,"deny",t,e):new A("all"===i?_.ALL:"any"===i?_.ANY:"of"===i?_.OF:"if"===i?_.IF:"true"===i||"false"===i?_.BOOLEAN:"null"===i?_.NULL:"defined"===i?_.DEFINED:"except"===i?_.EXCEPT:"alias"===i?_.ALIAS:_.KEYWORD,i,t,e);const r=this.tokens[this.tokens.length-1];return new A(r?.type===_.EFFECT?_.PERMISSION:_.IDENTIFIER,i,t,e)}skipWhitespace(){for(;!this.isAtEnd()&&/\s/.test(this.peek());)this.advance()}isDigit(t){return t>="0"&&t<="9"}isAlpha(t){return/[a-zA-Z_]/.test(t)}isSymbol(t){return[".",":",",","[","]",">","<","=","!"].includes(t)}isNewline(){return"\n"===this.peek()}peek(){return this.input[this.pos]}advance(){const t=this.input[this.pos++];return"\n"===t?(this.line++,this.column=1):this.column++,t}isAtEnd(){return this.pos>=this.input.length}}class S extends Error{line;column;context;details;_formattedMessage;_originalStack;constructor(t,e,s,i){super(i.split("\n")[0]),this.line=t,this.column=e,this.context=s,this.details=i,this.name="AbilityDSLSyntaxError",Error.captureStackTrace&&Error.captureStackTrace(this,S),this._originalStack=this.stack,this._formattedMessage=this.formatMessage(),Object.defineProperty(this,"stack",{get:()=>this._formattedMessage,configurable:!0})}static supportsColor(){return"undefined"!=typeof process&&process.stdout?.isTTY}formatMessage(){const t=S.supportsColor(),e=t?"[1m":"",s=t?"[31m":"",i=t?"[33;1m":"",r=t?"[90m":"",n=t?"[0m":"",a=this.context.split("\n"),o=a.findIndex(t=>t.includes("^")||t.includes("~")),c=a.findIndex(t=>t.trim().includes("#")),h=a.map((t,a)=>a===o-1?`${e}${i}${t}${n}`:a===o?`${s}${t}${n}`:a===c?`${r}${t}${n}`:t).join("\n");return`${e}${s}${this.name}: ${this.details}${n}\n\n`+h}toString(){return this._formattedMessage}}class b{tokens;pos=0;dsl;marks=[];lastToken=null;next(){const t=this.tokens[this.pos++];return this.lastToken=t,t}prev(){if(0===this.pos)return null;const t=this.tokens[this.pos--];return this.lastToken=t,t}lookPrev(){return this.lastToken}constructor(t,e){this.tokens=t,this.dsl=e}peek(){return this.tokens[this.pos]}eof(){return this.peek().type===_.EOF}check(t){return!this.eof()&&this.peek().type===t}match(t){return this.check(t)?this.next():null}expect(t,e){const s=this.peek();if(s&&s.type===t)return this.next();this.syntaxError(e,s,[t])}expectOneOf(t,e){const s=this.peek();for(const e of t)if(s&&s.type===e)return this.next();this.syntaxError(e,s,t)}mark(){this.marks.push(this.pos)}reset(){const t=this.marks.pop();void 0!==t&&(this.pos=t)}commit(){this.marks.pop()}syntaxError(t,e,s){const i=this.dsl.split(/\r?\n/),r=e.line-1,n=r>0?i[r-1]:"",a=i[r],o=r+1<i.length?i[r+1]:"",c=" ".repeat(Math.max(0,e.column-1))+"~".repeat(e.value.length),h=String(e.line+1).length,l=t=>String(t).padStart(h," ");let u="";""!==n.trim()&&(u+=`${l(e.line-1)} | ${n}\n`),u+=`${l(e.line)} | ${a}\n`,u+=`${" ".repeat(h)} | ${c}\n`,""!==o.trim()&&(u+=`${l(e.line+1)} | ${o}`);let d=t;if(s&&s?.length>0){const i=e.value,r=this.suggest(i,s),n=`${t}\nDetails: Unexpected value token \`${i}\``;d=r?`${n} Did you mean \`${r}\`?`:n}throw new S(e.line,e.column,u+"\n",d)}suggest(t,e){const s=[];for(const t of e)s.push(t);const i=[...new Set(s)];let r=null,n=3;for(const e of i){const s=this.levenshteinDistance(t.toLowerCase(),e.toLowerCase());s<n&&(n=s,r=e)}return r}levenshteinDistance(t,e){const s=Array.from({length:e.length+1},()=>Array.from({length:t.length+1},()=>0));for(let e=0;e<=t.length;e++)s[0][e]=e;for(let t=0;t<=e.length;t++)s[t][0]=t;for(let i=1;i<=e.length;i++)for(let r=1;r<=t.length;r++){const n=t[r-1]===e[i-1]?0:1;s[i][r]=Math.min(s[i][r-1]+1,s[i-1][r]+1,s[i-1][r-1]+n)}return s[e.length][t.length]}}class N{store={id:void 0,name:void 0,priority:void 0,description:void 0,disabled:void 0,tags:void 0};get(t){return this.store[t]??null}set(t,e,s){return this.store[t]=null===e?void 0:{key:t,value:e,token:s},this}clear(){for(const t of Object.keys(this.store))this.store[t]=void 0}clone(){const t=new N;for(const e of Object.keys(this.store)){const s=this.store[e];t.store[e]=s?{...s}:void 0}return t}get id(){return this.get("id")}get name(){return this.get("name")}get description(){return this.get("description")}get priority(){return this.get("priority")}get disabled(){return this.get("disabled")}get tags(){return this.get("tags")}setID(t,e){return this.set("id",t,e)}setName(t,e){return this.set("name",t,e)}setDescription(t,e){return this.set("description",t,e)}setPriority(t,e){return this.set("priority",t,e)}setDisabled(t,e){return this.set("disabled",t,e)}setTags(t,e){return this.set("tags",t,e)}}const x={policy:new Set(["id","name","description","priority","disabled","tags"]),ruleSet:new Set(["id","name","description","disabled"]),rule:new Set(["id","name","disabled"]),alias:new Set(["name","disabled"])};class L{store=new Map;get(t){return this.store.get(t)||null}set(t,e){return this.store.set(t,e),this}has(t){return this.store.has(t)}}class k{dsl;stream;annBuffer=new N;aliasBuffer=new L;constructor(t){this.dsl=t}parse(){this.annBuffer.clear();const t=new v(this.dsl).tokenize();this.stream=new b(t,this.dsl);const e=[];for(;!this.stream.eof();){if(this.consumeLeadingComments(),this.consumeLeadingAnnotations(),this.consumeLeadingAliases(),!this.isStartOfPolicy()){const t=this.stream.peek();this.stream.syntaxError(`Expected policy, got ${t.type}.`,t,[_.EFFECT])}e.push(this.parsePolicy())}return e}parsePolicy(){this.consumeLeadingComments(),this.consumeLeadingAnnotations(),this.consumeLeadingAliases();const e=this.takeAnnotations("policy"),s=this.stream.expect(_.EFFECT,"Expected effect").value,i=this.stream.expect(_.PERMISSION,"Expected permission"),r=i.value;if(!r.startsWith("permission."))return this.stream.syntaxError(`Unexpected token. The permission key, must be starts with prefix \`permission.\`, but got \`${r}\`.\nDid you mean \`permission.${r}\`?`,i);this.stream.expect(_.IF,'Expected "if"');const n=this.stream.expectOneOf([_.ALL,_.ANY],'Expected "all" or "any"').type===_.ALL?t.and:t.or;this.stream.expect(_.COLON,'Expected ":"');const a=this.parseRuleSets(n);return new f({id:e.id?.value||null,name:e.name?.value||null,description:e.description?.value||null,priority:e.priority?.value||null,permission:r.replace(/^permission\./,""),effect:"permit"===s?d.permit:d.deny,disabled:e.disabled?.value??void 0,tags:e.tags?.value??void 0,compareMethod:n}).addRuleSets(a)}parseRuleSets(t){const e=[];for(this.consumeLeadingComments(),this.consumeLeadingAnnotations();!this.stream.eof()&&!this.isStartOfPolicy();){if(this.isStartOfExcept()){e.push(this.parseExceptGroup(t));continue}if(this.isStartOfGroup()){e.push(this.parseGroup());continue}const s=new g({compareMethod:t});for(;!(this.stream.eof()||(this.consumeLeadingComments(),this.consumeLeadingAnnotations(),this.isStartOfGroup()||this.isStartOfPolicy()||this.isStartOfExcept()));)this.stream.check(_.IDENTIFIER)||this.stream.check(_.ALWAYS)||this.stream.check(_.NEVER)?s.addRule(this.parseRule()):this.stream.syntaxError(`Unexpected token in implicit group: ${this.stream.peek().type}`,this.stream.peek());e.push(s)}return e}parseGroup(){this.consumeLeadingComments(),this.consumeLeadingAnnotations();const e=this.takeAnnotations("ruleSet"),s=this.stream.expectOneOf([_.ALL,_.ANY,_.ALWAYS,_.NEVER],'Expected "all" or "any" or "always" or "never"').type===_.ALL?t.and:t.or;this.stream.check(_.OF)&&this.stream.next(),this.stream.expect(_.COLON,'Expected ":"');const i=new g({id:e.id?.value||null,compareMethod:s,name:e.name?.value||null,description:e.description?.value||null,disabled:e.disabled?.value??void 0});for(;!(this.stream.eof()||(this.consumeLeadingComments(),this.consumeLeadingAnnotations(),this.isStartOfExcept())||this.isStartOfGroup()||this.isStartOfPolicy());)this.stream.check(_.IDENTIFIER)?i.addRule(this.parseRule()):this.stream.syntaxError(`Unexpected token in group: ${this.stream.peek().type}`,this.stream.peek());return i}parseExceptGroup(e){this.consumeLeadingComments(),this.consumeLeadingAnnotations();const s=this.takeAnnotations("ruleSet");this.stream.expect(_.EXCEPT,'Expected "except"');let i=e;this.stream.check(_.ALL)||this.stream.check(_.ANY)?(i=this.stream.next().type===_.ALL?t.and:t.or,this.stream.check(_.OF)&&this.stream.next(),this.stream.expect(_.COLON,'Expected ":" after except group')):this.stream.expect(_.COLON,'Expected ":" after "except"');const r=new g({id:s.id?.value||null,compareMethod:i,name:s.name?.value||null,description:s.description?.value||null,isExcept:!0,disabled:s.disabled?.value??void 0});for(;!(this.stream.eof()||(this.consumeLeadingComments(),this.consumeLeadingAnnotations(),this.isStartOfGroup()||this.isStartOfPolicy()||this.isStartOfExcept()));)this.stream.check(_.IDENTIFIER)?r.addRule(this.parseRule()):this.stream.syntaxError(`Unexpected token in except group: ${this.stream.peek().type}`,this.stream.peek());return r}parseRule(){this.consumeLeadingComments(),this.consumeLeadingAnnotations();const t=this.takeAnnotations("rule"),e=this.stream.check(_.ALWAYS)||this.stream.check(_.NEVER);e||this.stream.check(_.IDENTIFIER)||this.stream.syntaxError(`Expected identifier, but got ${this.stream.peek().type}`,this.stream.peek());const s=e?"":this.stream.expect(_.IDENTIFIER,"Expected field").value;if(this.aliasBuffer.has(s))return this.aliasBuffer.get(s);const{condition:i,operator:r}=this.parseConditionOperator();let n=null,a=null;return r!==_.EQ_NULL&&r!==_.NOT_EQ_NULL&&r!==_.NULL&&r!==_.ALWAYS&&r!==_.NEVER&&r!==_.DEFINED&&(this.stream.mark(),n=this.parseValue(),a=this.stream.lookPrev(),this.stream.commit()),this.consumeLeadingComments(),this.consumeLeadingAnnotations(),this.consumeLeadingAliases(),"string"==typeof n&&a&&a.type===_.IDENTIFIER&&!a.value.includes(".")&&this.stream.syntaxError(`Expected comparison operator or value, got \`${n}\``,a,[_.KEYWORD]),new y({id:t.id?.value||null,subject:s,resource:n,condition:i,name:t.name?.value||null,description:t.description?.value||null,disabled:t.disabled?.value??void 0})}parseConditionOperator(){if(this.stream.mark(),this.matchWord("always"))return this.stream.commit(),{condition:i.always,operator:_.ALWAYS};if(this.stream.reset(),this.stream.mark(),this.matchWord("never"))return this.stream.commit(),{condition:i.never,operator:_.NEVER};if(this.stream.reset(),this.stream.mark(),(this.matchWord("length")||this.matchWord("len"))&&this.matchWord("equals"))return this.stream.commit(),{condition:i.length_equals,operator:_.LEN_EQ};if(this.stream.reset(),this.stream.mark(),(this.matchWord("length")||this.matchWord("len"))&&this.matchSymbol("="))return this.stream.commit(),{condition:i.length_equals,operator:_.LEN_EQ};if(this.stream.reset(),this.stream.mark(),(this.matchWord("length")||this.matchWord("len"))&&this.matchWord("greater")&&this.matchWord("than"))return this.stream.commit(),{condition:i.length_greater_than,operator:_.LEN_GT};if(this.stream.reset(),this.stream.mark(),(this.matchWord("length")||this.matchWord("len"))&&this.matchSymbol(">"))return this.stream.commit(),{condition:i.length_greater_than,operator:_.LEN_GT};if(this.stream.reset(),this.stream.mark(),(this.matchWord("length")||this.matchWord("len"))&&this.matchWord("less")&&this.matchWord("than"))return this.stream.commit(),{condition:i.length_less_than,operator:_.LEN_LT};if(this.stream.reset(),this.stream.mark(),(this.matchWord("length")||this.matchWord("len"))&&this.matchSymbol("<"))return this.stream.commit(),{condition:i.length_less_than,operator:_.LEN_LT};if(this.stream.reset(),this.stream.mark(),this.matchWord("greater")&&this.matchWord("than")&&this.matchWord("or")&&this.matchWord("equal"))return this.stream.commit(),{condition:i.greater_or_equal,operator:_.GTE};if(this.stream.reset(),this.stream.mark(),this.matchWord("greater")&&this.matchWord("than"))return this.stream.commit(),{condition:i.greater_than,operator:_.GT};if(this.stream.reset(),this.stream.mark(),this.matchWord("less")&&this.matchWord("than")&&this.matchWord("or")&&this.matchWord("equal"))return this.stream.commit(),{condition:i.less_or_equal,operator:_.LTE};if(this.stream.reset(),this.matchWord("less")&&this.matchWord("than"))return{condition:i.less_than,operator:_.LT};if(this.stream.reset(),this.stream.mark(),this.matchWord("not")&&this.matchWord("contains"))return this.stream.commit(),{condition:i.not_contains,operator:_.NOT_CONTAINS};if(this.stream.reset(),this.stream.mark(),this.matchWord("not")&&this.matchWord("includes"))return this.stream.commit(),{condition:i.not_contains,operator:_.NOT_CONTAINS};if(this.stream.reset(),this.stream.mark(),this.matchWord("not")&&this.matchWord("has"))return this.stream.commit(),{condition:i.not_contains,operator:_.NOT_CONTAINS};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("equals"))return this.stream.commit(),{condition:i.equals,operator:_.EQ};if(this.stream.reset(),this.stream.mark(),this.matchWord("not")&&this.matchWord("equals"))return this.stream.commit(),{condition:i.not_equals,operator:_.NOT_EQ};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("not")&&this.matchWord("equals"))return this.stream.commit(),{condition:i.not_equals,operator:_.NOT_EQ};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("in"))return this.stream.commit(),{condition:i.in,operator:_.IN};if(this.stream.reset(),this.stream.mark(),this.matchWord("not")&&this.matchWord("in"))return this.stream.commit(),{condition:i.not_in,operator:_.NOT_IN};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("not")&&this.stream.check(_.NULL))return this.stream.next(),this.stream.commit(),{condition:i.not_equals,operator:_.NOT_EQ_NULL};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("null")&&this.stream.check(_.NULL))return this.stream.commit(),this.stream.next(),{condition:i.equals,operator:_.EQ_NULL};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("defined"))return this.stream.commit(),{condition:i.defined,operator:_.DEFINED};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("not")&&this.matchWord("defined"))return this.stream.commit(),{condition:i.not_defined,operator:_.DEFINED};this.stream.reset();const t=this.stream.peek();switch(t.type!==_.SYMBOL&&t.type!==_.KEYWORD&&t.type!==_.NULL&&this.stream.syntaxError(`Expected comparison operator, got \`${t.value}\``,t,[_.SYMBOL,_.KEYWORD,_.NULL]),this.stream.next(),t.type){case _.SYMBOL:if("="===t.value||"=="===t.value)return{condition:i.equals,operator:_.EQ};if("!="===t.value||"<>"===t.value)return{condition:i.not_equals,operator:_.NOT_EQ};if(">"===t.value)return{condition:i.greater_than,operator:_.GT};if("<"===t.value)return{condition:i.less_than,operator:_.LT};if(">="===t.value)return{condition:i.greater_or_equal,operator:_.GTE};if("<="===t.value)return{condition:i.less_or_equal,operator:_.LTE};break;case _.KEYWORD:if("contains"===t.value||"includes"===t.value||"has"===t.value)return{condition:i.contains,operator:_.CONTAINS};if("in"===t.value)return{condition:i.in,operator:_.IN};if("equals"===t.value)return{condition:i.equals,operator:_.EQ};if("gte"===t.value)return{condition:i.greater_or_equal,operator:_.GTE};if("greater"===t.value||"gt"===t.value)return{condition:i.greater_than,operator:_.GT};if("less"===t.value||"lt"===t.value)return{condition:i.less_than,operator:_.LT};if("lte"===t.value)return{condition:i.less_or_equal,operator:_.LTE};if("is"===t.value)return{condition:i.equals,operator:_.EQ}}return this.stream.syntaxError(`Unexpected operator token \`${t.value}\``,t,[_.SYMBOL,_.KEYWORD])}matchWord(t){if(this.stream.eof())return!1;const e=this.stream.peek();return(e.type===_.KEYWORD||e.type===_.IDENTIFIER||e.type===_.ALWAYS||e.type===_.NEVER||e.type===_.DEFINED)&&e.value===t&&(this.stream.next(),!0)}matchSymbol(t){if(this.stream.eof())return!1;const e=this.stream.peek();return e.type===_.SYMBOL&&e.value===t&&(this.stream.next(),!0)}parseValue(){if(this.stream.check(_.LBRACKET))return this.stream.next(),this.parseArray();const t=this.stream.peek();switch(t.type!==_.ALL&&t.type!==_.ANY&&t.type!==_.EFFECT||this.stream.syntaxError(`Unexpected ${t.type} in value position`,t),this.stream.next(),t.type){case _.STRING:return t.value;case _.NUMBER:return Number(t.value);case _.BOOLEAN:return"true"===t.value;case _.NULL:return null;case _.DEFINED:return void 0!==t.value;case _.IDENTIFIER:return t.value;default:this.stream.syntaxError(`Unexpected value token "${t.value}"`,t,[_.KEYWORD])}}parseArray(){const t=[];if(this.stream.check(_.RBRACKET))return this.stream.next(),t;for(;!this.stream.eof()&&!this.stream.check(_.RBRACKET);){const e=this.parseValue();Array.isArray(e)?t.push(...e):"string"==typeof e||"number"==typeof e||"boolean"==typeof e?t.push(e):null===e&&this.stream.syntaxError("Unexpected null in array",this.stream.peek()),this.stream.check(_.COMMA)&&this.stream.next()}return this.stream.expect(_.RBRACKET,'Expected "]"'),t}consumeLeadingComments(){for(;this.stream.check(_.COMMENT);)this.stream.next()}consumeLeadingAliases(){for(;this.stream.check(_.ALIAS);){this.stream.next();const t=this.stream.expect(_.IDENTIFIER,"Expected alias name").value;this.stream.expect(_.COLON,"Expected colon after an alias");const e=this.takeAnnotations("alias");for(;!this.stream.eof()&&!this.isStartOfAlias()&&!this.isStartOfPolicy();){const s=this.parseRule();s.name=e.get("name")?.value||t,s.description=e.get("description")?.value,!0===e.get("disabled")?.value&&(s.disabled=!0),this.aliasBuffer.set(t,s)}}}consumeLeadingAnnotations(){for(;this.stream.check(_.ANNOTATION);){const t=this.stream.next(),e=t.value.trim();if(e.startsWith("@id ")&&this.annBuffer.setID(e.slice(4).trim(),t),e.startsWith("@name ")&&this.annBuffer.setName(e.slice(6).trim(),t),e.startsWith("@description ")&&this.annBuffer.setDescription(e.slice(13).trim(),t),e.startsWith("@priority ")&&this.annBuffer.setPriority(parseInt(e.slice(10).trim(),10),t),e.startsWith("@disabled")){const s=e.slice(9).trim();this.annBuffer.setDisabled(0===s.length||"true"===e.slice(9).trim(),t)}if(e.startsWith("@tags ")){const s=e.slice(6).trim().split(",").map(t=>t.trim());this.annBuffer.setTags(s,t)}}}takeAnnotations(t){const e=this.annBuffer.clone();this.annBuffer.clear();const s=x[t];for(const i of Object.keys(e.store)){const r=e.get(i);r&&(s.has(i)||this.stream.syntaxError(`Annotation @${i} is not allowed on ${t}. Allowed: ${[...s].map(t=>"@"+t).join(", ")}`,r.token??this.stream.peek()))}return e}isStartOfPolicy(){return this.stream.check(_.EFFECT)}isStartOfGroup(){return this.stream.check(_.ALL)||this.stream.check(_.ANY)}isStartOfRule(){return this.stream.check(_.IDENTIFIER)||this.stream.check(_.ALWAYS)||this.stream.check(_.NEVER)}isStartOfExcept(){return this.stream.check(_.EXCEPT)}isStartOfAlias(){return this.stream.check(_.ALIAS)}}class O{policies;matched;constructor(t){this.policies=t,this.matched=t.filter(t=>t.matchState===a.match)}matchedPolicies(){return this.matched}hasMatched(){return this.matched.length>0}firstMatched(){return this.matchedPolicies()[0]??null}lastMatched(){const t=this.matchedPolicies();return t.length>0?t[t.length-1]:null}firstDenied(){return this.getDenyPolicies()[0]??null}firstPermitted(){return this.getPermitPolicies()[0]??null}getPermitPolicies(){return this.matched.filter(t=>t.effect===d.permit)}getDenyPolicies(){return this.matched.filter(t=>t.effect===d.deny)}hasPermit(){return this.getPermitPolicies().length>0}hasDeny(){return this.getDenyPolicies().length>0}isAllowed(){return this.evaluate()===d.permit}isDenied(){return this.evaluate()===d.deny}}exports.AbilityCompare=t,exports.AbilityCondition=i,exports.AbilityDSLLexer=v,exports.AbilityDSLParser=k,exports.AbilityDSLToken=A,exports.AbilityError=e,exports.AbilityExplain=o,exports.AbilityExplainPolicy=l,exports.AbilityExplainRule=c,exports.AbilityExplainRuleSet=h,exports.AbilityJSONParser=E,exports.AbilityMatch=a,exports.AbilityParserError=s,exports.AbilityPolicy=f,exports.AbilityPolicyEffect=d,exports.AbilityResolver=m,exports.AbilityResult=u,exports.AbilityRule=y,exports.AbilityRuleSet=g,exports.AbilityStrategy=O,exports.AbilityTypeGenerator=class{policies;policyEntries;constructor(t){this.policies=t,this.policyEntries=t.map(t=>({policy:t,normalizedPermission:m.normalizePermission(t.permission),segments:m.normalizePermission(t.permission).split(".")}))}generateTypeDefs(){const t={},e={},s=new Set;this.policies.forEach(i=>{i.tags.forEach(t=>s.add(t));const r=i.permission;t[r]||(t[r]={}),i.ruleSet.forEach(s=>{s.rules.forEach(s=>{const i=s.subject,n=this.determineTypeFromRule(s);if(n){if(i.startsWith("env.")){const t=i.replace(/^env\./,"");e[r]||(e[r]={}),e[r][t]=n}else{const e=t[r][i];t[r][i]=e&&e!==n?`${e} | ${n}`:n}if("string"==typeof s.resource&&this.isPath(s.resource)){const i=s.resource;if(i.startsWith("env.")){const t=i.replace(/^env\./,"");e[r]||(e[r]={});const s=e[r][t],a=n;e[r][t]=s&&s!==a?`${s} | ${a}`:a}else{t[r]||(t[r]={});const e=t[r][i],s=n;t[r][i]=e&&e!==s?`${e} | ${s}`:s}}}})})});const i={};Object.entries(t).forEach(([t,e])=>{t.endsWith(".*")||(i[t]=e)});const r=this.buildNestedStructure(i),n=this.buildNestedStructure(e);return this.formatTypeDefinitions(r,n,s)}isPath(t){return"string"==typeof t&&!t.startsWith('"')&&!t.startsWith("'")&&t.includes(".")}determineTypeFromRule(t){return t.condition===i.never||t.condition===i.always?null:t.condition===i.contains||t.condition===i.not_contains?this.getArrayType(t.resource):t.condition===i.length_equals||t.condition===i.length_greater_than||t.condition===i.length_less_than?"string | readonly unknown[]":t.condition===i.greater_than||t.condition===i.greater_or_equal||t.condition===i.less_than||t.condition===i.less_or_equal?"number":t.condition===i.in||t.condition===i.not_in?this.getInArrayType(t.resource):t.condition===i.equals||t.condition===i.not_equals?this.getPrimitiveType(t.resource):"any"}getArrayType(t){return`readonly ${this.getInArrayType(t)}[]`}getInArrayType(t){if(Array.isArray(t)){if(0===t.length)return"unknown";const e=new Set(t.map(t=>this.getPrimitiveType(t)));return 1===e.size?Array.from(e)[0]:`(${Array.from(e).join(" | ")})`}return this.getPrimitiveType(t)}getPrimitiveType(t){if(null===t)return"null | unknown";if(void 0===t)return"undefined";if("string"==typeof t&&this.isPath(t))return"unknown";switch(typeof t){case"string":return"string";case"number":return"number";case"boolean":return"boolean";case"object":return Array.isArray(t)?"array":"object";default:return"any"}}buildNestedStructure(t){const e={};return Object.entries(t).forEach(([t,s])=>{e[t]={},Object.entries(s).forEach(([s,i])=>{const r=s.split(".");let n=e[t];for(let t=0;t<r.length-1;t++){const e=r[t],s=n[e];if(s&&"object"==typeof s)n=s;else{const t={};n[e]=t,n=t}}n[r[r.length-1]]=i})}),e}formatTypeDefinitions(t,e,s){let i="// Automatically generated by via-profit/ability\n";i+="// Do not edit manually\n",i+="export type Resources = {\n",Object.keys(t).sort().forEach(e=>{const s=t[e],r=0===Object.keys(s).length,n=m.normalizePermission(e).split("."),a=this.policyEntries.filter(t=>m.matchPermissions(t.segments,n)).map(t=>t.policy),o=[...new Set(a.map(t=>t.effect))].sort(),c=a.sort((t,e)=>t.id.localeCompare(e.id)).map(t=>{const e=t.effect.padEnd(6," "),s=t.name===t.id?"Unnamed policy":t.name;return` * - ${e} ${t.id} "${s}"`}).join("\n");i+=`\n /**\n * Permission: ${e}\n * Effects: ${o.join(", ")}\n * Policies:\n${c}\n */\n`,r?i+=` ['${e}']: undefined;\n`:(i+=` ['${e}']: {\n`,i+=this.formatNestedObject(s,4),i+=" } | null | undefined;\n")}),i+="}\n";const r=s.size>0?Array.from(s).sort().map(t=>`'${t}'`).join(" | "):"never";return i+=`\n\nexport type PolicyTags = ${r};\n`,i+="\n\nexport type Environment = {\n",Object.entries(e).forEach(([t,e])=>{const s=0===Object.keys(e).length,r=m.normalizePermission(t).split("."),n=this.policyEntries.filter(t=>m.matchPermissions(t.segments,r)).map(t=>t.policy),a=[...new Set(n.map(t=>t.effect))].sort(),o=n.sort((t,e)=>t.id.localeCompare(e.id)).map(t=>{const e=t.effect.padEnd(6," "),s=t.name===t.id?"Unnamed policy":t.name;return` * - ${e} ${t.id} "${s}"`}).join("\n");i+=`\n /**\n * Permission: ${t}\n * Effects: ${a.join(", ")}\n * Policies:\n${o}\n */\n`,s?i+=` ['${t}']: undefined;\n`:(i+=` ['${t}']: {\n`,i+=this.formatNestedObject(e,4),i+=" } | null | undefined;\n")}),i+="}\n",i}formatNestedObject(t,e){const s=" ".repeat(e);let i="";return Object.keys(t).sort().forEach(r=>{const n=t[r];if("object"==typeof n&&null!==n)i+=`${s}readonly ${r}: {\n`,i+=this.formatNestedObject(n,e+2),i+=`${s}} | null | undefined;\n`;else{const t=[String(n)];let e=String(n);e.match(/unknown/)||(e.match(/null/)||t.push("null"),e.match(/undefined/)||t.push("undefined")),i+=`${s}readonly ${r}: ${t.join(" | ")} \n`}}),i}},exports.AllMustPermitStrategy=class extends O{_decisive=null;evaluate(){if(!this.hasMatched())return this._decisive=null,d.deny;const t=this.firstDenied();return t?(this._decisive=t,d.deny):(this._decisive=this.firstPermitted(),d.permit)}decisivePolicy(){return this._decisive}},exports.AnyPermitStrategy=class extends O{_decisive=null;evaluate(){const t=this.firstPermitted();return t?(this._decisive=t,d.permit):(this._decisive=null,d.deny)}decisivePolicy(){return this._decisive}},exports.DenyOverridesStrategy=class extends O{_decisive=null;evaluate(){const t=this.firstDenied();if(t)return this._decisive=t,d.deny;const e=this.firstPermitted();return e?(this._decisive=e,d.permit):(this._decisive=null,d.deny)}decisivePolicy(){return this._decisive}},exports.FirstMatchStrategy=class extends O{_decisive=null;evaluate(){const t=this.firstMatched();return t?(this._decisive=t,t.effect):(this._decisive=null,d.deny)}decisivePolicy(){return this._decisive}},exports.OnlyOneApplicableStrategy=class extends O{_decisive=null;evaluate(){const t=this.matchedPolicies();return 1===t.length?(this._decisive=t[0],t[0].effect):(this._decisive=null,d.deny)}decisivePolicy(){return this._decisive}},exports.PermitOverridesStrategy=class extends O{_decisive=null;evaluate(){const t=this.matchedPolicies().find(t=>t.effect===d.permit);if(t)return this._decisive=t,d.permit;const e=this.matchedPolicies().find(t=>t.effect===d.deny);return e?(this._decisive=e,d.deny):(this._decisive=null,d.deny)}decisivePolicy(){return this._decisive}},exports.PriorityStrategy=class extends O{_decisive=null;evaluate(){const t=this.matchedPolicies();if(0===t.length)return this._decisive=null,d.deny;const e=[...t].sort((t,e)=>e.priority-t.priority)[0];return this._decisive=e,e.effect}decisivePolicy(){return this._decisive}},exports.SequentialLastMatchStrategy=class extends O{_decisive=null;evaluate(){const t=this.lastMatched();return t?(this._decisive=t,t.effect):(this._decisive=null,d.deny)}decisivePolicy(){return this._decisive}},exports.TokenTypes=_,exports.ability=function(t,...e){const s=t.reduce((t,s,i)=>t+s+(e[i]??""),"");return new k(s).parse()},exports.fromLiteral=function(t){const e={equals:i.equals,not_equals:i.not_equals,greater_than:i.greater_than,less_than:i.less_than,less_or_equal:i.less_or_equal,greater_or_equal:i.greater_or_equal,in:i.in,not_in:i.not_in,contains:i.contains,not_contains:i.not_contains,length_greater_than:i.length_greater_than,length_less_than:i.length_less_than,length_equals:i.length_equals,always:i.always,never:i.never,defined:i.defined,not_defined:i.not_defined},r=e[t];if(!r){const i=Object.keys(e).join(", ");throw new s(`Literal "${t}" does not found in AbilityCondition. Expected one of: ${i}`)}return r},exports.isConditionEqual=n,exports.isConditionNotEqual=function(t,e){return!n(t,e)},exports.toLiteral=r;
|
|
1
|
+
"use strict";const t={or:"or",and:"and"};class e extends Error{constructor(t,e){super(t,e),this.name="AbilityError",Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}}class s extends Error{constructor(t,e){super(t,e),this.name="AbilityParserError",Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}}const i={equals:"=",defined:"defined",not_defined:"not_defined",not_equals:"<>",greater_than:">",less_than:"<",less_or_equal:"<=",greater_or_equal:">=",in:"in",not_in:"not in",contains:"contains",not_contains:"not contains",length_greater_than:"length greater than",length_less_than:"length less than",length_equals:"length equals",always:"always",never:"never"};function r(t){switch(t){case i.equals:return"equals";case i.not_equals:return"not_equals";case i.greater_than:return"greater_than";case i.less_than:return"less_than";case i.less_or_equal:return"less_or_equal";case i.greater_or_equal:return"greater_or_equal";case i.in:return"in";case i.not_in:return"not_in";case i.contains:return"contains";case i.not_contains:return"not_contains";case i.length_greater_than:return"length_greater_than";case i.length_less_than:return"length_less_than";case i.length_equals:return"length_equals";case i.always:return"always";case i.never:return"never";case i.defined:return"defined";case i.not_defined:return"not_defined";default:return"never"}}function n(t,e){return null!==t&&null!==e&&t===e}const a={pending:"pending",match:"match",mismatch:"mismatch",exceptMismatch:"except-mismatch",disabled:"disabled"};class o{type;children;_name;match;debugInfo;constructor(t,e=[]){this.type=t.type,this.children=e,this._name=t.name,this.match=t.match,this.debugInfo=t.debugInfo}get name(){const t=this._name.substring(0,60);return`${t}${t.length<this._name.length?"...":""}`}toString(t="",e=!0){const s=this.match===a.match,i=this.match===a.mismatch,r=this.match===a.pending,n=`[${s?"MATCH ✓":i?"MISMATCH ✗":r?"PENDING …":"DISABLED ⊘"}]`.padEnd(15," "),o=("policy"===this.type?"POLICY":"ruleSet"===this.type?"RULESET":"RULE").padEnd(10," ");let c=`${t}${0===t.length?"":e?"└─ ":"├─ "}${n}${o}${this.name}`;this.debugInfo&&(c+=` (${this.debugInfo})`);const h=t+(e?" ":"│ ");return this.children.forEach((t,e)=>{c+="\n"+t.toString(h,e===this.children.length-1)}),c}}class c extends o{constructor(t){super({type:"rule",match:t.state,name:t.name,debugInfo:`${t.subject} ${t.condition} ${JSON.stringify(t.resource)}`})}}class h extends o{constructor(t){const e=t.rules.map(t=>new c(t));super({type:"ruleSet",match:t.state,name:t.name},e)}}class l extends o{constructor(t){const e=t.ruleSet.map(t=>new h(t));super({type:"policy",name:t.priority>-1?`@priority ${t.priority} <${t.effect}> ${t.name}`:`<${t.effect}> ${t.name}`,match:t.matchState},e)}}class u{effect;strategy;constructor(t,e){this.effect=t,this.strategy=e}explain(){return`${this.strategy.isDenied()?"== DENIED==":"== ALLOWED =="}\n${this.strategy.policies.map(t=>new l(t).toString()).join("\n")}\n`}decisive(){return this.strategy.decisivePolicy()}explainDecisive(){const t=this.decisive();return t?new l(t).toString():null}isAllowed=()=>this.strategy.isAllowed();isDenied=()=>this.strategy.isDenied()}const d={deny:"deny",permit:"permit"};class m{onDeny;onAllow;StrategyClass;policyEntries;constructor(t,e,s={}){const i=this.toArray(t);this.onDeny=s.onDeny,this.onAllow=s.onAllow;const r=[...s.tags?i.filter(t=>t.tags.some(t=>s.tags.includes(t))):i].sort((t,e)=>e.priority-t.priority);this.policyEntries=r.map(t=>({policy:t,normalizedPermission:m.normalizePermission(t.permission),segments:m.normalizePermission(t.permission).split(".")})),this.StrategyClass=e}resolve(t,s,i){const r=m.normalizePermission(String(t)).split("."),n=this.policyEntries.filter(t=>m.matchPermissions(t.segments,r)).map(t=>t.policy);for(const t of n)if(!t.disabled&&t.check(s,i)===a.pending)throw new e(`The policy "${t.name}" is still in a pending state. Make sure to call "check" to evaluate the policy before resolving permissions.`);const o=new this.StrategyClass(n),c=o.evaluate(),h=new u(c,o);return c===d.deny&&this.onDeny&&this.onDeny(h),c===d.permit&&this.onAllow&&this.onAllow(h),h}enforce(t,s,i,r){const n=this.resolve(t,s,i);if(n.isDenied())throw r?.onDeny&&r?.onDeny(n),new e("Permission denied")}static isInPermissionContain(t,e){const s=t.split("."),i=e.split("."),[r,n]=s.length>=i.length?[s,i]:[i,s];return n.every((t,e)=>"*"===t||"*"===r[e]||t===r[e])}toArray(t){return[...Array.isArray(t)?t:[t]]}static normalizePermission(t){return t.trim().replace(/^permission\./,"").replace(/\.+/g,".").toLowerCase()}static matchPermissions(t,e){let s=0;for(;s<t.length;s++){const i=t[s],r=e[s];if("*"===i)return!0;if(void 0===r)return!1;if(i!==r)return!1}return s===e.length}}class p{static sha1(t){const e=p.stringToBytes(t),s=8*e.length,i=new Uint8Array(e.length+1);i.set(e,0),i[e.length]=128;let r=(56-i.length%64+64)%64;const n=new Uint8Array(i.length+r+8);n.set(i,0);const a=Math.floor(s/4294967296),o=s>>>0;n[n.length-8]=a>>>24&255,n[n.length-7]=a>>>16&255,n[n.length-6]=a>>>8&255,n[n.length-5]=255&a,n[n.length-4]=o>>>24&255,n[n.length-3]=o>>>16&255,n[n.length-2]=o>>>8&255,n[n.length-1]=255&o;let c=1732584193,h=4023233417,l=2562383102,u=271733878,d=3285377520;const m=new Array(80);for(let t=0;t<n.length;t+=64){for(let e=0;e<16;e++){const s=t+4*e;m[e]=n[s]<<24|n[s+1]<<16|n[s+2]<<8|n[s+3]}for(let t=16;t<80;t++)m[t]=p.leftRotate(m[t-3]^m[t-8]^m[t-14]^m[t-16],1);let e=c,s=h,i=l,r=u,a=d;for(let t=0;t<80;t++){let n,o;t<20?(n=s&i|~s&r,o=1518500249):t<40?(n=s^i^r,o=1859775393):t<60?(n=s&i|s&r|i&r,o=2400959708):(n=s^i^r,o=3395469782);const c=p.leftRotate(e,5)+n+a+o+(0|m[t])|0;a=r,r=i,i=p.leftRotate(s,30),s=e,e=c}c=c+e|0,h=h+s|0,l=l+i|0,u=u+r|0,d=d+a|0}return[p.toHex32(c),p.toHex32(h),p.toHex32(l),p.toHex32(u),p.toHex32(d)].join("")}static leftRotate(t,e){return(t<<e|t>>>32-e)>>>0}static toHex32(t){return(t>>>0).toString(16).padStart(8,"0")}static stringToBytes(t){if("undefined"!=typeof TextEncoder)return(new TextEncoder).encode(t);{const e=Buffer.from(t,"utf8");return new Uint8Array(e.buffer,e.byteOffset,e.byteLength)}}}class f{matchState=a.pending;ruleSet=[];effect;compareMethod=t.and;id;name;description;permission;priority=-1;disabled;tags;constructor(e){const{name:s,description:i,id:r,permission:n,effect:a,compareMethod:o=t.and,priority:c,disabled:h,tags:l}=e;this.permission=n,this.description=i,this.effect=a,this.compareMethod=o,this.priority="number"==typeof c?c:-1,this.disabled="boolean"==typeof h&&h,this.tags=l||[],this.id=r||`p_${this.hash().slice(0,10)}`,this.name=s||this.id}addRuleSet(t){return this.ruleSet.push(t),this}addRuleSets(t){for(const e of t)this.ruleSet.push(e);return this}extractRules(){const t=[];for(const e of this.ruleSet)for(const s of e.rules)t.push(s);return t}check(e,s){if(this.matchState=a.mismatch,this.disabled)return this.matchState=a.disabled,this.matchState;if(!this.ruleSet.length)return this.matchState;const i=this.ruleSet.filter(t=>!t.isExcept),r=this.ruleSet.filter(t=>t.isExcept),n=[];for(const r of i){if(r.disabled)continue;const i=r.check(e,s);if(n.push(i),t.and===this.compareMethod&&a.mismatch===i)return this.matchState=a.mismatch,this.matchState;if(t.or===this.compareMethod&&a.match===i){this.matchState=a.match;break}}let o=!1;if(o=t.and===this.compareMethod?n.every(t=>a.match===t):n.some(t=>a.match===t),!o)return this.matchState=a.mismatch,this.matchState;for(const t of r){if(t.disabled)continue;const i=t.check(e,s);if(a.match===i)return this.matchState=a.exceptMismatch,this.matchState}return this.matchState=a.match,this.matchState}explain(){if(this.matchState===a.pending)throw new e("First, run the check method, then explain");return new l(this)}copyWith(t){const e=new f({id:t.id??this.id,name:t.name??this.name,description:t.description??this.description,priority:void 0!==t.priority?t.priority:this.priority,permission:t.permission??this.permission,effect:t.effect??this.effect,compareMethod:t.compareMethod??this.compareMethod}),s=t.ruleSet??this.ruleSet;for(const t of s)e.addRuleSet(t);return e}hash(){const t=[`permission:${this.permission}`,`effect:${this.effect}`,`compareMethod:${this.compareMethod}`,`priority:${this.priority}`,`disabled:${this.disabled}`];if(this.tags&&this.tags.length>0&&t.push(`tags:${[...this.tags].sort().join(",")}`),this.ruleSet&&this.ruleSet.length>0){const e=this.ruleSet.map(t=>t.hash());t.push(`rules:${e.sort().join("|")}`)}const e=t.join(";");return p.sha1(e)}}class y{subject;resource;condition;name;description;id;state=a.pending;disabled;constructor(t){const{id:e,name:s,subject:i,resource:r,condition:n,disabled:o,description:c}=t;this.description=c,this.disabled="boolean"==typeof o&&o,this.subject=i,this.resource=r,this.condition=n,this.state=this.disabled?a.disabled:this.state,this.id=e||`r_${this.hash().slice(0,10)}`,this.name=s||this.id}static isPrimitive(t){return"string"==typeof t||"number"==typeof t||"boolean"==typeof t||null===t}static isNumber(t){return"number"==typeof t}static isString(t){return"string"==typeof t}static valueLen=t=>this.isString(t)||Array.isArray(t)?t.length:null;static operatorHandlers={[r(i.always)]:()=>!0,[r(i.defined)]:t=>void 0!==t,[r(i.not_defined)]:t=>void 0===t,[r(i.never)]:()=>!1,[r(i.equals)]:(t,e)=>t===e,[r(i.not_equals)]:(t,e)=>t!==e,[r(i.contains)]:(t,e)=>Array.isArray(t)&&y.isPrimitive(e)?t.includes(e):!(!Array.isArray(t)||!Array.isArray(e))&&t.some(t=>e.includes(t)),[r(i.not_contains)]:(t,e)=>Array.isArray(t)&&y.isPrimitive(e)?!t.includes(e):!(!Array.isArray(t)||!Array.isArray(e)||t.some(t=>e.includes(t))),[r(i.in)]:(t,e)=>y.isPrimitive(t)&&Array.isArray(e)?e.includes(t):!(!Array.isArray(t)||!Array.isArray(e))&&t.some(t=>e.includes(t)),[r(i.not_in)]:(t,e)=>y.isPrimitive(t)&&Array.isArray(e)?!e.includes(t):!(!Array.isArray(t)||!Array.isArray(e)||t.some(t=>e.includes(t))),[r(i.greater_than)]:(t,e)=>!(!y.isNumber(t)||!y.isNumber(e))&&t>e,[r(i.less_than)]:(t,e)=>!(!y.isNumber(t)||!y.isNumber(e))&&t<e,[r(i.greater_or_equal)]:(t,e)=>!(!y.isNumber(t)||!y.isNumber(e))&&t>=e,[r(i.less_or_equal)]:(t,e)=>!(!y.isNumber(t)||!y.isNumber(e))&&t<=e,[r(i.length_greater_than)]:(t,e)=>{const s=y.valueLen(t);if(null===s)return!1;if(y.isNumber(e))return s>e;const i=y.valueLen(e);return null!==i&&s>i},[r(i.length_less_than)]:(t,e)=>{const s=y.valueLen(t);if(null===s)return!1;if(y.isNumber(e))return s<e;const i=y.valueLen(e);return null!==i&&s<i},[r(i.length_equals)]:(t,e)=>{const s=y.valueLen(t);if(null===s)return!1;if(y.isNumber(e))return s===e;const i=y.valueLen(e);return null!==i&&s===i}};check(t,e){if(this.disabled)return this.state=a.disabled,this.state;const[s,i]=this.extractValues(t,e),n=(0,y.operatorHandlers[r(this.condition)])(s,i);return this.state=n?a.match:a.mismatch,this.state}extractValues(t,e){let s,i;return null==t&&null==e?[NaN,NaN]:(s=this.subject.includes(".")?this.subject.startsWith("env.")&&void 0!==e?this.getDotNotationValue(e,this.subject.replace(/^env\./,"")):this.getDotNotationValue(t,this.subject):this.subject,i="string"==typeof this.resource&&this.resource.includes(".")?this.resource.startsWith("env.")&&void 0!==e?this.getDotNotationValue(e,this.resource.replace(/^env\./,"")):this.getDotNotationValue(t,this.resource):this.resource,[s,i])}static _pathCache=new Map;static _parsePath(t){const e=y._pathCache.get(t);if(e)return e;const s=t.split("."),i=[];for(const t of s){const e=t.indexOf("[");if(-1!==e){const s=t.slice(0,e),r=t.slice(e+1,-1),n=Number(r);i.push({prop:s,index:n})}else i.push(t)}return y._pathCache.set(t,i),i}getDotNotationValue(t,e){if(null==t)return;const s=y._parsePath(e);let i=t;for(const t of s){if(null==i)return;if("string"==typeof t)i=i[t];else{const e=i[t.prop];i=Array.isArray(e)?e[t.index]:void 0}}return i}toString(){return`AbilityRule: ${this.name} condition: ${r(this.condition)} subject: "${this.subject?.toString()}" resource: "${this.resource?.toString()}"`}copyWith(t){return new y({id:t.id??this.id,name:t.name??this.name,description:t.description??this.description,subject:t.subject??this.subject,resource:t.resource??this.resource,condition:t.condition??this.condition})}hash(){const t=[];return t.push(`subject:${this.subject}`),t.push(`resource:${JSON.stringify(this.resource)}`),t.push(`condition:${this.condition}`),t.push(`disabled:${this.disabled}`),p.sha1(t.join(";"))}static equals(t,e){return new y({condition:i.equals,subject:t,resource:e})}static notEquals(t,e){return new y({condition:i.not_equals,subject:t,resource:e})}static contains(t,e){return new y({condition:i.contains,subject:t,resource:e})}static notContains(t,e){return new y({condition:i.not_contains,subject:t,resource:e})}static notIn(t,e){return new y({condition:i.not_in,subject:t,resource:e})}static in(t,e){return new y({condition:i.in,subject:t,resource:e})}static notEqual(t,e){return new y({condition:i.not_equals,subject:t,resource:e})}static lessThan(t,e){return new y({condition:i.less_than,subject:t,resource:e})}static lessOrEqual(t,e){return new y({condition:i.less_or_equal,subject:t,resource:e})}static moreThan(t,e){return new y({condition:i.greater_than,subject:t,resource:e})}static moreOrEqual(t,e){return new y({condition:i.greater_or_equal,subject:t,resource:e})}}class g{state=a.pending;rules=[];compareMethod=t.and;name;description;id;isExcept=!1;disabled;constructor(t){const{name:e,id:s,compareMethod:i,isExcept:r,disabled:n,description:o}=t;this.description=o,this.compareMethod=i,this.isExcept=r,this.disabled="boolean"==typeof n&&n,this.state=this.disabled?a.disabled:this.state,this.id=s||`g_${this.hash().slice(0,10)}`,this.name=e||this.id}addRule(t){return this.rules.push(t),this}addRules(t){return t.forEach(t=>this.addRule(t)),this}check(e,s){if(this.state=a.mismatch,this.disabled)return this.state=a.disabled,this.state;if(!this.rules.length)return this.state;const i=[];for(const r of this.rules){if(r.disabled)continue;const n=r.check(e,s);if(i.push(n),t.and===this.compareMethod&&a.mismatch===n)return this.state;if(t.or===this.compareMethod&&a.match===n)return this.state=a.match,this.state}return t.and===this.compareMethod&&i.every(t=>a.match===t)&&(this.state=a.match),t.or===this.compareMethod&&i.some(t=>a.match===t)&&(this.state=a.match),this.state}toString(){return`AbilityRuleSet: ${this.name} compareMethod: ${this.compareMethod}, rules: ${this.rules.map(t=>t.toString()).join("\n")}`}copyWith(t){const e=new g({id:t.id??this.id,name:t.name??this.name,description:t.description??this.description,compareMethod:t.compareMethod??this.compareMethod}),s=t.rules??this.rules;for(const t of s)e.addRule(t);return e}hash(){const t=this.rules.map(t=>t.hash()).sort(),e=[`compareMethod:${this.compareMethod}`,`isExcept:${this.isExcept}`,`disabled:${this.disabled}`,`rules:${t.join("|")}`];return p.sha1(e.join(";"))}static and(e){return new g({compareMethod:t.and}).addRules(e)}static or(e){return new g({compareMethod:t.or}).addRules(e)}}class E{static parse(t){return t.map(t=>E.parsePolicy(t))}static parsePolicy(t){const{id:e,name:s,ruleSet:i,compareMethod:r,permission:n,effect:a,priority:o,disabled:c,tags:h}=t,l=new f({name:s,id:e,permission:n,priority:o,effect:a,disabled:c,tags:h});return l.compareMethod=r,i.forEach(t=>{l.addRuleSet(E.parseRuleSet(t))}),l}static parseRule(t){const{id:e,name:s,subject:i,resource:r,condition:n,disabled:a}=t;return new y({id:e,name:s,subject:i,resource:r,disabled:a,condition:n})}static parseRuleSet(t){const{id:e,name:s,rules:i,compareMethod:r,disabled:n}=t,a=new g({disabled:n,compareMethod:r,name:s,id:e});if(i&&i.length>0){const t=i.map(t=>E.parseRule(t));a.addRules(t)}return a}static ruleToJSON(t){return{id:t.id,name:t.name,disabled:t.disabled,subject:t.subject,resource:t.resource,condition:t.condition}}static ruleSetToJSON(t){return{id:t.id.toString(),name:t.name.toString(),disabled:t.disabled,compareMethod:t.compareMethod,rules:t.rules.map(t=>E.ruleToJSON(t))}}static policyToJSON(t){return{id:t.id.toString(),name:t.name.toString(),disabled:t.disabled,priority:t.priority,permission:t.permission,effect:t.effect,compareMethod:t.compareMethod,tags:t.tags,ruleSet:t.ruleSet.map(t=>E.ruleSetToJSON(t))}}static toJSON(t){return t.map(t=>E.policyToJSON(t))}}const _={EFFECT:"EFFECT",IF:"IF",PERMISSION:"PERMISSION",IDENTIFIER:"IDENTIFIER",COLON:"COLON",COMMA:"COMMA",DOT:"DOT",LBRACKET:"LBRACKET",RBRACKET:"RBRACKET",ALL:"ALL",ANY:"ANY",OF:"OF",EOF:"EOF",COMMENT:"COMMENT",EQ:"EQ",CONTAINS:"CONTAINS",IN:"IN",NOT_IN:"NOT_IN",NOT_CONTAINS:"NOT_CONTAINS",GT:"GT",GTE:"GTE",LT:"LT",LTE:"LTE",NULL:"NULL",EQ_NULL:"EQ_NULL",NOT_EQ_NULL:"NOT_EQ_NULL",DEFINED:"DEFINED",NOT_EQ:"NOT_EQ",LEN_GT:"LEN_GT",LEN_LT:"LEN_LT",LEN_EQ:"LEN_EQ",ALWAYS:"ALWAYS",NEVER:"NEVER",EXCEPT:"EXCEPT",ANNOTATION:"ANNOTATION",STRING:"STRING",NUMBER:"NUMBER",BOOLEAN:"BOOLEAN",SYMBOL:"SYMBOL",KEYWORD:"KEYWORD",ALIAS:"ALIAS",UNKNOWN:"UNKNOWN"};class A{type;value;line;column;constructor(t,e,s,i){this.type=t,this.value=e,this.line=s,this.column=i}toString(){return`AbilityDSLToken([${this.type}] "${this.value}" at ${this.line}:${this.column})`}}class v{input;pos=0;tokens=[];line=1;column=1;keywords=new Set(["if","all","any","of","permit","allow","deny","forbidden","true","false","null","defined","contains","includes","length","len","has","in","gt","lt","gte","lte","equals","greater","less","not","is","or","than","always","never","except","alias"]);constructor(t){this.input=t}tokenize(){for(;!this.isAtEnd()&&(this.skipWhitespace(),!this.isAtEnd());){const t=this.peek();if("@"!==t)if("#"!==t)if('"'!==t&&"'"!==t)if(this.isDigit(t))this.tokens.push(this.readNumber());else if(this.isSymbol(t))this.tokens.push(this.readSymbol());else{if(!this.isAlpha(t))throw new Error(`Unexpected character '${t}' at ${this.line}:${this.column}`);this.tokens.push(this.readWord())}else this.tokens.push(this.readString());else this.tokens.push(this.readComment());else this.tokens.push(this.readAnnotation())}return this.tokens.push(new A(_.EOF,"",this.line,this.column)),this.tokens}readComment(){const t=this.line,e=this.column;this.advance();let s="";for(;!this.isAtEnd()&&!this.isNewline();)s+=this.advance();return new A(_.COMMENT,s.trim(),t,e)}readAnnotation(){const t=this.line,e=this.column;let s="";for(;!this.isAtEnd()&&!this.isNewline();)s+=this.advance();s=s.trim();let i="",r=0,n=!1,a=null,o=!1;for(;r<s.length;){const t=s[r];n?(o?(i+=t,o=!1):"\\"===t?o=!0:t===a?(n=!1,a=null):i+=t,r++):'"'!==t&&"'"!==t?(i+=t,r++):(n=!0,a=t,r++)}return new A(_.ANNOTATION,i.trim(),t,e)}readString(){const t=this.line,e=this.column,s=this.advance();let i="",r=!1;for(;!this.isAtEnd();){const n=this.advance();if(r)i+=n,r=!1;else if("\\"!==n){if(n===s)return new A(_.STRING,i,t,e);i+=n}else r=!0}throw new Error(`Unterminated string at ${t}:${e}`)}readNumber(){const t=this.line,e=this.column,s=this.pos;for(;!this.isAtEnd()&&this.isDigit(this.peek());)this.advance();const i=this.input.slice(s,this.pos);return new A(_.NUMBER,i,t,e)}readSymbol(){const t=this.line,e=this.column,s=this.advance();switch(s){case".":return new A(_.DOT,s,t,e);case":":return new A(_.COLON,s,t,e);case",":return new A(_.COMMA,s,t,e);case"[":return new A(_.LBRACKET,s,t,e);case"]":return new A(_.RBRACKET,s,t,e);case">":return"="===this.peek()?(this.advance(),new A(_.SYMBOL,">=",t,e)):new A(_.SYMBOL,">",t,e);case"<":return"="===this.peek()?(this.advance(),new A(_.SYMBOL,"<=",t,e)):">"===this.peek()?(this.advance(),new A(_.SYMBOL,"<>",t,e)):new A(_.SYMBOL,"<",t,e);case"=":return"="===this.peek()?(this.advance(),new A(_.SYMBOL,"==",t,e)):new A(_.SYMBOL,"=",t,e);case"!":if("="===this.peek())return this.advance(),new A(_.SYMBOL,"!=",t,e);throw new Error(`Unexpected symbol '!' at ${this.line}:${this.column}`);default:throw new Error(`Unknown symbol '${s}' at ${this.line}:${this.column}`)}}readWord(){const t=this.line,e=this.column,s=this.pos;for(;!this.isAtEnd()&&/[a-zA-Z0-9_*]/.test(this.peek());)this.advance();for(;!this.isAtEnd()&&"."===this.peek()&&(this.advance(),/[a-zA-Z_*]/.test(this.peek()));)for(;!this.isAtEnd()&&/[a-zA-Z0-9_*]/.test(this.peek());)this.advance();const i=this.input.slice(s,this.pos);if("always"===i)return new A(_.ALWAYS,i,t,e);if("never"===i)return new A(_.NEVER,i,t,e);if(i.includes(".")){const s=this.tokens[this.tokens.length-1];return s?.type===_.EFFECT&&i.startsWith("permission.")?new A(_.PERMISSION,i,t,e):new A(_.IDENTIFIER,i,t,e)}if(this.keywords.has(i))return"permit"===i||"allow"===i?new A(_.EFFECT,"permit",t,e):"deny"===i||"forbidden"===i?new A(_.EFFECT,"deny",t,e):new A("all"===i?_.ALL:"any"===i?_.ANY:"of"===i?_.OF:"if"===i?_.IF:"true"===i||"false"===i?_.BOOLEAN:"null"===i?_.NULL:"defined"===i?_.DEFINED:"except"===i?_.EXCEPT:"alias"===i?_.ALIAS:_.KEYWORD,i,t,e);const r=this.tokens[this.tokens.length-1];return new A(r?.type===_.EFFECT?_.PERMISSION:_.IDENTIFIER,i,t,e)}skipWhitespace(){for(;!this.isAtEnd()&&/\s/.test(this.peek());)this.advance()}isDigit(t){return t>="0"&&t<="9"}isAlpha(t){return/[a-zA-Z_]/.test(t)}isSymbol(t){return[".",":",",","[","]",">","<","=","!"].includes(t)}isNewline(){return"\n"===this.peek()}peek(){return this.input[this.pos]}advance(){const t=this.input[this.pos++];return"\n"===t?(this.line++,this.column=1):this.column++,t}isAtEnd(){return this.pos>=this.input.length}}class S extends Error{line;column;context;details;_formattedMessage;_originalStack;constructor(t,e,s,i){super(i.split("\n")[0]),this.line=t,this.column=e,this.context=s,this.details=i,this.name="AbilityDSLSyntaxError",Error.captureStackTrace&&Error.captureStackTrace(this,S),this._originalStack=this.stack,this._formattedMessage=this.formatMessage(),Object.defineProperty(this,"stack",{get:()=>this._formattedMessage,configurable:!0})}static supportsColor(){return"undefined"!=typeof process&&process.stdout?.isTTY}formatMessage(){const t=S.supportsColor(),e=t?"[1m":"",s=t?"[31m":"",i=t?"[33;1m":"",r=t?"[90m":"",n=t?"[0m":"",a=this.context.split("\n"),o=a.findIndex(t=>t.includes("^")||t.includes("~")),c=a.findIndex(t=>t.trim().includes("#")),h=a.map((t,a)=>a===o-1?`${e}${i}${t}${n}`:a===o?`${s}${t}${n}`:a===c?`${r}${t}${n}`:t).join("\n");return`${e}${s}${this.name}: ${this.details}${n}\n\n`+h}toString(){return this._formattedMessage}}class b{tokens;pos=0;dsl;marks=[];lastToken=null;next(){const t=this.tokens[this.pos++];return this.lastToken=t,t}prev(){if(0===this.pos)return null;const t=this.tokens[this.pos--];return this.lastToken=t,t}lookPrev(){return this.lastToken}constructor(t,e){this.tokens=t,this.dsl=e}peek(){return this.tokens[this.pos]}eof(){return this.peek().type===_.EOF}check(t){return!this.eof()&&this.peek().type===t}match(t){return this.check(t)?this.next():null}expect(t,e){const s=this.peek();if(s&&s.type===t)return this.next();this.syntaxError(e,s,[t])}expectOneOf(t,e){const s=this.peek();for(const e of t)if(s&&s.type===e)return this.next();this.syntaxError(e,s,t)}mark(){this.marks.push(this.pos)}reset(){const t=this.marks.pop();void 0!==t&&(this.pos=t)}commit(){this.marks.pop()}syntaxError(t,e,s){const i=this.dsl.split(/\r?\n/),r=e.line-1,n=r>0?i[r-1]:"",a=i[r],o=r+1<i.length?i[r+1]:"",c=" ".repeat(Math.max(0,e.column-1))+"~".repeat(e.value.length),h=String(e.line+1).length,l=t=>String(t).padStart(h," ");let u="";""!==n.trim()&&(u+=`${l(e.line-1)} | ${n}\n`),u+=`${l(e.line)} | ${a}\n`,u+=`${" ".repeat(h)} | ${c}\n`,""!==o.trim()&&(u+=`${l(e.line+1)} | ${o}`);let d=t;if(s&&s?.length>0){const i=e.value,r=this.suggest(i,s),n=`${t}\nDetails: Unexpected value token \`${i}\``;d=r?`${n} Did you mean \`${r}\`?`:n}throw new S(e.line,e.column,u+"\n",d)}suggest(t,e){const s=[];for(const t of e)s.push(t);const i=[...new Set(s)];let r=null,n=3;for(const e of i){const s=this.levenshteinDistance(t.toLowerCase(),e.toLowerCase());s<n&&(n=s,r=e)}return r}levenshteinDistance(t,e){const s=Array.from({length:e.length+1},()=>Array.from({length:t.length+1},()=>0));for(let e=0;e<=t.length;e++)s[0][e]=e;for(let t=0;t<=e.length;t++)s[t][0]=t;for(let i=1;i<=e.length;i++)for(let r=1;r<=t.length;r++){const n=t[r-1]===e[i-1]?0:1;s[i][r]=Math.min(s[i][r-1]+1,s[i-1][r]+1,s[i-1][r-1]+n)}return s[e.length][t.length]}}class N{store={id:void 0,name:void 0,priority:void 0,description:void 0,disabled:void 0,tags:void 0};get(t){return this.store[t]??null}set(t,e,s){return this.store[t]=null===e?void 0:{key:t,value:e,token:s},this}clear(){for(const t of Object.keys(this.store))this.store[t]=void 0}clone(){const t=new N;for(const e of Object.keys(this.store)){const s=this.store[e];t.store[e]=s?{...s}:void 0}return t}get id(){return this.get("id")}get name(){return this.get("name")}get description(){return this.get("description")}get priority(){return this.get("priority")}get disabled(){return this.get("disabled")}get tags(){return this.get("tags")}setID(t,e){return this.set("id",t,e)}setName(t,e){return this.set("name",t,e)}setDescription(t,e){return this.set("description",t,e)}setPriority(t,e){return this.set("priority",t,e)}setDisabled(t,e){return this.set("disabled",t,e)}setTags(t,e){return this.set("tags",t,e)}}const x={policy:new Set(["id","name","description","priority","disabled","tags"]),ruleSet:new Set(["id","name","description","disabled"]),rule:new Set(["id","name","disabled"]),alias:new Set(["name","disabled"])};class L{store=new Map;get(t){return this.store.get(t)||null}set(t,e){return this.store.set(t,e),this}has(t){return this.store.has(t)}}class k{dsl;stream;annBuffer=new N;aliasBuffer=new L;constructor(t){this.dsl=t}parse(){this.annBuffer.clear();const t=new v(this.dsl).tokenize();this.stream=new b(t,this.dsl);const e=[];for(;!this.stream.eof();){if(this.consumeLeadingComments(),this.consumeLeadingAnnotations(),this.consumeLeadingAliases(),!this.isStartOfPolicy()){const t=this.stream.peek();this.stream.syntaxError(`Expected policy, got ${t.type}.`,t,[_.EFFECT])}e.push(this.parsePolicy())}return e}parsePolicy(){this.consumeLeadingComments(),this.consumeLeadingAnnotations(),this.consumeLeadingAliases();const e=this.takeAnnotations("policy"),s=this.stream.expect(_.EFFECT,"Expected effect").value,i=this.stream.expect(_.PERMISSION,"Expected permission"),r=i.value;if(!r.startsWith("permission."))return this.stream.syntaxError(`Unexpected token. The permission key, must be starts with prefix \`permission.\`, but got \`${r}\`.\nDid you mean \`permission.${r}\`?`,i);this.stream.expect(_.IF,'Expected "if"');const n=this.stream.expectOneOf([_.ALL,_.ANY],'Expected "all" or "any"').type===_.ALL?t.and:t.or;this.stream.expect(_.COLON,'Expected ":"');const a=this.parseRuleSets(n);return new f({id:e.id?.value||null,name:e.name?.value||null,description:e.description?.value||null,priority:e.priority?.value||null,permission:r.replace(/^permission\./,""),effect:"permit"===s?d.permit:d.deny,disabled:e.disabled?.value??void 0,tags:e.tags?.value??void 0,compareMethod:n}).addRuleSets(a)}parseRuleSets(t){const e=[];for(this.consumeLeadingComments(),this.consumeLeadingAnnotations();!this.stream.eof()&&!this.isStartOfPolicy();){if(this.isStartOfExcept()){e.push(this.parseExceptGroup(t));continue}if(this.isStartOfGroup()){e.push(this.parseGroup());continue}const s=new g({compareMethod:t});for(;!(this.stream.eof()||(this.consumeLeadingComments(),this.consumeLeadingAnnotations(),this.isStartOfGroup()||this.isStartOfPolicy()||this.isStartOfExcept()));)this.stream.check(_.IDENTIFIER)||this.stream.check(_.ALWAYS)||this.stream.check(_.NEVER)?s.addRule(this.parseRule()):this.stream.syntaxError(`Unexpected token in implicit group: ${this.stream.peek().type}`,this.stream.peek());e.push(s)}return e}parseGroup(){this.consumeLeadingComments(),this.consumeLeadingAnnotations();const e=this.takeAnnotations("ruleSet"),s=this.stream.expectOneOf([_.ALL,_.ANY,_.ALWAYS,_.NEVER],'Expected "all" or "any" or "always" or "never"').type===_.ALL?t.and:t.or;this.stream.check(_.OF)&&this.stream.next(),this.stream.expect(_.COLON,'Expected ":"');const i=new g({id:e.id?.value||null,compareMethod:s,name:e.name?.value||null,description:e.description?.value||null,disabled:e.disabled?.value??void 0});for(;!(this.stream.eof()||(this.consumeLeadingComments(),this.consumeLeadingAnnotations(),this.isStartOfExcept())||this.isStartOfGroup()||this.isStartOfPolicy());)this.stream.check(_.IDENTIFIER)?i.addRule(this.parseRule()):this.stream.syntaxError(`Unexpected token in group: ${this.stream.peek().type}`,this.stream.peek());return i}parseExceptGroup(e){this.consumeLeadingComments(),this.consumeLeadingAnnotations();const s=this.takeAnnotations("ruleSet");this.stream.expect(_.EXCEPT,'Expected "except"');let i=e;this.stream.check(_.ALL)||this.stream.check(_.ANY)?(i=this.stream.next().type===_.ALL?t.and:t.or,this.stream.check(_.OF)&&this.stream.next(),this.stream.expect(_.COLON,'Expected ":" after except group')):this.stream.expect(_.COLON,'Expected ":" after "except"');const r=new g({id:s.id?.value||null,compareMethod:i,name:s.name?.value||null,description:s.description?.value||null,isExcept:!0,disabled:s.disabled?.value??void 0});for(;!(this.stream.eof()||(this.consumeLeadingComments(),this.consumeLeadingAnnotations(),this.isStartOfGroup()||this.isStartOfPolicy()||this.isStartOfExcept()));)this.stream.check(_.IDENTIFIER)?r.addRule(this.parseRule()):this.stream.syntaxError(`Unexpected token in except group: ${this.stream.peek().type}`,this.stream.peek());return r}parseRule(){this.consumeLeadingComments(),this.consumeLeadingAnnotations();const t=this.takeAnnotations("rule"),e=this.stream.check(_.ALWAYS)||this.stream.check(_.NEVER);e||this.stream.check(_.IDENTIFIER)||this.stream.syntaxError(`Expected identifier, but got ${this.stream.peek().type}`,this.stream.peek());const s=e?"":this.stream.expect(_.IDENTIFIER,"Expected field").value;if(this.aliasBuffer.has(s))return this.aliasBuffer.get(s);const{condition:i,operator:r}=this.parseConditionOperator();let n=null,a=null;return r!==_.EQ_NULL&&r!==_.NOT_EQ_NULL&&r!==_.NULL&&r!==_.ALWAYS&&r!==_.NEVER&&r!==_.DEFINED&&(this.stream.mark(),n=this.parseValue(),a=this.stream.lookPrev(),this.stream.commit()),this.consumeLeadingComments(),this.consumeLeadingAnnotations(),this.consumeLeadingAliases(),"string"==typeof n&&a&&a.type===_.IDENTIFIER&&!a.value.includes(".")&&this.stream.syntaxError(`Expected comparison operator or value, got \`${n}\``,a,[_.KEYWORD]),new y({id:t.id?.value||null,subject:s,resource:n,condition:i,name:t.name?.value||null,description:t.description?.value||null,disabled:t.disabled?.value??void 0})}parseConditionOperator(){if(this.stream.mark(),this.matchWord("always"))return this.stream.commit(),{condition:i.always,operator:_.ALWAYS};if(this.stream.reset(),this.stream.mark(),this.matchWord("never"))return this.stream.commit(),{condition:i.never,operator:_.NEVER};if(this.stream.reset(),this.stream.mark(),(this.matchWord("length")||this.matchWord("len"))&&this.matchWord("equals"))return this.stream.commit(),{condition:i.length_equals,operator:_.LEN_EQ};if(this.stream.reset(),this.stream.mark(),(this.matchWord("length")||this.matchWord("len"))&&this.matchSymbol("="))return this.stream.commit(),{condition:i.length_equals,operator:_.LEN_EQ};if(this.stream.reset(),this.stream.mark(),(this.matchWord("length")||this.matchWord("len"))&&this.matchWord("greater")&&this.matchWord("than"))return this.stream.commit(),{condition:i.length_greater_than,operator:_.LEN_GT};if(this.stream.reset(),this.stream.mark(),(this.matchWord("length")||this.matchWord("len"))&&this.matchSymbol(">"))return this.stream.commit(),{condition:i.length_greater_than,operator:_.LEN_GT};if(this.stream.reset(),this.stream.mark(),(this.matchWord("length")||this.matchWord("len"))&&this.matchWord("less")&&this.matchWord("than"))return this.stream.commit(),{condition:i.length_less_than,operator:_.LEN_LT};if(this.stream.reset(),this.stream.mark(),(this.matchWord("length")||this.matchWord("len"))&&this.matchSymbol("<"))return this.stream.commit(),{condition:i.length_less_than,operator:_.LEN_LT};if(this.stream.reset(),this.stream.mark(),this.matchWord("greater")&&this.matchWord("than")&&this.matchWord("or")&&this.matchWord("equal"))return this.stream.commit(),{condition:i.greater_or_equal,operator:_.GTE};if(this.stream.reset(),this.stream.mark(),this.matchWord("greater")&&this.matchWord("than"))return this.stream.commit(),{condition:i.greater_than,operator:_.GT};if(this.stream.reset(),this.stream.mark(),this.matchWord("less")&&this.matchWord("than")&&this.matchWord("or")&&this.matchWord("equal"))return this.stream.commit(),{condition:i.less_or_equal,operator:_.LTE};if(this.stream.reset(),this.matchWord("less")&&this.matchWord("than"))return{condition:i.less_than,operator:_.LT};if(this.stream.reset(),this.stream.mark(),this.matchWord("not")&&this.matchWord("contains"))return this.stream.commit(),{condition:i.not_contains,operator:_.NOT_CONTAINS};if(this.stream.reset(),this.stream.mark(),this.matchWord("not")&&this.matchWord("includes"))return this.stream.commit(),{condition:i.not_contains,operator:_.NOT_CONTAINS};if(this.stream.reset(),this.stream.mark(),this.matchWord("not")&&this.matchWord("has"))return this.stream.commit(),{condition:i.not_contains,operator:_.NOT_CONTAINS};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("equals"))return this.stream.commit(),{condition:i.equals,operator:_.EQ};if(this.stream.reset(),this.stream.mark(),this.matchWord("not")&&this.matchWord("equals"))return this.stream.commit(),{condition:i.not_equals,operator:_.NOT_EQ};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("not")&&this.matchWord("equals"))return this.stream.commit(),{condition:i.not_equals,operator:_.NOT_EQ};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("in"))return this.stream.commit(),{condition:i.in,operator:_.IN};if(this.stream.reset(),this.stream.mark(),this.matchWord("not")&&this.matchWord("in"))return this.stream.commit(),{condition:i.not_in,operator:_.NOT_IN};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("not")&&this.stream.check(_.NULL))return this.stream.next(),this.stream.commit(),{condition:i.not_equals,operator:_.NOT_EQ_NULL};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("null")&&this.stream.check(_.NULL))return this.stream.commit(),this.stream.next(),{condition:i.equals,operator:_.EQ_NULL};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("defined"))return this.stream.commit(),{condition:i.defined,operator:_.DEFINED};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("not")&&this.matchWord("defined"))return this.stream.commit(),{condition:i.not_defined,operator:_.DEFINED};this.stream.reset();const t=this.stream.peek();switch(t.type!==_.SYMBOL&&t.type!==_.KEYWORD&&t.type!==_.NULL&&this.stream.syntaxError(`Expected comparison operator, got \`${t.value}\``,t,[_.SYMBOL,_.KEYWORD,_.NULL]),this.stream.next(),t.type){case _.SYMBOL:if("="===t.value||"=="===t.value)return{condition:i.equals,operator:_.EQ};if("!="===t.value||"<>"===t.value)return{condition:i.not_equals,operator:_.NOT_EQ};if(">"===t.value)return{condition:i.greater_than,operator:_.GT};if("<"===t.value)return{condition:i.less_than,operator:_.LT};if(">="===t.value)return{condition:i.greater_or_equal,operator:_.GTE};if("<="===t.value)return{condition:i.less_or_equal,operator:_.LTE};break;case _.KEYWORD:if("contains"===t.value||"includes"===t.value||"has"===t.value)return{condition:i.contains,operator:_.CONTAINS};if("in"===t.value)return{condition:i.in,operator:_.IN};if("equals"===t.value)return{condition:i.equals,operator:_.EQ};if("gte"===t.value)return{condition:i.greater_or_equal,operator:_.GTE};if("greater"===t.value||"gt"===t.value)return{condition:i.greater_than,operator:_.GT};if("less"===t.value||"lt"===t.value)return{condition:i.less_than,operator:_.LT};if("lte"===t.value)return{condition:i.less_or_equal,operator:_.LTE};if("is"===t.value)return{condition:i.equals,operator:_.EQ}}return this.stream.syntaxError(`Unexpected operator token \`${t.value}\``,t,[_.SYMBOL,_.KEYWORD])}matchWord(t){if(this.stream.eof())return!1;const e=this.stream.peek();return(e.type===_.KEYWORD||e.type===_.IDENTIFIER||e.type===_.ALWAYS||e.type===_.NEVER||e.type===_.DEFINED)&&e.value===t&&(this.stream.next(),!0)}matchSymbol(t){if(this.stream.eof())return!1;const e=this.stream.peek();return e.type===_.SYMBOL&&e.value===t&&(this.stream.next(),!0)}parseValue(){if(this.stream.check(_.LBRACKET))return this.stream.next(),this.parseArray();const t=this.stream.peek();switch(t.type!==_.ALL&&t.type!==_.ANY&&t.type!==_.EFFECT||this.stream.syntaxError(`Unexpected ${t.type} in value position`,t),this.stream.next(),t.type){case _.STRING:return t.value;case _.NUMBER:return Number(t.value);case _.BOOLEAN:return"true"===t.value;case _.NULL:return null;case _.DEFINED:return void 0!==t.value;case _.IDENTIFIER:return t.value;default:this.stream.syntaxError(`Unexpected value token "${t.value}"`,t,[_.KEYWORD])}}parseArray(){const t=[];if(this.stream.check(_.RBRACKET))return this.stream.next(),t;for(;!this.stream.eof()&&!this.stream.check(_.RBRACKET);){const e=this.parseValue();Array.isArray(e)?t.push(...e):"string"==typeof e||"number"==typeof e||"boolean"==typeof e?t.push(e):null===e&&this.stream.syntaxError("Unexpected null in array",this.stream.peek()),this.stream.check(_.COMMA)&&this.stream.next()}return this.stream.expect(_.RBRACKET,'Expected "]"'),t}consumeLeadingComments(){for(;this.stream.check(_.COMMENT);)this.stream.next()}consumeLeadingAliases(){for(;this.stream.check(_.ALIAS);){this.stream.next();const t=this.stream.expect(_.IDENTIFIER,"Expected alias name").value;this.stream.expect(_.COLON,"Expected colon after an alias");const e=this.takeAnnotations("alias");for(;!this.stream.eof()&&!this.isStartOfAlias()&&!this.isStartOfPolicy();){const s=this.parseRule();s.name=e.get("name")?.value||t,s.description=e.get("description")?.value,!0===e.get("disabled")?.value&&(s.disabled=!0),this.aliasBuffer.set(t,s)}}}consumeLeadingAnnotations(){for(;this.stream.check(_.ANNOTATION);){const t=this.stream.next(),e=t.value.trim();if(e.startsWith("@id ")&&this.annBuffer.setID(e.slice(4).trim(),t),e.startsWith("@name ")&&this.annBuffer.setName(e.slice(6).trim(),t),e.startsWith("@description ")&&this.annBuffer.setDescription(e.slice(13).trim(),t),e.startsWith("@priority ")&&this.annBuffer.setPriority(parseInt(e.slice(10).trim(),10),t),e.startsWith("@disabled")){const s=e.slice(9).trim();this.annBuffer.setDisabled(0===s.length||"true"===e.slice(9).trim(),t)}if(e.startsWith("@tags ")){const s=e.slice(6).trim().split(",").map(t=>t.trim());this.annBuffer.setTags(s,t)}}}takeAnnotations(t){const e=this.annBuffer.clone();this.annBuffer.clear();const s=x[t];for(const i of Object.keys(e.store)){const r=e.get(i);r&&(s.has(i)||this.stream.syntaxError(`Annotation @${i} is not allowed on ${t}. Allowed: ${[...s].map(t=>"@"+t).join(", ")}`,r.token??this.stream.peek()))}return e}isStartOfPolicy(){return this.stream.check(_.EFFECT)}isStartOfGroup(){return this.stream.check(_.ALL)||this.stream.check(_.ANY)}isStartOfRule(){return this.stream.check(_.IDENTIFIER)||this.stream.check(_.ALWAYS)||this.stream.check(_.NEVER)}isStartOfExcept(){return this.stream.check(_.EXCEPT)}isStartOfAlias(){return this.stream.check(_.ALIAS)}}class O{policies;matched;constructor(t){this.policies=t,this.matched=t.filter(t=>t.matchState===a.match)}matchedPolicies(){return this.matched}hasMatched(){return this.matched.length>0}firstMatched(){return this.matchedPolicies()[0]??null}lastMatched(){const t=this.matchedPolicies();return t.length>0?t[t.length-1]:null}firstDenied(){return this.getDenyPolicies()[0]??null}firstPermitted(){return this.getPermitPolicies()[0]??null}getPermitPolicies(){return this.matched.filter(t=>t.effect===d.permit)}getDenyPolicies(){return this.matched.filter(t=>t.effect===d.deny)}hasPermit(){return this.getPermitPolicies().length>0}hasDeny(){return this.getDenyPolicies().length>0}isAllowed(){return this.evaluate()===d.permit}isDenied(){return this.evaluate()===d.deny}}exports.AbilityCompare=t,exports.AbilityCondition=i,exports.AbilityDSLLexer=v,exports.AbilityDSLParser=k,exports.AbilityDSLToken=A,exports.AbilityError=e,exports.AbilityExplain=o,exports.AbilityExplainPolicy=l,exports.AbilityExplainRule=c,exports.AbilityExplainRuleSet=h,exports.AbilityJSONParser=E,exports.AbilityMatch=a,exports.AbilityParserError=s,exports.AbilityPolicy=f,exports.AbilityPolicyEffect=d,exports.AbilityResolver=m,exports.AbilityResult=u,exports.AbilityRule=y,exports.AbilityRuleSet=g,exports.AbilityStrategy=O,exports.AbilityTypeGenerator=class{policies;policyEntries;constructor(t){this.policies=t,this.policyEntries=t.map(t=>({policy:t,normalizedPermission:m.normalizePermission(t.permission),segments:m.normalizePermission(t.permission).split(".")}))}generateTypeDefs(){const t={},e={},s=new Set;this.policies.forEach(i=>{i.tags.forEach(t=>s.add(t));const r=i.permission;t[r]||(t[r]={}),i.ruleSet.forEach(s=>{s.rules.forEach(s=>{const i=s.subject,n=this.determineTypeFromRule(s);if(n){if(i.startsWith("env.")){const t=i.replace(/^env\./,"");e[r]||(e[r]={}),e[r][t]=n}else{const e=t[r][i];t[r][i]=e&&e!==n?`${e} | ${n}`:n}if("string"==typeof s.resource&&this.isPath(s.resource)){const i=s.resource;if(i.startsWith("env.")){const t=i.replace(/^env\./,"");e[r]||(e[r]={});const s=e[r][t],a=n;e[r][t]=s&&s!==a?`${s} | ${a}`:a}else{t[r]||(t[r]={});const e=t[r][i],s=n;t[r][i]=e&&e!==s?`${e} | ${s}`:s}}}})})});const i={};Object.entries(t).forEach(([t,e])=>{t.endsWith(".*")||(i[t]=e)});const r=this.buildNestedStructure(i),n=this.buildNestedStructure(e);return this.formatTypeDefinitions(r,n,s)}isPath(t){return"string"==typeof t&&!t.startsWith('"')&&!t.startsWith("'")&&t.includes(".")}determineTypeFromRule(t){return t.condition===i.never||t.condition===i.always?null:t.condition===i.contains||t.condition===i.not_contains?this.getArrayType(t.resource):t.condition===i.length_equals||t.condition===i.length_greater_than||t.condition===i.length_less_than?"string | readonly unknown[]":t.condition===i.greater_than||t.condition===i.greater_or_equal||t.condition===i.less_than||t.condition===i.less_or_equal?"number":t.condition===i.in||t.condition===i.not_in?this.getInArrayType(t.resource):t.condition===i.equals||t.condition===i.not_equals?this.getPrimitiveType(t.resource):"any"}getArrayType(t){return`readonly ${this.getInArrayType(t)}[]`}getInArrayType(t){if(Array.isArray(t)){if(0===t.length)return"unknown";const e=new Set(t.map(t=>this.getPrimitiveType(t)));return 1===e.size?Array.from(e)[0]:`(${Array.from(e).join(" | ")})`}return this.getPrimitiveType(t)}getPrimitiveType(t){if(null===t)return"null | unknown";if(void 0===t)return"undefined";if("string"==typeof t&&this.isPath(t))return"unknown";switch(typeof t){case"string":return"string";case"number":return"number";case"boolean":return"boolean";case"object":return Array.isArray(t)?"array":"object";default:return"any"}}buildNestedStructure(t){const e={};return Object.entries(t).forEach(([t,s])=>{e[t]={},Object.entries(s).forEach(([s,i])=>{const r=s.split(".");let n=e[t];for(let t=0;t<r.length-1;t++){const e=r[t],s=n[e];if(s&&"object"==typeof s)n=s;else{const t={};n[e]=t,n=t}}n[r[r.length-1]]=i})}),e}formatTypeDefinitions(t,e,s){let i="// Automatically generated by via-profit/ability\n";i+="// Do not edit manually\n",i+="export type Resources = {\n",Object.keys(t).sort().forEach(e=>{const s=t[e],r=0===Object.keys(s).length,n=m.normalizePermission(e).split("."),a=this.policyEntries.filter(t=>m.matchPermissions(t.segments,n)).map(t=>t.policy),o=[...new Set(a.map(t=>t.effect))].sort(),c=a.sort((t,e)=>t.id.localeCompare(e.id)).map(t=>{const e=t.effect.padEnd(6," "),s=t.name===t.id?"Unnamed policy":t.name;return` * - ${e} ${t.id} "${s}"`}).join("\n");i+=`\n /**\n * Permission: ${e}\n * Effects: ${o.join(", ")}\n * Policies:\n${c}\n */\n`,r?i+=` ['${e}']: undefined;\n`:(i+=` ['${e}']: {\n`,i+=this.formatNestedObject(s,4),i+=" } | null | undefined;\n")}),i+="}\n";const r=s.size>0?Array.from(s).sort().map(t=>`'${t}'`).join(" | "):"never";return i+=`\n\nexport type PolicyTags = ${r};\n`,i+="\n\nexport type Environment = {\n",Object.entries(e).forEach(([t,e])=>{const s=0===Object.keys(e).length,r=m.normalizePermission(t).split("."),n=this.policyEntries.filter(t=>m.matchPermissions(t.segments,r)).map(t=>t.policy),a=[...new Set(n.map(t=>t.effect))].sort(),o=n.sort((t,e)=>t.id.localeCompare(e.id)).map(t=>{const e=t.effect.padEnd(6," "),s=t.name===t.id?"Unnamed policy":t.name;return` * - ${e} ${t.id} "${s}"`}).join("\n");i+=`\n /**\n * Permission: ${t}\n * Effects: ${a.join(", ")}\n * Policies:\n${o}\n */\n`,s?i+=` ['${t}']: undefined;\n`:(i+=` ['${t}']: {\n`,i+=this.formatNestedObject(e,4),i+=" } | null | undefined;\n")}),i+="}\n",i}formatNestedObject(t,e){const s=" ".repeat(e);let i="";return Object.keys(t).sort().forEach(r=>{const n=t[r];if("object"==typeof n&&null!==n)i+=`${s}readonly ${r}: {\n`,i+=this.formatNestedObject(n,e+2),i+=`${s}} | null | undefined;\n`;else{const t=[String(n)];let e=String(n);e.match(/unknown/)||(e.match(/null/)||t.push("null"),e.match(/undefined/)||t.push("undefined")),i+=`${s}readonly ${r}?: ${[...new Set(t)].join(" | ")} \n`}}),i}},exports.AllMustPermitStrategy=class extends O{_decisive=null;evaluate(){if(!this.hasMatched())return this._decisive=null,d.deny;const t=this.firstDenied();return t?(this._decisive=t,d.deny):(this._decisive=this.firstPermitted(),d.permit)}decisivePolicy(){return this._decisive}},exports.AnyPermitStrategy=class extends O{_decisive=null;evaluate(){const t=this.firstPermitted();return t?(this._decisive=t,d.permit):(this._decisive=null,d.deny)}decisivePolicy(){return this._decisive}},exports.DenyOverridesStrategy=class extends O{_decisive=null;evaluate(){const t=this.firstDenied();if(t)return this._decisive=t,d.deny;const e=this.firstPermitted();return e?(this._decisive=e,d.permit):(this._decisive=null,d.deny)}decisivePolicy(){return this._decisive}},exports.FirstMatchStrategy=class extends O{_decisive=null;evaluate(){const t=this.firstMatched();return t?(this._decisive=t,t.effect):(this._decisive=null,d.deny)}decisivePolicy(){return this._decisive}},exports.OnlyOneApplicableStrategy=class extends O{_decisive=null;evaluate(){const t=this.matchedPolicies();return 1===t.length?(this._decisive=t[0],t[0].effect):(this._decisive=null,d.deny)}decisivePolicy(){return this._decisive}},exports.PermitOverridesStrategy=class extends O{_decisive=null;evaluate(){const t=this.matchedPolicies().find(t=>t.effect===d.permit);if(t)return this._decisive=t,d.permit;const e=this.matchedPolicies().find(t=>t.effect===d.deny);return e?(this._decisive=e,d.deny):(this._decisive=null,d.deny)}decisivePolicy(){return this._decisive}},exports.PriorityStrategy=class extends O{_decisive=null;evaluate(){const t=this.matchedPolicies();if(0===t.length)return this._decisive=null,d.deny;const e=[...t].sort((t,e)=>e.priority-t.priority)[0];return this._decisive=e,e.effect}decisivePolicy(){return this._decisive}},exports.SequentialLastMatchStrategy=class extends O{_decisive=null;evaluate(){const t=this.lastMatched();return t?(this._decisive=t,t.effect):(this._decisive=null,d.deny)}decisivePolicy(){return this._decisive}},exports.TokenTypes=_,exports.ability=function(t,...e){const s=t.reduce((t,s,i)=>t+s+(e[i]??""),"");return new k(s).parse()},exports.fromLiteral=function(t){const e={equals:i.equals,not_equals:i.not_equals,greater_than:i.greater_than,less_than:i.less_than,less_or_equal:i.less_or_equal,greater_or_equal:i.greater_or_equal,in:i.in,not_in:i.not_in,contains:i.contains,not_contains:i.not_contains,length_greater_than:i.length_greater_than,length_less_than:i.length_less_than,length_equals:i.length_equals,always:i.always,never:i.never,defined:i.defined,not_defined:i.not_defined},r=e[t];if(!r){const i=Object.keys(e).join(", ");throw new s(`Literal "${t}" does not found in AbilityCondition. Expected one of: ${i}`)}return r},exports.isConditionEqual=n,exports.isConditionNotEqual=function(t,e){return!n(t,e)},exports.toLiteral=r;
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const t={or:"or",and:"and"};class e extends Error{constructor(t,e){super(t,e),this.name="AbilityError",Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}}class s extends Error{constructor(t,e){super(t,e),this.name="AbilityParserError",Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}}const i={equals:"=",defined:"defined",not_defined:"not_defined",not_equals:"<>",greater_than:">",less_than:"<",less_or_equal:"<=",greater_or_equal:">=",in:"in",not_in:"not in",contains:"contains",not_contains:"not contains",length_greater_than:"length greater than",length_less_than:"length less than",length_equals:"length equals",always:"always",never:"never"};function r(t){const e={equals:i.equals,not_equals:i.not_equals,greater_than:i.greater_than,less_than:i.less_than,less_or_equal:i.less_or_equal,greater_or_equal:i.greater_or_equal,in:i.in,not_in:i.not_in,contains:i.contains,not_contains:i.not_contains,length_greater_than:i.length_greater_than,length_less_than:i.length_less_than,length_equals:i.length_equals,always:i.always,never:i.never,defined:i.defined,not_defined:i.not_defined},r=e[t];if(!r){const i=Object.keys(e).join(", ");throw new s(`Literal "${t}" does not found in AbilityCondition. Expected one of: ${i}`)}return r}function n(t){switch(t){case i.equals:return"equals";case i.not_equals:return"not_equals";case i.greater_than:return"greater_than";case i.less_than:return"less_than";case i.less_or_equal:return"less_or_equal";case i.greater_or_equal:return"greater_or_equal";case i.in:return"in";case i.not_in:return"not_in";case i.contains:return"contains";case i.not_contains:return"not_contains";case i.length_greater_than:return"length_greater_than";case i.length_less_than:return"length_less_than";case i.length_equals:return"length_equals";case i.always:return"always";case i.never:return"never";case i.defined:return"defined";case i.not_defined:return"not_defined";default:return"never"}}function a(t,e){return null!==t&&null!==e&&t===e}function o(t,e){return!a(t,e)}const c={pending:"pending",match:"match",mismatch:"mismatch",exceptMismatch:"except-mismatch",disabled:"disabled"};class h{type;children;_name;match;debugInfo;constructor(t,e=[]){this.type=t.type,this.children=e,this._name=t.name,this.match=t.match,this.debugInfo=t.debugInfo}get name(){const t=this._name.substring(0,60);return`${t}${t.length<this._name.length?"...":""}`}toString(t="",e=!0){const s=this.match===c.match,i=this.match===c.mismatch,r=this.match===c.pending,n=`[${s?"MATCH ✓":i?"MISMATCH ✗":r?"PENDING …":"DISABLED ⊘"}]`.padEnd(15," "),a=("policy"===this.type?"POLICY":"ruleSet"===this.type?"RULESET":"RULE").padEnd(10," ");let o=`${t}${0===t.length?"":e?"└─ ":"├─ "}${n}${a}${this.name}`;this.debugInfo&&(o+=` (${this.debugInfo})`);const h=t+(e?" ":"│ ");return this.children.forEach((t,e)=>{o+="\n"+t.toString(h,e===this.children.length-1)}),o}}class l extends h{constructor(t){super({type:"rule",match:t.state,name:t.name,debugInfo:`${t.subject} ${t.condition} ${JSON.stringify(t.resource)}`})}}class u extends h{constructor(t){const e=t.rules.map(t=>new l(t));super({type:"ruleSet",match:t.state,name:t.name},e)}}class d extends h{constructor(t){const e=t.ruleSet.map(t=>new u(t));super({type:"policy",name:t.priority>-1?`@priority ${t.priority} <${t.effect}> ${t.name}`:`<${t.effect}> ${t.name}`,match:t.matchState},e)}}class m{effect;strategy;constructor(t,e){this.effect=t,this.strategy=e}explain(){return`${this.strategy.isDenied()?"== DENIED==":"== ALLOWED =="}\n${this.strategy.policies.map(t=>new d(t).toString()).join("\n")}\n`}decisive(){return this.strategy.decisivePolicy()}explainDecisive(){const t=this.decisive();return t?new d(t).toString():null}isAllowed=()=>this.strategy.isAllowed();isDenied=()=>this.strategy.isDenied()}const p={deny:"deny",permit:"permit"};class f{onDeny;onAllow;StrategyClass;policyEntries;constructor(t,e,s={}){const i=this.toArray(t);this.onDeny=s.onDeny,this.onAllow=s.onAllow;const r=[...s.tags?i.filter(t=>t.tags.some(t=>s.tags.includes(t))):i].sort((t,e)=>e.priority-t.priority);this.policyEntries=r.map(t=>({policy:t,normalizedPermission:f.normalizePermission(t.permission),segments:f.normalizePermission(t.permission).split(".")})),this.StrategyClass=e}resolve(t,s,i){const r=f.normalizePermission(String(t)).split("."),n=this.policyEntries.filter(t=>f.matchPermissions(t.segments,r)).map(t=>t.policy);for(const t of n)if(!t.disabled&&t.check(s,i)===c.pending)throw new e(`The policy "${t.name}" is still in a pending state. Make sure to call "check" to evaluate the policy before resolving permissions.`);const a=new this.StrategyClass(n),o=a.evaluate(),h=new m(o,a);return o===p.deny&&this.onDeny&&this.onDeny(h),o===p.permit&&this.onAllow&&this.onAllow(h),h}enforce(t,s,i,r){const n=this.resolve(t,s,i);if(n.isDenied())throw r?.onDeny&&r?.onDeny(n),new e("Permission denied")}static isInPermissionContain(t,e){const s=t.split("."),i=e.split("."),[r,n]=s.length>=i.length?[s,i]:[i,s];return n.every((t,e)=>"*"===t||"*"===r[e]||t===r[e])}toArray(t){return[...Array.isArray(t)?t:[t]]}static normalizePermission(t){return t.trim().replace(/^permission\./,"").replace(/\.+/g,".").toLowerCase()}static matchPermissions(t,e){let s=0;for(;s<t.length;s++){const i=t[s],r=e[s];if("*"===i)return!0;if(void 0===r)return!1;if(i!==r)return!1}return s===e.length}}class y{policies;policyEntries;constructor(t){this.policies=t,this.policyEntries=t.map(t=>({policy:t,normalizedPermission:f.normalizePermission(t.permission),segments:f.normalizePermission(t.permission).split(".")}))}generateTypeDefs(){const t={},e={},s=new Set;this.policies.forEach(i=>{i.tags.forEach(t=>s.add(t));const r=i.permission;t[r]||(t[r]={}),i.ruleSet.forEach(s=>{s.rules.forEach(s=>{const i=s.subject,n=this.determineTypeFromRule(s);if(n){if(i.startsWith("env.")){const t=i.replace(/^env\./,"");e[r]||(e[r]={}),e[r][t]=n}else{const e=t[r][i];t[r][i]=e&&e!==n?`${e} | ${n}`:n}if("string"==typeof s.resource&&this.isPath(s.resource)){const i=s.resource;if(i.startsWith("env.")){const t=i.replace(/^env\./,"");e[r]||(e[r]={});const s=e[r][t],a=n;e[r][t]=s&&s!==a?`${s} | ${a}`:a}else{t[r]||(t[r]={});const e=t[r][i],s=n;t[r][i]=e&&e!==s?`${e} | ${s}`:s}}}})})});const i={};Object.entries(t).forEach(([t,e])=>{t.endsWith(".*")||(i[t]=e)});const r=this.buildNestedStructure(i),n=this.buildNestedStructure(e);return this.formatTypeDefinitions(r,n,s)}isPath(t){return"string"==typeof t&&!t.startsWith('"')&&!t.startsWith("'")&&t.includes(".")}determineTypeFromRule(t){return t.condition===i.never||t.condition===i.always?null:t.condition===i.contains||t.condition===i.not_contains?this.getArrayType(t.resource):t.condition===i.length_equals||t.condition===i.length_greater_than||t.condition===i.length_less_than?"string | readonly unknown[]":t.condition===i.greater_than||t.condition===i.greater_or_equal||t.condition===i.less_than||t.condition===i.less_or_equal?"number":t.condition===i.in||t.condition===i.not_in?this.getInArrayType(t.resource):t.condition===i.equals||t.condition===i.not_equals?this.getPrimitiveType(t.resource):"any"}getArrayType(t){return`readonly ${this.getInArrayType(t)}[]`}getInArrayType(t){if(Array.isArray(t)){if(0===t.length)return"unknown";const e=new Set(t.map(t=>this.getPrimitiveType(t)));return 1===e.size?Array.from(e)[0]:`(${Array.from(e).join(" | ")})`}return this.getPrimitiveType(t)}getPrimitiveType(t){if(null===t)return"null | unknown";if(void 0===t)return"undefined";if("string"==typeof t&&this.isPath(t))return"unknown";switch(typeof t){case"string":return"string";case"number":return"number";case"boolean":return"boolean";case"object":return Array.isArray(t)?"array":"object";default:return"any"}}buildNestedStructure(t){const e={};return Object.entries(t).forEach(([t,s])=>{e[t]={},Object.entries(s).forEach(([s,i])=>{const r=s.split(".");let n=e[t];for(let t=0;t<r.length-1;t++){const e=r[t],s=n[e];if(s&&"object"==typeof s)n=s;else{const t={};n[e]=t,n=t}}n[r[r.length-1]]=i})}),e}formatTypeDefinitions(t,e,s){let i="// Automatically generated by via-profit/ability\n";i+="// Do not edit manually\n",i+="export type Resources = {\n",Object.keys(t).sort().forEach(e=>{const s=t[e],r=0===Object.keys(s).length,n=f.normalizePermission(e).split("."),a=this.policyEntries.filter(t=>f.matchPermissions(t.segments,n)).map(t=>t.policy),o=[...new Set(a.map(t=>t.effect))].sort(),c=a.sort((t,e)=>t.id.localeCompare(e.id)).map(t=>{const e=t.effect.padEnd(6," "),s=t.name===t.id?"Unnamed policy":t.name;return` * - ${e} ${t.id} "${s}"`}).join("\n");i+=`\n /**\n * Permission: ${e}\n * Effects: ${o.join(", ")}\n * Policies:\n${c}\n */\n`,r?i+=` ['${e}']: undefined;\n`:(i+=` ['${e}']: {\n`,i+=this.formatNestedObject(s,4),i+=" } | null | undefined;\n")}),i+="}\n";const r=s.size>0?Array.from(s).sort().map(t=>`'${t}'`).join(" | "):"never";return i+=`\n\nexport type PolicyTags = ${r};\n`,i+="\n\nexport type Environment = {\n",Object.entries(e).forEach(([t,e])=>{const s=0===Object.keys(e).length,r=f.normalizePermission(t).split("."),n=this.policyEntries.filter(t=>f.matchPermissions(t.segments,r)).map(t=>t.policy),a=[...new Set(n.map(t=>t.effect))].sort(),o=n.sort((t,e)=>t.id.localeCompare(e.id)).map(t=>{const e=t.effect.padEnd(6," "),s=t.name===t.id?"Unnamed policy":t.name;return` * - ${e} ${t.id} "${s}"`}).join("\n");i+=`\n /**\n * Permission: ${t}\n * Effects: ${a.join(", ")}\n * Policies:\n${o}\n */\n`,s?i+=` ['${t}']: undefined;\n`:(i+=` ['${t}']: {\n`,i+=this.formatNestedObject(e,4),i+=" } | null | undefined;\n")}),i+="}\n",i}formatNestedObject(t,e){const s=" ".repeat(e);let i="";return Object.keys(t).sort().forEach(r=>{const n=t[r];if("object"==typeof n&&null!==n)i+=`${s}readonly ${r}: {\n`,i+=this.formatNestedObject(n,e+2),i+=`${s}} | null | undefined;\n`;else{const t=[String(n)];let e=String(n);e.match(/unknown/)||(e.match(/null/)||t.push("null"),e.match(/undefined/)||t.push("undefined")),i+=`${s}readonly ${r}: ${t.join(" | ")} \n`}}),i}}class g{static sha1(t){const e=g.stringToBytes(t),s=8*e.length,i=new Uint8Array(e.length+1);i.set(e,0),i[e.length]=128;let r=(56-i.length%64+64)%64;const n=new Uint8Array(i.length+r+8);n.set(i,0);const a=Math.floor(s/4294967296),o=s>>>0;n[n.length-8]=a>>>24&255,n[n.length-7]=a>>>16&255,n[n.length-6]=a>>>8&255,n[n.length-5]=255&a,n[n.length-4]=o>>>24&255,n[n.length-3]=o>>>16&255,n[n.length-2]=o>>>8&255,n[n.length-1]=255&o;let c=1732584193,h=4023233417,l=2562383102,u=271733878,d=3285377520;const m=new Array(80);for(let t=0;t<n.length;t+=64){for(let e=0;e<16;e++){const s=t+4*e;m[e]=n[s]<<24|n[s+1]<<16|n[s+2]<<8|n[s+3]}for(let t=16;t<80;t++)m[t]=g.leftRotate(m[t-3]^m[t-8]^m[t-14]^m[t-16],1);let e=c,s=h,i=l,r=u,a=d;for(let t=0;t<80;t++){let n,o;t<20?(n=s&i|~s&r,o=1518500249):t<40?(n=s^i^r,o=1859775393):t<60?(n=s&i|s&r|i&r,o=2400959708):(n=s^i^r,o=3395469782);const c=g.leftRotate(e,5)+n+a+o+(0|m[t])|0;a=r,r=i,i=g.leftRotate(s,30),s=e,e=c}c=c+e|0,h=h+s|0,l=l+i|0,u=u+r|0,d=d+a|0}return[g.toHex32(c),g.toHex32(h),g.toHex32(l),g.toHex32(u),g.toHex32(d)].join("")}static leftRotate(t,e){return(t<<e|t>>>32-e)>>>0}static toHex32(t){return(t>>>0).toString(16).padStart(8,"0")}static stringToBytes(t){if("undefined"!=typeof TextEncoder)return(new TextEncoder).encode(t);{const e=Buffer.from(t,"utf8");return new Uint8Array(e.buffer,e.byteOffset,e.byteLength)}}}class E{matchState=c.pending;ruleSet=[];effect;compareMethod=t.and;id;name;description;permission;priority=-1;disabled;tags;constructor(e){const{name:s,description:i,id:r,permission:n,effect:a,compareMethod:o=t.and,priority:c,disabled:h,tags:l}=e;this.permission=n,this.description=i,this.effect=a,this.compareMethod=o,this.priority="number"==typeof c?c:-1,this.disabled="boolean"==typeof h&&h,this.tags=l||[],this.id=r||`p_${this.hash().slice(0,10)}`,this.name=s||this.id}addRuleSet(t){return this.ruleSet.push(t),this}addRuleSets(t){for(const e of t)this.ruleSet.push(e);return this}extractRules(){const t=[];for(const e of this.ruleSet)for(const s of e.rules)t.push(s);return t}check(e,s){if(this.matchState=c.mismatch,this.disabled)return this.matchState=c.disabled,this.matchState;if(!this.ruleSet.length)return this.matchState;const i=this.ruleSet.filter(t=>!t.isExcept),r=this.ruleSet.filter(t=>t.isExcept),n=[];for(const r of i){if(r.disabled)continue;const i=r.check(e,s);if(n.push(i),t.and===this.compareMethod&&c.mismatch===i)return this.matchState=c.mismatch,this.matchState;if(t.or===this.compareMethod&&c.match===i){this.matchState=c.match;break}}let a=!1;if(a=t.and===this.compareMethod?n.every(t=>c.match===t):n.some(t=>c.match===t),!a)return this.matchState=c.mismatch,this.matchState;for(const t of r){if(t.disabled)continue;const i=t.check(e,s);if(c.match===i)return this.matchState=c.exceptMismatch,this.matchState}return this.matchState=c.match,this.matchState}explain(){if(this.matchState===c.pending)throw new e("First, run the check method, then explain");return new d(this)}copyWith(t){const e=new E({id:t.id??this.id,name:t.name??this.name,description:t.description??this.description,priority:void 0!==t.priority?t.priority:this.priority,permission:t.permission??this.permission,effect:t.effect??this.effect,compareMethod:t.compareMethod??this.compareMethod}),s=t.ruleSet??this.ruleSet;for(const t of s)e.addRuleSet(t);return e}hash(){const t=[`permission:${this.permission}`,`effect:${this.effect}`,`compareMethod:${this.compareMethod}`,`priority:${this.priority}`,`disabled:${this.disabled}`];if(this.tags&&this.tags.length>0&&t.push(`tags:${[...this.tags].sort().join(",")}`),this.ruleSet&&this.ruleSet.length>0){const e=this.ruleSet.map(t=>t.hash());t.push(`rules:${e.sort().join("|")}`)}const e=t.join(";");return g.sha1(e)}}class _{subject;resource;condition;name;description;id;state=c.pending;disabled;constructor(t){const{id:e,name:s,subject:i,resource:r,condition:n,disabled:a,description:o}=t;this.description=o,this.disabled="boolean"==typeof a&&a,this.subject=i,this.resource=r,this.condition=n,this.state=this.disabled?c.disabled:this.state,this.id=e||`r_${this.hash().slice(0,10)}`,this.name=s||this.id}static isPrimitive(t){return"string"==typeof t||"number"==typeof t||"boolean"==typeof t||null===t}static isNumber(t){return"number"==typeof t}static isString(t){return"string"==typeof t}static valueLen=t=>this.isString(t)||Array.isArray(t)?t.length:null;static operatorHandlers={[n(i.always)]:()=>!0,[n(i.defined)]:t=>void 0!==t,[n(i.not_defined)]:t=>void 0===t,[n(i.never)]:()=>!1,[n(i.equals)]:(t,e)=>t===e,[n(i.not_equals)]:(t,e)=>t!==e,[n(i.contains)]:(t,e)=>Array.isArray(t)&&_.isPrimitive(e)?t.includes(e):!(!Array.isArray(t)||!Array.isArray(e))&&t.some(t=>e.includes(t)),[n(i.not_contains)]:(t,e)=>Array.isArray(t)&&_.isPrimitive(e)?!t.includes(e):!(!Array.isArray(t)||!Array.isArray(e)||t.some(t=>e.includes(t))),[n(i.in)]:(t,e)=>_.isPrimitive(t)&&Array.isArray(e)?e.includes(t):!(!Array.isArray(t)||!Array.isArray(e))&&t.some(t=>e.includes(t)),[n(i.not_in)]:(t,e)=>_.isPrimitive(t)&&Array.isArray(e)?!e.includes(t):!(!Array.isArray(t)||!Array.isArray(e)||t.some(t=>e.includes(t))),[n(i.greater_than)]:(t,e)=>!(!_.isNumber(t)||!_.isNumber(e))&&t>e,[n(i.less_than)]:(t,e)=>!(!_.isNumber(t)||!_.isNumber(e))&&t<e,[n(i.greater_or_equal)]:(t,e)=>!(!_.isNumber(t)||!_.isNumber(e))&&t>=e,[n(i.less_or_equal)]:(t,e)=>!(!_.isNumber(t)||!_.isNumber(e))&&t<=e,[n(i.length_greater_than)]:(t,e)=>{const s=_.valueLen(t);if(null===s)return!1;if(_.isNumber(e))return s>e;const i=_.valueLen(e);return null!==i&&s>i},[n(i.length_less_than)]:(t,e)=>{const s=_.valueLen(t);if(null===s)return!1;if(_.isNumber(e))return s<e;const i=_.valueLen(e);return null!==i&&s<i},[n(i.length_equals)]:(t,e)=>{const s=_.valueLen(t);if(null===s)return!1;if(_.isNumber(e))return s===e;const i=_.valueLen(e);return null!==i&&s===i}};check(t,e){if(this.disabled)return this.state=c.disabled,this.state;const[s,i]=this.extractValues(t,e),r=(0,_.operatorHandlers[n(this.condition)])(s,i);return this.state=r?c.match:c.mismatch,this.state}extractValues(t,e){let s,i;return null==t&&null==e?[NaN,NaN]:(s=this.subject.includes(".")?this.subject.startsWith("env.")&&void 0!==e?this.getDotNotationValue(e,this.subject.replace(/^env\./,"")):this.getDotNotationValue(t,this.subject):this.subject,i="string"==typeof this.resource&&this.resource.includes(".")?this.resource.startsWith("env.")&&void 0!==e?this.getDotNotationValue(e,this.resource.replace(/^env\./,"")):this.getDotNotationValue(t,this.resource):this.resource,[s,i])}static _pathCache=new Map;static _parsePath(t){const e=_._pathCache.get(t);if(e)return e;const s=t.split("."),i=[];for(const t of s){const e=t.indexOf("[");if(-1!==e){const s=t.slice(0,e),r=t.slice(e+1,-1),n=Number(r);i.push({prop:s,index:n})}else i.push(t)}return _._pathCache.set(t,i),i}getDotNotationValue(t,e){if(null==t)return;const s=_._parsePath(e);let i=t;for(const t of s){if(null==i)return;if("string"==typeof t)i=i[t];else{const e=i[t.prop];i=Array.isArray(e)?e[t.index]:void 0}}return i}toString(){return`AbilityRule: ${this.name} condition: ${n(this.condition)} subject: "${this.subject?.toString()}" resource: "${this.resource?.toString()}"`}copyWith(t){return new _({id:t.id??this.id,name:t.name??this.name,description:t.description??this.description,subject:t.subject??this.subject,resource:t.resource??this.resource,condition:t.condition??this.condition})}hash(){const t=[];return t.push(`subject:${this.subject}`),t.push(`resource:${JSON.stringify(this.resource)}`),t.push(`condition:${this.condition}`),t.push(`disabled:${this.disabled}`),g.sha1(t.join(";"))}static equals(t,e){return new _({condition:i.equals,subject:t,resource:e})}static notEquals(t,e){return new _({condition:i.not_equals,subject:t,resource:e})}static contains(t,e){return new _({condition:i.contains,subject:t,resource:e})}static notContains(t,e){return new _({condition:i.not_contains,subject:t,resource:e})}static notIn(t,e){return new _({condition:i.not_in,subject:t,resource:e})}static in(t,e){return new _({condition:i.in,subject:t,resource:e})}static notEqual(t,e){return new _({condition:i.not_equals,subject:t,resource:e})}static lessThan(t,e){return new _({condition:i.less_than,subject:t,resource:e})}static lessOrEqual(t,e){return new _({condition:i.less_or_equal,subject:t,resource:e})}static moreThan(t,e){return new _({condition:i.greater_than,subject:t,resource:e})}static moreOrEqual(t,e){return new _({condition:i.greater_or_equal,subject:t,resource:e})}}class v{state=c.pending;rules=[];compareMethod=t.and;name;description;id;isExcept=!1;disabled;constructor(t){const{name:e,id:s,compareMethod:i,isExcept:r,disabled:n,description:a}=t;this.description=a,this.compareMethod=i,this.isExcept=r,this.disabled="boolean"==typeof n&&n,this.state=this.disabled?c.disabled:this.state,this.id=s||`g_${this.hash().slice(0,10)}`,this.name=e||this.id}addRule(t){return this.rules.push(t),this}addRules(t){return t.forEach(t=>this.addRule(t)),this}check(e,s){if(this.state=c.mismatch,this.disabled)return this.state=c.disabled,this.state;if(!this.rules.length)return this.state;const i=[];for(const r of this.rules){if(r.disabled)continue;const n=r.check(e,s);if(i.push(n),t.and===this.compareMethod&&c.mismatch===n)return this.state;if(t.or===this.compareMethod&&c.match===n)return this.state=c.match,this.state}return t.and===this.compareMethod&&i.every(t=>c.match===t)&&(this.state=c.match),t.or===this.compareMethod&&i.some(t=>c.match===t)&&(this.state=c.match),this.state}toString(){return`AbilityRuleSet: ${this.name} compareMethod: ${this.compareMethod}, rules: ${this.rules.map(t=>t.toString()).join("\n")}`}copyWith(t){const e=new v({id:t.id??this.id,name:t.name??this.name,description:t.description??this.description,compareMethod:t.compareMethod??this.compareMethod}),s=t.rules??this.rules;for(const t of s)e.addRule(t);return e}hash(){const t=this.rules.map(t=>t.hash()).sort(),e=[`compareMethod:${this.compareMethod}`,`isExcept:${this.isExcept}`,`disabled:${this.disabled}`,`rules:${t.join("|")}`];return g.sha1(e.join(";"))}static and(e){return new v({compareMethod:t.and}).addRules(e)}static or(e){return new v({compareMethod:t.or}).addRules(e)}}class N{static parse(t){return t.map(t=>N.parsePolicy(t))}static parsePolicy(t){const{id:e,name:s,ruleSet:i,compareMethod:r,permission:n,effect:a,priority:o,disabled:c,tags:h}=t,l=new E({name:s,id:e,permission:n,priority:o,effect:a,disabled:c,tags:h});return l.compareMethod=r,i.forEach(t=>{l.addRuleSet(N.parseRuleSet(t))}),l}static parseRule(t){const{id:e,name:s,subject:i,resource:r,condition:n,disabled:a}=t;return new _({id:e,name:s,subject:i,resource:r,disabled:a,condition:n})}static parseRuleSet(t){const{id:e,name:s,rules:i,compareMethod:r,disabled:n}=t,a=new v({disabled:n,compareMethod:r,name:s,id:e});if(i&&i.length>0){const t=i.map(t=>N.parseRule(t));a.addRules(t)}return a}static ruleToJSON(t){return{id:t.id,name:t.name,disabled:t.disabled,subject:t.subject,resource:t.resource,condition:t.condition}}static ruleSetToJSON(t){return{id:t.id.toString(),name:t.name.toString(),disabled:t.disabled,compareMethod:t.compareMethod,rules:t.rules.map(t=>N.ruleToJSON(t))}}static policyToJSON(t){return{id:t.id.toString(),name:t.name.toString(),disabled:t.disabled,priority:t.priority,permission:t.permission,effect:t.effect,compareMethod:t.compareMethod,tags:t.tags,ruleSet:t.ruleSet.map(t=>N.ruleSetToJSON(t))}}static toJSON(t){return t.map(t=>N.policyToJSON(t))}}const A={EFFECT:"EFFECT",IF:"IF",PERMISSION:"PERMISSION",IDENTIFIER:"IDENTIFIER",COLON:"COLON",COMMA:"COMMA",DOT:"DOT",LBRACKET:"LBRACKET",RBRACKET:"RBRACKET",ALL:"ALL",ANY:"ANY",OF:"OF",EOF:"EOF",COMMENT:"COMMENT",EQ:"EQ",CONTAINS:"CONTAINS",IN:"IN",NOT_IN:"NOT_IN",NOT_CONTAINS:"NOT_CONTAINS",GT:"GT",GTE:"GTE",LT:"LT",LTE:"LTE",NULL:"NULL",EQ_NULL:"EQ_NULL",NOT_EQ_NULL:"NOT_EQ_NULL",DEFINED:"DEFINED",NOT_EQ:"NOT_EQ",LEN_GT:"LEN_GT",LEN_LT:"LEN_LT",LEN_EQ:"LEN_EQ",ALWAYS:"ALWAYS",NEVER:"NEVER",EXCEPT:"EXCEPT",ANNOTATION:"ANNOTATION",STRING:"STRING",NUMBER:"NUMBER",BOOLEAN:"BOOLEAN",SYMBOL:"SYMBOL",KEYWORD:"KEYWORD",ALIAS:"ALIAS",UNKNOWN:"UNKNOWN"};class S{type;value;line;column;constructor(t,e,s,i){this.type=t,this.value=e,this.line=s,this.column=i}toString(){return`AbilityDSLToken([${this.type}] "${this.value}" at ${this.line}:${this.column})`}}class b{input;pos=0;tokens=[];line=1;column=1;keywords=new Set(["if","all","any","of","permit","allow","deny","forbidden","true","false","null","defined","contains","includes","length","len","has","in","gt","lt","gte","lte","equals","greater","less","not","is","or","than","always","never","except","alias"]);constructor(t){this.input=t}tokenize(){for(;!this.isAtEnd()&&(this.skipWhitespace(),!this.isAtEnd());){const t=this.peek();if("@"!==t)if("#"!==t)if('"'!==t&&"'"!==t)if(this.isDigit(t))this.tokens.push(this.readNumber());else if(this.isSymbol(t))this.tokens.push(this.readSymbol());else{if(!this.isAlpha(t))throw new Error(`Unexpected character '${t}' at ${this.line}:${this.column}`);this.tokens.push(this.readWord())}else this.tokens.push(this.readString());else this.tokens.push(this.readComment());else this.tokens.push(this.readAnnotation())}return this.tokens.push(new S(A.EOF,"",this.line,this.column)),this.tokens}readComment(){const t=this.line,e=this.column;this.advance();let s="";for(;!this.isAtEnd()&&!this.isNewline();)s+=this.advance();return new S(A.COMMENT,s.trim(),t,e)}readAnnotation(){const t=this.line,e=this.column;let s="";for(;!this.isAtEnd()&&!this.isNewline();)s+=this.advance();s=s.trim();let i="",r=0,n=!1,a=null,o=!1;for(;r<s.length;){const t=s[r];n?(o?(i+=t,o=!1):"\\"===t?o=!0:t===a?(n=!1,a=null):i+=t,r++):'"'!==t&&"'"!==t?(i+=t,r++):(n=!0,a=t,r++)}return new S(A.ANNOTATION,i.trim(),t,e)}readString(){const t=this.line,e=this.column,s=this.advance();let i="",r=!1;for(;!this.isAtEnd();){const n=this.advance();if(r)i+=n,r=!1;else if("\\"!==n){if(n===s)return new S(A.STRING,i,t,e);i+=n}else r=!0}throw new Error(`Unterminated string at ${t}:${e}`)}readNumber(){const t=this.line,e=this.column,s=this.pos;for(;!this.isAtEnd()&&this.isDigit(this.peek());)this.advance();const i=this.input.slice(s,this.pos);return new S(A.NUMBER,i,t,e)}readSymbol(){const t=this.line,e=this.column,s=this.advance();switch(s){case".":return new S(A.DOT,s,t,e);case":":return new S(A.COLON,s,t,e);case",":return new S(A.COMMA,s,t,e);case"[":return new S(A.LBRACKET,s,t,e);case"]":return new S(A.RBRACKET,s,t,e);case">":return"="===this.peek()?(this.advance(),new S(A.SYMBOL,">=",t,e)):new S(A.SYMBOL,">",t,e);case"<":return"="===this.peek()?(this.advance(),new S(A.SYMBOL,"<=",t,e)):">"===this.peek()?(this.advance(),new S(A.SYMBOL,"<>",t,e)):new S(A.SYMBOL,"<",t,e);case"=":return"="===this.peek()?(this.advance(),new S(A.SYMBOL,"==",t,e)):new S(A.SYMBOL,"=",t,e);case"!":if("="===this.peek())return this.advance(),new S(A.SYMBOL,"!=",t,e);throw new Error(`Unexpected symbol '!' at ${this.line}:${this.column}`);default:throw new Error(`Unknown symbol '${s}' at ${this.line}:${this.column}`)}}readWord(){const t=this.line,e=this.column,s=this.pos;for(;!this.isAtEnd()&&/[a-zA-Z0-9_*]/.test(this.peek());)this.advance();for(;!this.isAtEnd()&&"."===this.peek()&&(this.advance(),/[a-zA-Z_*]/.test(this.peek()));)for(;!this.isAtEnd()&&/[a-zA-Z0-9_*]/.test(this.peek());)this.advance();const i=this.input.slice(s,this.pos);if("always"===i)return new S(A.ALWAYS,i,t,e);if("never"===i)return new S(A.NEVER,i,t,e);if(i.includes(".")){const s=this.tokens[this.tokens.length-1];return s?.type===A.EFFECT&&i.startsWith("permission.")?new S(A.PERMISSION,i,t,e):new S(A.IDENTIFIER,i,t,e)}if(this.keywords.has(i))return"permit"===i||"allow"===i?new S(A.EFFECT,"permit",t,e):"deny"===i||"forbidden"===i?new S(A.EFFECT,"deny",t,e):new S("all"===i?A.ALL:"any"===i?A.ANY:"of"===i?A.OF:"if"===i?A.IF:"true"===i||"false"===i?A.BOOLEAN:"null"===i?A.NULL:"defined"===i?A.DEFINED:"except"===i?A.EXCEPT:"alias"===i?A.ALIAS:A.KEYWORD,i,t,e);const r=this.tokens[this.tokens.length-1];return new S(r?.type===A.EFFECT?A.PERMISSION:A.IDENTIFIER,i,t,e)}skipWhitespace(){for(;!this.isAtEnd()&&/\s/.test(this.peek());)this.advance()}isDigit(t){return t>="0"&&t<="9"}isAlpha(t){return/[a-zA-Z_]/.test(t)}isSymbol(t){return[".",":",",","[","]",">","<","=","!"].includes(t)}isNewline(){return"\n"===this.peek()}peek(){return this.input[this.pos]}advance(){const t=this.input[this.pos++];return"\n"===t?(this.line++,this.column=1):this.column++,t}isAtEnd(){return this.pos>=this.input.length}}class k extends Error{line;column;context;details;_formattedMessage;_originalStack;constructor(t,e,s,i){super(i.split("\n")[0]),this.line=t,this.column=e,this.context=s,this.details=i,this.name="AbilityDSLSyntaxError",Error.captureStackTrace&&Error.captureStackTrace(this,k),this._originalStack=this.stack,this._formattedMessage=this.formatMessage(),Object.defineProperty(this,"stack",{get:()=>this._formattedMessage,configurable:!0})}static supportsColor(){return"undefined"!=typeof process&&process.stdout?.isTTY}formatMessage(){const t=k.supportsColor(),e=t?"[1m":"",s=t?"[31m":"",i=t?"[33;1m":"",r=t?"[90m":"",n=t?"[0m":"",a=this.context.split("\n"),o=a.findIndex(t=>t.includes("^")||t.includes("~")),c=a.findIndex(t=>t.trim().includes("#")),h=a.map((t,a)=>a===o-1?`${e}${i}${t}${n}`:a===o?`${s}${t}${n}`:a===c?`${r}${t}${n}`:t).join("\n");return`${e}${s}${this.name}: ${this.details}${n}\n\n`+h}toString(){return this._formattedMessage}}class L{tokens;pos=0;dsl;marks=[];lastToken=null;next(){const t=this.tokens[this.pos++];return this.lastToken=t,t}prev(){if(0===this.pos)return null;const t=this.tokens[this.pos--];return this.lastToken=t,t}lookPrev(){return this.lastToken}constructor(t,e){this.tokens=t,this.dsl=e}peek(){return this.tokens[this.pos]}eof(){return this.peek().type===A.EOF}check(t){return!this.eof()&&this.peek().type===t}match(t){return this.check(t)?this.next():null}expect(t,e){const s=this.peek();if(s&&s.type===t)return this.next();this.syntaxError(e,s,[t])}expectOneOf(t,e){const s=this.peek();for(const e of t)if(s&&s.type===e)return this.next();this.syntaxError(e,s,t)}mark(){this.marks.push(this.pos)}reset(){const t=this.marks.pop();void 0!==t&&(this.pos=t)}commit(){this.marks.pop()}syntaxError(t,e,s){const i=this.dsl.split(/\r?\n/),r=e.line-1,n=r>0?i[r-1]:"",a=i[r],o=r+1<i.length?i[r+1]:"",c=" ".repeat(Math.max(0,e.column-1))+"~".repeat(e.value.length),h=String(e.line+1).length,l=t=>String(t).padStart(h," ");let u="";""!==n.trim()&&(u+=`${l(e.line-1)} | ${n}\n`),u+=`${l(e.line)} | ${a}\n`,u+=`${" ".repeat(h)} | ${c}\n`,""!==o.trim()&&(u+=`${l(e.line+1)} | ${o}`);let d=t;if(s&&s?.length>0){const i=e.value,r=this.suggest(i,s),n=`${t}\nDetails: Unexpected value token \`${i}\``;d=r?`${n} Did you mean \`${r}\`?`:n}throw new k(e.line,e.column,u+"\n",d)}suggest(t,e){const s=[];for(const t of e)s.push(t);const i=[...new Set(s)];let r=null,n=3;for(const e of i){const s=this.levenshteinDistance(t.toLowerCase(),e.toLowerCase());s<n&&(n=s,r=e)}return r}levenshteinDistance(t,e){const s=Array.from({length:e.length+1},()=>Array.from({length:t.length+1},()=>0));for(let e=0;e<=t.length;e++)s[0][e]=e;for(let t=0;t<=e.length;t++)s[t][0]=t;for(let i=1;i<=e.length;i++)for(let r=1;r<=t.length;r++){const n=t[r-1]===e[i-1]?0:1;s[i][r]=Math.min(s[i][r-1]+1,s[i-1][r]+1,s[i-1][r-1]+n)}return s[e.length][t.length]}}class O{store={id:void 0,name:void 0,priority:void 0,description:void 0,disabled:void 0,tags:void 0};get(t){return this.store[t]??null}set(t,e,s){return this.store[t]=null===e?void 0:{key:t,value:e,token:s},this}clear(){for(const t of Object.keys(this.store))this.store[t]=void 0}clone(){const t=new O;for(const e of Object.keys(this.store)){const s=this.store[e];t.store[e]=s?{...s}:void 0}return t}get id(){return this.get("id")}get name(){return this.get("name")}get description(){return this.get("description")}get priority(){return this.get("priority")}get disabled(){return this.get("disabled")}get tags(){return this.get("tags")}setID(t,e){return this.set("id",t,e)}setName(t,e){return this.set("name",t,e)}setDescription(t,e){return this.set("description",t,e)}setPriority(t,e){return this.set("priority",t,e)}setDisabled(t,e){return this.set("disabled",t,e)}setTags(t,e){return this.set("tags",t,e)}}const T={policy:new Set(["id","name","description","priority","disabled","tags"]),ruleSet:new Set(["id","name","description","disabled"]),rule:new Set(["id","name","disabled"]),alias:new Set(["name","disabled"])};class x{store=new Map;get(t){return this.store.get(t)||null}set(t,e){return this.store.set(t,e),this}has(t){return this.store.has(t)}}class w{dsl;stream;annBuffer=new O;aliasBuffer=new x;constructor(t){this.dsl=t}parse(){this.annBuffer.clear();const t=new b(this.dsl).tokenize();this.stream=new L(t,this.dsl);const e=[];for(;!this.stream.eof();){if(this.consumeLeadingComments(),this.consumeLeadingAnnotations(),this.consumeLeadingAliases(),!this.isStartOfPolicy()){const t=this.stream.peek();this.stream.syntaxError(`Expected policy, got ${t.type}.`,t,[A.EFFECT])}e.push(this.parsePolicy())}return e}parsePolicy(){this.consumeLeadingComments(),this.consumeLeadingAnnotations(),this.consumeLeadingAliases();const e=this.takeAnnotations("policy"),s=this.stream.expect(A.EFFECT,"Expected effect").value,i=this.stream.expect(A.PERMISSION,"Expected permission"),r=i.value;if(!r.startsWith("permission."))return this.stream.syntaxError(`Unexpected token. The permission key, must be starts with prefix \`permission.\`, but got \`${r}\`.\nDid you mean \`permission.${r}\`?`,i);this.stream.expect(A.IF,'Expected "if"');const n=this.stream.expectOneOf([A.ALL,A.ANY],'Expected "all" or "any"').type===A.ALL?t.and:t.or;this.stream.expect(A.COLON,'Expected ":"');const a=this.parseRuleSets(n);return new E({id:e.id?.value||null,name:e.name?.value||null,description:e.description?.value||null,priority:e.priority?.value||null,permission:r.replace(/^permission\./,""),effect:"permit"===s?p.permit:p.deny,disabled:e.disabled?.value??void 0,tags:e.tags?.value??void 0,compareMethod:n}).addRuleSets(a)}parseRuleSets(t){const e=[];for(this.consumeLeadingComments(),this.consumeLeadingAnnotations();!this.stream.eof()&&!this.isStartOfPolicy();){if(this.isStartOfExcept()){e.push(this.parseExceptGroup(t));continue}if(this.isStartOfGroup()){e.push(this.parseGroup());continue}const s=new v({compareMethod:t});for(;!(this.stream.eof()||(this.consumeLeadingComments(),this.consumeLeadingAnnotations(),this.isStartOfGroup()||this.isStartOfPolicy()||this.isStartOfExcept()));)this.stream.check(A.IDENTIFIER)||this.stream.check(A.ALWAYS)||this.stream.check(A.NEVER)?s.addRule(this.parseRule()):this.stream.syntaxError(`Unexpected token in implicit group: ${this.stream.peek().type}`,this.stream.peek());e.push(s)}return e}parseGroup(){this.consumeLeadingComments(),this.consumeLeadingAnnotations();const e=this.takeAnnotations("ruleSet"),s=this.stream.expectOneOf([A.ALL,A.ANY,A.ALWAYS,A.NEVER],'Expected "all" or "any" or "always" or "never"').type===A.ALL?t.and:t.or;this.stream.check(A.OF)&&this.stream.next(),this.stream.expect(A.COLON,'Expected ":"');const i=new v({id:e.id?.value||null,compareMethod:s,name:e.name?.value||null,description:e.description?.value||null,disabled:e.disabled?.value??void 0});for(;!(this.stream.eof()||(this.consumeLeadingComments(),this.consumeLeadingAnnotations(),this.isStartOfExcept())||this.isStartOfGroup()||this.isStartOfPolicy());)this.stream.check(A.IDENTIFIER)?i.addRule(this.parseRule()):this.stream.syntaxError(`Unexpected token in group: ${this.stream.peek().type}`,this.stream.peek());return i}parseExceptGroup(e){this.consumeLeadingComments(),this.consumeLeadingAnnotations();const s=this.takeAnnotations("ruleSet");this.stream.expect(A.EXCEPT,'Expected "except"');let i=e;this.stream.check(A.ALL)||this.stream.check(A.ANY)?(i=this.stream.next().type===A.ALL?t.and:t.or,this.stream.check(A.OF)&&this.stream.next(),this.stream.expect(A.COLON,'Expected ":" after except group')):this.stream.expect(A.COLON,'Expected ":" after "except"');const r=new v({id:s.id?.value||null,compareMethod:i,name:s.name?.value||null,description:s.description?.value||null,isExcept:!0,disabled:s.disabled?.value??void 0});for(;!(this.stream.eof()||(this.consumeLeadingComments(),this.consumeLeadingAnnotations(),this.isStartOfGroup()||this.isStartOfPolicy()||this.isStartOfExcept()));)this.stream.check(A.IDENTIFIER)?r.addRule(this.parseRule()):this.stream.syntaxError(`Unexpected token in except group: ${this.stream.peek().type}`,this.stream.peek());return r}parseRule(){this.consumeLeadingComments(),this.consumeLeadingAnnotations();const t=this.takeAnnotations("rule"),e=this.stream.check(A.ALWAYS)||this.stream.check(A.NEVER);e||this.stream.check(A.IDENTIFIER)||this.stream.syntaxError(`Expected identifier, but got ${this.stream.peek().type}`,this.stream.peek());const s=e?"":this.stream.expect(A.IDENTIFIER,"Expected field").value;if(this.aliasBuffer.has(s))return this.aliasBuffer.get(s);const{condition:i,operator:r}=this.parseConditionOperator();let n=null,a=null;return r!==A.EQ_NULL&&r!==A.NOT_EQ_NULL&&r!==A.NULL&&r!==A.ALWAYS&&r!==A.NEVER&&r!==A.DEFINED&&(this.stream.mark(),n=this.parseValue(),a=this.stream.lookPrev(),this.stream.commit()),this.consumeLeadingComments(),this.consumeLeadingAnnotations(),this.consumeLeadingAliases(),"string"==typeof n&&a&&a.type===A.IDENTIFIER&&!a.value.includes(".")&&this.stream.syntaxError(`Expected comparison operator or value, got \`${n}\``,a,[A.KEYWORD]),new _({id:t.id?.value||null,subject:s,resource:n,condition:i,name:t.name?.value||null,description:t.description?.value||null,disabled:t.disabled?.value??void 0})}parseConditionOperator(){if(this.stream.mark(),this.matchWord("always"))return this.stream.commit(),{condition:i.always,operator:A.ALWAYS};if(this.stream.reset(),this.stream.mark(),this.matchWord("never"))return this.stream.commit(),{condition:i.never,operator:A.NEVER};if(this.stream.reset(),this.stream.mark(),(this.matchWord("length")||this.matchWord("len"))&&this.matchWord("equals"))return this.stream.commit(),{condition:i.length_equals,operator:A.LEN_EQ};if(this.stream.reset(),this.stream.mark(),(this.matchWord("length")||this.matchWord("len"))&&this.matchSymbol("="))return this.stream.commit(),{condition:i.length_equals,operator:A.LEN_EQ};if(this.stream.reset(),this.stream.mark(),(this.matchWord("length")||this.matchWord("len"))&&this.matchWord("greater")&&this.matchWord("than"))return this.stream.commit(),{condition:i.length_greater_than,operator:A.LEN_GT};if(this.stream.reset(),this.stream.mark(),(this.matchWord("length")||this.matchWord("len"))&&this.matchSymbol(">"))return this.stream.commit(),{condition:i.length_greater_than,operator:A.LEN_GT};if(this.stream.reset(),this.stream.mark(),(this.matchWord("length")||this.matchWord("len"))&&this.matchWord("less")&&this.matchWord("than"))return this.stream.commit(),{condition:i.length_less_than,operator:A.LEN_LT};if(this.stream.reset(),this.stream.mark(),(this.matchWord("length")||this.matchWord("len"))&&this.matchSymbol("<"))return this.stream.commit(),{condition:i.length_less_than,operator:A.LEN_LT};if(this.stream.reset(),this.stream.mark(),this.matchWord("greater")&&this.matchWord("than")&&this.matchWord("or")&&this.matchWord("equal"))return this.stream.commit(),{condition:i.greater_or_equal,operator:A.GTE};if(this.stream.reset(),this.stream.mark(),this.matchWord("greater")&&this.matchWord("than"))return this.stream.commit(),{condition:i.greater_than,operator:A.GT};if(this.stream.reset(),this.stream.mark(),this.matchWord("less")&&this.matchWord("than")&&this.matchWord("or")&&this.matchWord("equal"))return this.stream.commit(),{condition:i.less_or_equal,operator:A.LTE};if(this.stream.reset(),this.matchWord("less")&&this.matchWord("than"))return{condition:i.less_than,operator:A.LT};if(this.stream.reset(),this.stream.mark(),this.matchWord("not")&&this.matchWord("contains"))return this.stream.commit(),{condition:i.not_contains,operator:A.NOT_CONTAINS};if(this.stream.reset(),this.stream.mark(),this.matchWord("not")&&this.matchWord("includes"))return this.stream.commit(),{condition:i.not_contains,operator:A.NOT_CONTAINS};if(this.stream.reset(),this.stream.mark(),this.matchWord("not")&&this.matchWord("has"))return this.stream.commit(),{condition:i.not_contains,operator:A.NOT_CONTAINS};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("equals"))return this.stream.commit(),{condition:i.equals,operator:A.EQ};if(this.stream.reset(),this.stream.mark(),this.matchWord("not")&&this.matchWord("equals"))return this.stream.commit(),{condition:i.not_equals,operator:A.NOT_EQ};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("not")&&this.matchWord("equals"))return this.stream.commit(),{condition:i.not_equals,operator:A.NOT_EQ};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("in"))return this.stream.commit(),{condition:i.in,operator:A.IN};if(this.stream.reset(),this.stream.mark(),this.matchWord("not")&&this.matchWord("in"))return this.stream.commit(),{condition:i.not_in,operator:A.NOT_IN};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("not")&&this.stream.check(A.NULL))return this.stream.next(),this.stream.commit(),{condition:i.not_equals,operator:A.NOT_EQ_NULL};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("null")&&this.stream.check(A.NULL))return this.stream.commit(),this.stream.next(),{condition:i.equals,operator:A.EQ_NULL};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("defined"))return this.stream.commit(),{condition:i.defined,operator:A.DEFINED};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("not")&&this.matchWord("defined"))return this.stream.commit(),{condition:i.not_defined,operator:A.DEFINED};this.stream.reset();const t=this.stream.peek();switch(t.type!==A.SYMBOL&&t.type!==A.KEYWORD&&t.type!==A.NULL&&this.stream.syntaxError(`Expected comparison operator, got \`${t.value}\``,t,[A.SYMBOL,A.KEYWORD,A.NULL]),this.stream.next(),t.type){case A.SYMBOL:if("="===t.value||"=="===t.value)return{condition:i.equals,operator:A.EQ};if("!="===t.value||"<>"===t.value)return{condition:i.not_equals,operator:A.NOT_EQ};if(">"===t.value)return{condition:i.greater_than,operator:A.GT};if("<"===t.value)return{condition:i.less_than,operator:A.LT};if(">="===t.value)return{condition:i.greater_or_equal,operator:A.GTE};if("<="===t.value)return{condition:i.less_or_equal,operator:A.LTE};break;case A.KEYWORD:if("contains"===t.value||"includes"===t.value||"has"===t.value)return{condition:i.contains,operator:A.CONTAINS};if("in"===t.value)return{condition:i.in,operator:A.IN};if("equals"===t.value)return{condition:i.equals,operator:A.EQ};if("gte"===t.value)return{condition:i.greater_or_equal,operator:A.GTE};if("greater"===t.value||"gt"===t.value)return{condition:i.greater_than,operator:A.GT};if("less"===t.value||"lt"===t.value)return{condition:i.less_than,operator:A.LT};if("lte"===t.value)return{condition:i.less_or_equal,operator:A.LTE};if("is"===t.value)return{condition:i.equals,operator:A.EQ}}return this.stream.syntaxError(`Unexpected operator token \`${t.value}\``,t,[A.SYMBOL,A.KEYWORD])}matchWord(t){if(this.stream.eof())return!1;const e=this.stream.peek();return(e.type===A.KEYWORD||e.type===A.IDENTIFIER||e.type===A.ALWAYS||e.type===A.NEVER||e.type===A.DEFINED)&&e.value===t&&(this.stream.next(),!0)}matchSymbol(t){if(this.stream.eof())return!1;const e=this.stream.peek();return e.type===A.SYMBOL&&e.value===t&&(this.stream.next(),!0)}parseValue(){if(this.stream.check(A.LBRACKET))return this.stream.next(),this.parseArray();const t=this.stream.peek();switch(t.type!==A.ALL&&t.type!==A.ANY&&t.type!==A.EFFECT||this.stream.syntaxError(`Unexpected ${t.type} in value position`,t),this.stream.next(),t.type){case A.STRING:return t.value;case A.NUMBER:return Number(t.value);case A.BOOLEAN:return"true"===t.value;case A.NULL:return null;case A.DEFINED:return void 0!==t.value;case A.IDENTIFIER:return t.value;default:this.stream.syntaxError(`Unexpected value token "${t.value}"`,t,[A.KEYWORD])}}parseArray(){const t=[];if(this.stream.check(A.RBRACKET))return this.stream.next(),t;for(;!this.stream.eof()&&!this.stream.check(A.RBRACKET);){const e=this.parseValue();Array.isArray(e)?t.push(...e):"string"==typeof e||"number"==typeof e||"boolean"==typeof e?t.push(e):null===e&&this.stream.syntaxError("Unexpected null in array",this.stream.peek()),this.stream.check(A.COMMA)&&this.stream.next()}return this.stream.expect(A.RBRACKET,'Expected "]"'),t}consumeLeadingComments(){for(;this.stream.check(A.COMMENT);)this.stream.next()}consumeLeadingAliases(){for(;this.stream.check(A.ALIAS);){this.stream.next();const t=this.stream.expect(A.IDENTIFIER,"Expected alias name").value;this.stream.expect(A.COLON,"Expected colon after an alias");const e=this.takeAnnotations("alias");for(;!this.stream.eof()&&!this.isStartOfAlias()&&!this.isStartOfPolicy();){const s=this.parseRule();s.name=e.get("name")?.value||t,s.description=e.get("description")?.value,!0===e.get("disabled")?.value&&(s.disabled=!0),this.aliasBuffer.set(t,s)}}}consumeLeadingAnnotations(){for(;this.stream.check(A.ANNOTATION);){const t=this.stream.next(),e=t.value.trim();if(e.startsWith("@id ")&&this.annBuffer.setID(e.slice(4).trim(),t),e.startsWith("@name ")&&this.annBuffer.setName(e.slice(6).trim(),t),e.startsWith("@description ")&&this.annBuffer.setDescription(e.slice(13).trim(),t),e.startsWith("@priority ")&&this.annBuffer.setPriority(parseInt(e.slice(10).trim(),10),t),e.startsWith("@disabled")){const s=e.slice(9).trim();this.annBuffer.setDisabled(0===s.length||"true"===e.slice(9).trim(),t)}if(e.startsWith("@tags ")){const s=e.slice(6).trim().split(",").map(t=>t.trim());this.annBuffer.setTags(s,t)}}}takeAnnotations(t){const e=this.annBuffer.clone();this.annBuffer.clear();const s=T[t];for(const i of Object.keys(e.store)){const r=e.get(i);r&&(s.has(i)||this.stream.syntaxError(`Annotation @${i} is not allowed on ${t}. Allowed: ${[...s].map(t=>"@"+t).join(", ")}`,r.token??this.stream.peek()))}return e}isStartOfPolicy(){return this.stream.check(A.EFFECT)}isStartOfGroup(){return this.stream.check(A.ALL)||this.stream.check(A.ANY)}isStartOfRule(){return this.stream.check(A.IDENTIFIER)||this.stream.check(A.ALWAYS)||this.stream.check(A.NEVER)}isStartOfExcept(){return this.stream.check(A.EXCEPT)}isStartOfAlias(){return this.stream.check(A.ALIAS)}}function $(t,...e){const s=t.reduce((t,s,i)=>t+s+(e[i]??""),"");return new w(s).parse()}class I{policies;matched;constructor(t){this.policies=t,this.matched=t.filter(t=>t.matchState===c.match)}matchedPolicies(){return this.matched}hasMatched(){return this.matched.length>0}firstMatched(){return this.matchedPolicies()[0]??null}lastMatched(){const t=this.matchedPolicies();return t.length>0?t[t.length-1]:null}firstDenied(){return this.getDenyPolicies()[0]??null}firstPermitted(){return this.getPermitPolicies()[0]??null}getPermitPolicies(){return this.matched.filter(t=>t.effect===p.permit)}getDenyPolicies(){return this.matched.filter(t=>t.effect===p.deny)}hasPermit(){return this.getPermitPolicies().length>0}hasDeny(){return this.getDenyPolicies().length>0}isAllowed(){return this.evaluate()===p.permit}isDenied(){return this.evaluate()===p.deny}}class W extends I{_decisive=null;evaluate(){if(!this.hasMatched())return this._decisive=null,p.deny;const t=this.firstDenied();return t?(this._decisive=t,p.deny):(this._decisive=this.firstPermitted(),p.permit)}decisivePolicy(){return this._decisive}}class M extends I{_decisive=null;evaluate(){const t=this.firstPermitted();return t?(this._decisive=t,p.permit):(this._decisive=null,p.deny)}decisivePolicy(){return this._decisive}}class R extends I{_decisive=null;evaluate(){const t=this.firstDenied();if(t)return this._decisive=t,p.deny;const e=this.firstPermitted();return e?(this._decisive=e,p.permit):(this._decisive=null,p.deny)}decisivePolicy(){return this._decisive}}class D extends I{_decisive=null;evaluate(){const t=this.firstMatched();return t?(this._decisive=t,t.effect):(this._decisive=null,p.deny)}decisivePolicy(){return this._decisive}}class P extends I{_decisive=null;evaluate(){const t=this.matchedPolicies();return 1===t.length?(this._decisive=t[0],t[0].effect):(this._decisive=null,p.deny)}decisivePolicy(){return this._decisive}}class C extends I{_decisive=null;evaluate(){const t=this.matchedPolicies().find(t=>t.effect===p.permit);if(t)return this._decisive=t,p.permit;const e=this.matchedPolicies().find(t=>t.effect===p.deny);return e?(this._decisive=e,p.deny):(this._decisive=null,p.deny)}decisivePolicy(){return this._decisive}}class j extends I{_decisive=null;evaluate(){const t=this.lastMatched();return t?(this._decisive=t,t.effect):(this._decisive=null,p.deny)}decisivePolicy(){return this._decisive}}class q extends I{_decisive=null;evaluate(){const t=this.matchedPolicies();if(0===t.length)return this._decisive=null,p.deny;const e=[...t].sort((t,e)=>e.priority-t.priority)[0];return this._decisive=e,e.effect}decisivePolicy(){return this._decisive}}export{t as AbilityCompare,i as AbilityCondition,b as AbilityDSLLexer,w as AbilityDSLParser,S as AbilityDSLToken,e as AbilityError,h as AbilityExplain,d as AbilityExplainPolicy,l as AbilityExplainRule,u as AbilityExplainRuleSet,N as AbilityJSONParser,c as AbilityMatch,s as AbilityParserError,E as AbilityPolicy,p as AbilityPolicyEffect,f as AbilityResolver,m as AbilityResult,_ as AbilityRule,v as AbilityRuleSet,I as AbilityStrategy,y as AbilityTypeGenerator,W as AllMustPermitStrategy,M as AnyPermitStrategy,R as DenyOverridesStrategy,D as FirstMatchStrategy,P as OnlyOneApplicableStrategy,C as PermitOverridesStrategy,q as PriorityStrategy,j as SequentialLastMatchStrategy,A as TokenTypes,$ as ability,r as fromLiteral,a as isConditionEqual,o as isConditionNotEqual,n as toLiteral};
|
|
1
|
+
const t={or:"or",and:"and"};class e extends Error{constructor(t,e){super(t,e),this.name="AbilityError",Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}}class s extends Error{constructor(t,e){super(t,e),this.name="AbilityParserError",Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}}const i={equals:"=",defined:"defined",not_defined:"not_defined",not_equals:"<>",greater_than:">",less_than:"<",less_or_equal:"<=",greater_or_equal:">=",in:"in",not_in:"not in",contains:"contains",not_contains:"not contains",length_greater_than:"length greater than",length_less_than:"length less than",length_equals:"length equals",always:"always",never:"never"};function r(t){const e={equals:i.equals,not_equals:i.not_equals,greater_than:i.greater_than,less_than:i.less_than,less_or_equal:i.less_or_equal,greater_or_equal:i.greater_or_equal,in:i.in,not_in:i.not_in,contains:i.contains,not_contains:i.not_contains,length_greater_than:i.length_greater_than,length_less_than:i.length_less_than,length_equals:i.length_equals,always:i.always,never:i.never,defined:i.defined,not_defined:i.not_defined},r=e[t];if(!r){const i=Object.keys(e).join(", ");throw new s(`Literal "${t}" does not found in AbilityCondition. Expected one of: ${i}`)}return r}function n(t){switch(t){case i.equals:return"equals";case i.not_equals:return"not_equals";case i.greater_than:return"greater_than";case i.less_than:return"less_than";case i.less_or_equal:return"less_or_equal";case i.greater_or_equal:return"greater_or_equal";case i.in:return"in";case i.not_in:return"not_in";case i.contains:return"contains";case i.not_contains:return"not_contains";case i.length_greater_than:return"length_greater_than";case i.length_less_than:return"length_less_than";case i.length_equals:return"length_equals";case i.always:return"always";case i.never:return"never";case i.defined:return"defined";case i.not_defined:return"not_defined";default:return"never"}}function a(t,e){return null!==t&&null!==e&&t===e}function o(t,e){return!a(t,e)}const c={pending:"pending",match:"match",mismatch:"mismatch",exceptMismatch:"except-mismatch",disabled:"disabled"};class h{type;children;_name;match;debugInfo;constructor(t,e=[]){this.type=t.type,this.children=e,this._name=t.name,this.match=t.match,this.debugInfo=t.debugInfo}get name(){const t=this._name.substring(0,60);return`${t}${t.length<this._name.length?"...":""}`}toString(t="",e=!0){const s=this.match===c.match,i=this.match===c.mismatch,r=this.match===c.pending,n=`[${s?"MATCH ✓":i?"MISMATCH ✗":r?"PENDING …":"DISABLED ⊘"}]`.padEnd(15," "),a=("policy"===this.type?"POLICY":"ruleSet"===this.type?"RULESET":"RULE").padEnd(10," ");let o=`${t}${0===t.length?"":e?"└─ ":"├─ "}${n}${a}${this.name}`;this.debugInfo&&(o+=` (${this.debugInfo})`);const h=t+(e?" ":"│ ");return this.children.forEach((t,e)=>{o+="\n"+t.toString(h,e===this.children.length-1)}),o}}class l extends h{constructor(t){super({type:"rule",match:t.state,name:t.name,debugInfo:`${t.subject} ${t.condition} ${JSON.stringify(t.resource)}`})}}class u extends h{constructor(t){const e=t.rules.map(t=>new l(t));super({type:"ruleSet",match:t.state,name:t.name},e)}}class d extends h{constructor(t){const e=t.ruleSet.map(t=>new u(t));super({type:"policy",name:t.priority>-1?`@priority ${t.priority} <${t.effect}> ${t.name}`:`<${t.effect}> ${t.name}`,match:t.matchState},e)}}class m{effect;strategy;constructor(t,e){this.effect=t,this.strategy=e}explain(){return`${this.strategy.isDenied()?"== DENIED==":"== ALLOWED =="}\n${this.strategy.policies.map(t=>new d(t).toString()).join("\n")}\n`}decisive(){return this.strategy.decisivePolicy()}explainDecisive(){const t=this.decisive();return t?new d(t).toString():null}isAllowed=()=>this.strategy.isAllowed();isDenied=()=>this.strategy.isDenied()}const p={deny:"deny",permit:"permit"};class f{onDeny;onAllow;StrategyClass;policyEntries;constructor(t,e,s={}){const i=this.toArray(t);this.onDeny=s.onDeny,this.onAllow=s.onAllow;const r=[...s.tags?i.filter(t=>t.tags.some(t=>s.tags.includes(t))):i].sort((t,e)=>e.priority-t.priority);this.policyEntries=r.map(t=>({policy:t,normalizedPermission:f.normalizePermission(t.permission),segments:f.normalizePermission(t.permission).split(".")})),this.StrategyClass=e}resolve(t,s,i){const r=f.normalizePermission(String(t)).split("."),n=this.policyEntries.filter(t=>f.matchPermissions(t.segments,r)).map(t=>t.policy);for(const t of n)if(!t.disabled&&t.check(s,i)===c.pending)throw new e(`The policy "${t.name}" is still in a pending state. Make sure to call "check" to evaluate the policy before resolving permissions.`);const a=new this.StrategyClass(n),o=a.evaluate(),h=new m(o,a);return o===p.deny&&this.onDeny&&this.onDeny(h),o===p.permit&&this.onAllow&&this.onAllow(h),h}enforce(t,s,i,r){const n=this.resolve(t,s,i);if(n.isDenied())throw r?.onDeny&&r?.onDeny(n),new e("Permission denied")}static isInPermissionContain(t,e){const s=t.split("."),i=e.split("."),[r,n]=s.length>=i.length?[s,i]:[i,s];return n.every((t,e)=>"*"===t||"*"===r[e]||t===r[e])}toArray(t){return[...Array.isArray(t)?t:[t]]}static normalizePermission(t){return t.trim().replace(/^permission\./,"").replace(/\.+/g,".").toLowerCase()}static matchPermissions(t,e){let s=0;for(;s<t.length;s++){const i=t[s],r=e[s];if("*"===i)return!0;if(void 0===r)return!1;if(i!==r)return!1}return s===e.length}}class y{policies;policyEntries;constructor(t){this.policies=t,this.policyEntries=t.map(t=>({policy:t,normalizedPermission:f.normalizePermission(t.permission),segments:f.normalizePermission(t.permission).split(".")}))}generateTypeDefs(){const t={},e={},s=new Set;this.policies.forEach(i=>{i.tags.forEach(t=>s.add(t));const r=i.permission;t[r]||(t[r]={}),i.ruleSet.forEach(s=>{s.rules.forEach(s=>{const i=s.subject,n=this.determineTypeFromRule(s);if(n){if(i.startsWith("env.")){const t=i.replace(/^env\./,"");e[r]||(e[r]={}),e[r][t]=n}else{const e=t[r][i];t[r][i]=e&&e!==n?`${e} | ${n}`:n}if("string"==typeof s.resource&&this.isPath(s.resource)){const i=s.resource;if(i.startsWith("env.")){const t=i.replace(/^env\./,"");e[r]||(e[r]={});const s=e[r][t],a=n;e[r][t]=s&&s!==a?`${s} | ${a}`:a}else{t[r]||(t[r]={});const e=t[r][i],s=n;t[r][i]=e&&e!==s?`${e} | ${s}`:s}}}})})});const i={};Object.entries(t).forEach(([t,e])=>{t.endsWith(".*")||(i[t]=e)});const r=this.buildNestedStructure(i),n=this.buildNestedStructure(e);return this.formatTypeDefinitions(r,n,s)}isPath(t){return"string"==typeof t&&!t.startsWith('"')&&!t.startsWith("'")&&t.includes(".")}determineTypeFromRule(t){return t.condition===i.never||t.condition===i.always?null:t.condition===i.contains||t.condition===i.not_contains?this.getArrayType(t.resource):t.condition===i.length_equals||t.condition===i.length_greater_than||t.condition===i.length_less_than?"string | readonly unknown[]":t.condition===i.greater_than||t.condition===i.greater_or_equal||t.condition===i.less_than||t.condition===i.less_or_equal?"number":t.condition===i.in||t.condition===i.not_in?this.getInArrayType(t.resource):t.condition===i.equals||t.condition===i.not_equals?this.getPrimitiveType(t.resource):"any"}getArrayType(t){return`readonly ${this.getInArrayType(t)}[]`}getInArrayType(t){if(Array.isArray(t)){if(0===t.length)return"unknown";const e=new Set(t.map(t=>this.getPrimitiveType(t)));return 1===e.size?Array.from(e)[0]:`(${Array.from(e).join(" | ")})`}return this.getPrimitiveType(t)}getPrimitiveType(t){if(null===t)return"null | unknown";if(void 0===t)return"undefined";if("string"==typeof t&&this.isPath(t))return"unknown";switch(typeof t){case"string":return"string";case"number":return"number";case"boolean":return"boolean";case"object":return Array.isArray(t)?"array":"object";default:return"any"}}buildNestedStructure(t){const e={};return Object.entries(t).forEach(([t,s])=>{e[t]={},Object.entries(s).forEach(([s,i])=>{const r=s.split(".");let n=e[t];for(let t=0;t<r.length-1;t++){const e=r[t],s=n[e];if(s&&"object"==typeof s)n=s;else{const t={};n[e]=t,n=t}}n[r[r.length-1]]=i})}),e}formatTypeDefinitions(t,e,s){let i="// Automatically generated by via-profit/ability\n";i+="// Do not edit manually\n",i+="export type Resources = {\n",Object.keys(t).sort().forEach(e=>{const s=t[e],r=0===Object.keys(s).length,n=f.normalizePermission(e).split("."),a=this.policyEntries.filter(t=>f.matchPermissions(t.segments,n)).map(t=>t.policy),o=[...new Set(a.map(t=>t.effect))].sort(),c=a.sort((t,e)=>t.id.localeCompare(e.id)).map(t=>{const e=t.effect.padEnd(6," "),s=t.name===t.id?"Unnamed policy":t.name;return` * - ${e} ${t.id} "${s}"`}).join("\n");i+=`\n /**\n * Permission: ${e}\n * Effects: ${o.join(", ")}\n * Policies:\n${c}\n */\n`,r?i+=` ['${e}']: undefined;\n`:(i+=` ['${e}']: {\n`,i+=this.formatNestedObject(s,4),i+=" } | null | undefined;\n")}),i+="}\n";const r=s.size>0?Array.from(s).sort().map(t=>`'${t}'`).join(" | "):"never";return i+=`\n\nexport type PolicyTags = ${r};\n`,i+="\n\nexport type Environment = {\n",Object.entries(e).forEach(([t,e])=>{const s=0===Object.keys(e).length,r=f.normalizePermission(t).split("."),n=this.policyEntries.filter(t=>f.matchPermissions(t.segments,r)).map(t=>t.policy),a=[...new Set(n.map(t=>t.effect))].sort(),o=n.sort((t,e)=>t.id.localeCompare(e.id)).map(t=>{const e=t.effect.padEnd(6," "),s=t.name===t.id?"Unnamed policy":t.name;return` * - ${e} ${t.id} "${s}"`}).join("\n");i+=`\n /**\n * Permission: ${t}\n * Effects: ${a.join(", ")}\n * Policies:\n${o}\n */\n`,s?i+=` ['${t}']: undefined;\n`:(i+=` ['${t}']: {\n`,i+=this.formatNestedObject(e,4),i+=" } | null | undefined;\n")}),i+="}\n",i}formatNestedObject(t,e){const s=" ".repeat(e);let i="";return Object.keys(t).sort().forEach(r=>{const n=t[r];if("object"==typeof n&&null!==n)i+=`${s}readonly ${r}: {\n`,i+=this.formatNestedObject(n,e+2),i+=`${s}} | null | undefined;\n`;else{const t=[String(n)];let e=String(n);e.match(/unknown/)||(e.match(/null/)||t.push("null"),e.match(/undefined/)||t.push("undefined")),i+=`${s}readonly ${r}?: ${[...new Set(t)].join(" | ")} \n`}}),i}}class g{static sha1(t){const e=g.stringToBytes(t),s=8*e.length,i=new Uint8Array(e.length+1);i.set(e,0),i[e.length]=128;let r=(56-i.length%64+64)%64;const n=new Uint8Array(i.length+r+8);n.set(i,0);const a=Math.floor(s/4294967296),o=s>>>0;n[n.length-8]=a>>>24&255,n[n.length-7]=a>>>16&255,n[n.length-6]=a>>>8&255,n[n.length-5]=255&a,n[n.length-4]=o>>>24&255,n[n.length-3]=o>>>16&255,n[n.length-2]=o>>>8&255,n[n.length-1]=255&o;let c=1732584193,h=4023233417,l=2562383102,u=271733878,d=3285377520;const m=new Array(80);for(let t=0;t<n.length;t+=64){for(let e=0;e<16;e++){const s=t+4*e;m[e]=n[s]<<24|n[s+1]<<16|n[s+2]<<8|n[s+3]}for(let t=16;t<80;t++)m[t]=g.leftRotate(m[t-3]^m[t-8]^m[t-14]^m[t-16],1);let e=c,s=h,i=l,r=u,a=d;for(let t=0;t<80;t++){let n,o;t<20?(n=s&i|~s&r,o=1518500249):t<40?(n=s^i^r,o=1859775393):t<60?(n=s&i|s&r|i&r,o=2400959708):(n=s^i^r,o=3395469782);const c=g.leftRotate(e,5)+n+a+o+(0|m[t])|0;a=r,r=i,i=g.leftRotate(s,30),s=e,e=c}c=c+e|0,h=h+s|0,l=l+i|0,u=u+r|0,d=d+a|0}return[g.toHex32(c),g.toHex32(h),g.toHex32(l),g.toHex32(u),g.toHex32(d)].join("")}static leftRotate(t,e){return(t<<e|t>>>32-e)>>>0}static toHex32(t){return(t>>>0).toString(16).padStart(8,"0")}static stringToBytes(t){if("undefined"!=typeof TextEncoder)return(new TextEncoder).encode(t);{const e=Buffer.from(t,"utf8");return new Uint8Array(e.buffer,e.byteOffset,e.byteLength)}}}class E{matchState=c.pending;ruleSet=[];effect;compareMethod=t.and;id;name;description;permission;priority=-1;disabled;tags;constructor(e){const{name:s,description:i,id:r,permission:n,effect:a,compareMethod:o=t.and,priority:c,disabled:h,tags:l}=e;this.permission=n,this.description=i,this.effect=a,this.compareMethod=o,this.priority="number"==typeof c?c:-1,this.disabled="boolean"==typeof h&&h,this.tags=l||[],this.id=r||`p_${this.hash().slice(0,10)}`,this.name=s||this.id}addRuleSet(t){return this.ruleSet.push(t),this}addRuleSets(t){for(const e of t)this.ruleSet.push(e);return this}extractRules(){const t=[];for(const e of this.ruleSet)for(const s of e.rules)t.push(s);return t}check(e,s){if(this.matchState=c.mismatch,this.disabled)return this.matchState=c.disabled,this.matchState;if(!this.ruleSet.length)return this.matchState;const i=this.ruleSet.filter(t=>!t.isExcept),r=this.ruleSet.filter(t=>t.isExcept),n=[];for(const r of i){if(r.disabled)continue;const i=r.check(e,s);if(n.push(i),t.and===this.compareMethod&&c.mismatch===i)return this.matchState=c.mismatch,this.matchState;if(t.or===this.compareMethod&&c.match===i){this.matchState=c.match;break}}let a=!1;if(a=t.and===this.compareMethod?n.every(t=>c.match===t):n.some(t=>c.match===t),!a)return this.matchState=c.mismatch,this.matchState;for(const t of r){if(t.disabled)continue;const i=t.check(e,s);if(c.match===i)return this.matchState=c.exceptMismatch,this.matchState}return this.matchState=c.match,this.matchState}explain(){if(this.matchState===c.pending)throw new e("First, run the check method, then explain");return new d(this)}copyWith(t){const e=new E({id:t.id??this.id,name:t.name??this.name,description:t.description??this.description,priority:void 0!==t.priority?t.priority:this.priority,permission:t.permission??this.permission,effect:t.effect??this.effect,compareMethod:t.compareMethod??this.compareMethod}),s=t.ruleSet??this.ruleSet;for(const t of s)e.addRuleSet(t);return e}hash(){const t=[`permission:${this.permission}`,`effect:${this.effect}`,`compareMethod:${this.compareMethod}`,`priority:${this.priority}`,`disabled:${this.disabled}`];if(this.tags&&this.tags.length>0&&t.push(`tags:${[...this.tags].sort().join(",")}`),this.ruleSet&&this.ruleSet.length>0){const e=this.ruleSet.map(t=>t.hash());t.push(`rules:${e.sort().join("|")}`)}const e=t.join(";");return g.sha1(e)}}class _{subject;resource;condition;name;description;id;state=c.pending;disabled;constructor(t){const{id:e,name:s,subject:i,resource:r,condition:n,disabled:a,description:o}=t;this.description=o,this.disabled="boolean"==typeof a&&a,this.subject=i,this.resource=r,this.condition=n,this.state=this.disabled?c.disabled:this.state,this.id=e||`r_${this.hash().slice(0,10)}`,this.name=s||this.id}static isPrimitive(t){return"string"==typeof t||"number"==typeof t||"boolean"==typeof t||null===t}static isNumber(t){return"number"==typeof t}static isString(t){return"string"==typeof t}static valueLen=t=>this.isString(t)||Array.isArray(t)?t.length:null;static operatorHandlers={[n(i.always)]:()=>!0,[n(i.defined)]:t=>void 0!==t,[n(i.not_defined)]:t=>void 0===t,[n(i.never)]:()=>!1,[n(i.equals)]:(t,e)=>t===e,[n(i.not_equals)]:(t,e)=>t!==e,[n(i.contains)]:(t,e)=>Array.isArray(t)&&_.isPrimitive(e)?t.includes(e):!(!Array.isArray(t)||!Array.isArray(e))&&t.some(t=>e.includes(t)),[n(i.not_contains)]:(t,e)=>Array.isArray(t)&&_.isPrimitive(e)?!t.includes(e):!(!Array.isArray(t)||!Array.isArray(e)||t.some(t=>e.includes(t))),[n(i.in)]:(t,e)=>_.isPrimitive(t)&&Array.isArray(e)?e.includes(t):!(!Array.isArray(t)||!Array.isArray(e))&&t.some(t=>e.includes(t)),[n(i.not_in)]:(t,e)=>_.isPrimitive(t)&&Array.isArray(e)?!e.includes(t):!(!Array.isArray(t)||!Array.isArray(e)||t.some(t=>e.includes(t))),[n(i.greater_than)]:(t,e)=>!(!_.isNumber(t)||!_.isNumber(e))&&t>e,[n(i.less_than)]:(t,e)=>!(!_.isNumber(t)||!_.isNumber(e))&&t<e,[n(i.greater_or_equal)]:(t,e)=>!(!_.isNumber(t)||!_.isNumber(e))&&t>=e,[n(i.less_or_equal)]:(t,e)=>!(!_.isNumber(t)||!_.isNumber(e))&&t<=e,[n(i.length_greater_than)]:(t,e)=>{const s=_.valueLen(t);if(null===s)return!1;if(_.isNumber(e))return s>e;const i=_.valueLen(e);return null!==i&&s>i},[n(i.length_less_than)]:(t,e)=>{const s=_.valueLen(t);if(null===s)return!1;if(_.isNumber(e))return s<e;const i=_.valueLen(e);return null!==i&&s<i},[n(i.length_equals)]:(t,e)=>{const s=_.valueLen(t);if(null===s)return!1;if(_.isNumber(e))return s===e;const i=_.valueLen(e);return null!==i&&s===i}};check(t,e){if(this.disabled)return this.state=c.disabled,this.state;const[s,i]=this.extractValues(t,e),r=(0,_.operatorHandlers[n(this.condition)])(s,i);return this.state=r?c.match:c.mismatch,this.state}extractValues(t,e){let s,i;return null==t&&null==e?[NaN,NaN]:(s=this.subject.includes(".")?this.subject.startsWith("env.")&&void 0!==e?this.getDotNotationValue(e,this.subject.replace(/^env\./,"")):this.getDotNotationValue(t,this.subject):this.subject,i="string"==typeof this.resource&&this.resource.includes(".")?this.resource.startsWith("env.")&&void 0!==e?this.getDotNotationValue(e,this.resource.replace(/^env\./,"")):this.getDotNotationValue(t,this.resource):this.resource,[s,i])}static _pathCache=new Map;static _parsePath(t){const e=_._pathCache.get(t);if(e)return e;const s=t.split("."),i=[];for(const t of s){const e=t.indexOf("[");if(-1!==e){const s=t.slice(0,e),r=t.slice(e+1,-1),n=Number(r);i.push({prop:s,index:n})}else i.push(t)}return _._pathCache.set(t,i),i}getDotNotationValue(t,e){if(null==t)return;const s=_._parsePath(e);let i=t;for(const t of s){if(null==i)return;if("string"==typeof t)i=i[t];else{const e=i[t.prop];i=Array.isArray(e)?e[t.index]:void 0}}return i}toString(){return`AbilityRule: ${this.name} condition: ${n(this.condition)} subject: "${this.subject?.toString()}" resource: "${this.resource?.toString()}"`}copyWith(t){return new _({id:t.id??this.id,name:t.name??this.name,description:t.description??this.description,subject:t.subject??this.subject,resource:t.resource??this.resource,condition:t.condition??this.condition})}hash(){const t=[];return t.push(`subject:${this.subject}`),t.push(`resource:${JSON.stringify(this.resource)}`),t.push(`condition:${this.condition}`),t.push(`disabled:${this.disabled}`),g.sha1(t.join(";"))}static equals(t,e){return new _({condition:i.equals,subject:t,resource:e})}static notEquals(t,e){return new _({condition:i.not_equals,subject:t,resource:e})}static contains(t,e){return new _({condition:i.contains,subject:t,resource:e})}static notContains(t,e){return new _({condition:i.not_contains,subject:t,resource:e})}static notIn(t,e){return new _({condition:i.not_in,subject:t,resource:e})}static in(t,e){return new _({condition:i.in,subject:t,resource:e})}static notEqual(t,e){return new _({condition:i.not_equals,subject:t,resource:e})}static lessThan(t,e){return new _({condition:i.less_than,subject:t,resource:e})}static lessOrEqual(t,e){return new _({condition:i.less_or_equal,subject:t,resource:e})}static moreThan(t,e){return new _({condition:i.greater_than,subject:t,resource:e})}static moreOrEqual(t,e){return new _({condition:i.greater_or_equal,subject:t,resource:e})}}class v{state=c.pending;rules=[];compareMethod=t.and;name;description;id;isExcept=!1;disabled;constructor(t){const{name:e,id:s,compareMethod:i,isExcept:r,disabled:n,description:a}=t;this.description=a,this.compareMethod=i,this.isExcept=r,this.disabled="boolean"==typeof n&&n,this.state=this.disabled?c.disabled:this.state,this.id=s||`g_${this.hash().slice(0,10)}`,this.name=e||this.id}addRule(t){return this.rules.push(t),this}addRules(t){return t.forEach(t=>this.addRule(t)),this}check(e,s){if(this.state=c.mismatch,this.disabled)return this.state=c.disabled,this.state;if(!this.rules.length)return this.state;const i=[];for(const r of this.rules){if(r.disabled)continue;const n=r.check(e,s);if(i.push(n),t.and===this.compareMethod&&c.mismatch===n)return this.state;if(t.or===this.compareMethod&&c.match===n)return this.state=c.match,this.state}return t.and===this.compareMethod&&i.every(t=>c.match===t)&&(this.state=c.match),t.or===this.compareMethod&&i.some(t=>c.match===t)&&(this.state=c.match),this.state}toString(){return`AbilityRuleSet: ${this.name} compareMethod: ${this.compareMethod}, rules: ${this.rules.map(t=>t.toString()).join("\n")}`}copyWith(t){const e=new v({id:t.id??this.id,name:t.name??this.name,description:t.description??this.description,compareMethod:t.compareMethod??this.compareMethod}),s=t.rules??this.rules;for(const t of s)e.addRule(t);return e}hash(){const t=this.rules.map(t=>t.hash()).sort(),e=[`compareMethod:${this.compareMethod}`,`isExcept:${this.isExcept}`,`disabled:${this.disabled}`,`rules:${t.join("|")}`];return g.sha1(e.join(";"))}static and(e){return new v({compareMethod:t.and}).addRules(e)}static or(e){return new v({compareMethod:t.or}).addRules(e)}}class N{static parse(t){return t.map(t=>N.parsePolicy(t))}static parsePolicy(t){const{id:e,name:s,ruleSet:i,compareMethod:r,permission:n,effect:a,priority:o,disabled:c,tags:h}=t,l=new E({name:s,id:e,permission:n,priority:o,effect:a,disabled:c,tags:h});return l.compareMethod=r,i.forEach(t=>{l.addRuleSet(N.parseRuleSet(t))}),l}static parseRule(t){const{id:e,name:s,subject:i,resource:r,condition:n,disabled:a}=t;return new _({id:e,name:s,subject:i,resource:r,disabled:a,condition:n})}static parseRuleSet(t){const{id:e,name:s,rules:i,compareMethod:r,disabled:n}=t,a=new v({disabled:n,compareMethod:r,name:s,id:e});if(i&&i.length>0){const t=i.map(t=>N.parseRule(t));a.addRules(t)}return a}static ruleToJSON(t){return{id:t.id,name:t.name,disabled:t.disabled,subject:t.subject,resource:t.resource,condition:t.condition}}static ruleSetToJSON(t){return{id:t.id.toString(),name:t.name.toString(),disabled:t.disabled,compareMethod:t.compareMethod,rules:t.rules.map(t=>N.ruleToJSON(t))}}static policyToJSON(t){return{id:t.id.toString(),name:t.name.toString(),disabled:t.disabled,priority:t.priority,permission:t.permission,effect:t.effect,compareMethod:t.compareMethod,tags:t.tags,ruleSet:t.ruleSet.map(t=>N.ruleSetToJSON(t))}}static toJSON(t){return t.map(t=>N.policyToJSON(t))}}const A={EFFECT:"EFFECT",IF:"IF",PERMISSION:"PERMISSION",IDENTIFIER:"IDENTIFIER",COLON:"COLON",COMMA:"COMMA",DOT:"DOT",LBRACKET:"LBRACKET",RBRACKET:"RBRACKET",ALL:"ALL",ANY:"ANY",OF:"OF",EOF:"EOF",COMMENT:"COMMENT",EQ:"EQ",CONTAINS:"CONTAINS",IN:"IN",NOT_IN:"NOT_IN",NOT_CONTAINS:"NOT_CONTAINS",GT:"GT",GTE:"GTE",LT:"LT",LTE:"LTE",NULL:"NULL",EQ_NULL:"EQ_NULL",NOT_EQ_NULL:"NOT_EQ_NULL",DEFINED:"DEFINED",NOT_EQ:"NOT_EQ",LEN_GT:"LEN_GT",LEN_LT:"LEN_LT",LEN_EQ:"LEN_EQ",ALWAYS:"ALWAYS",NEVER:"NEVER",EXCEPT:"EXCEPT",ANNOTATION:"ANNOTATION",STRING:"STRING",NUMBER:"NUMBER",BOOLEAN:"BOOLEAN",SYMBOL:"SYMBOL",KEYWORD:"KEYWORD",ALIAS:"ALIAS",UNKNOWN:"UNKNOWN"};class S{type;value;line;column;constructor(t,e,s,i){this.type=t,this.value=e,this.line=s,this.column=i}toString(){return`AbilityDSLToken([${this.type}] "${this.value}" at ${this.line}:${this.column})`}}class b{input;pos=0;tokens=[];line=1;column=1;keywords=new Set(["if","all","any","of","permit","allow","deny","forbidden","true","false","null","defined","contains","includes","length","len","has","in","gt","lt","gte","lte","equals","greater","less","not","is","or","than","always","never","except","alias"]);constructor(t){this.input=t}tokenize(){for(;!this.isAtEnd()&&(this.skipWhitespace(),!this.isAtEnd());){const t=this.peek();if("@"!==t)if("#"!==t)if('"'!==t&&"'"!==t)if(this.isDigit(t))this.tokens.push(this.readNumber());else if(this.isSymbol(t))this.tokens.push(this.readSymbol());else{if(!this.isAlpha(t))throw new Error(`Unexpected character '${t}' at ${this.line}:${this.column}`);this.tokens.push(this.readWord())}else this.tokens.push(this.readString());else this.tokens.push(this.readComment());else this.tokens.push(this.readAnnotation())}return this.tokens.push(new S(A.EOF,"",this.line,this.column)),this.tokens}readComment(){const t=this.line,e=this.column;this.advance();let s="";for(;!this.isAtEnd()&&!this.isNewline();)s+=this.advance();return new S(A.COMMENT,s.trim(),t,e)}readAnnotation(){const t=this.line,e=this.column;let s="";for(;!this.isAtEnd()&&!this.isNewline();)s+=this.advance();s=s.trim();let i="",r=0,n=!1,a=null,o=!1;for(;r<s.length;){const t=s[r];n?(o?(i+=t,o=!1):"\\"===t?o=!0:t===a?(n=!1,a=null):i+=t,r++):'"'!==t&&"'"!==t?(i+=t,r++):(n=!0,a=t,r++)}return new S(A.ANNOTATION,i.trim(),t,e)}readString(){const t=this.line,e=this.column,s=this.advance();let i="",r=!1;for(;!this.isAtEnd();){const n=this.advance();if(r)i+=n,r=!1;else if("\\"!==n){if(n===s)return new S(A.STRING,i,t,e);i+=n}else r=!0}throw new Error(`Unterminated string at ${t}:${e}`)}readNumber(){const t=this.line,e=this.column,s=this.pos;for(;!this.isAtEnd()&&this.isDigit(this.peek());)this.advance();const i=this.input.slice(s,this.pos);return new S(A.NUMBER,i,t,e)}readSymbol(){const t=this.line,e=this.column,s=this.advance();switch(s){case".":return new S(A.DOT,s,t,e);case":":return new S(A.COLON,s,t,e);case",":return new S(A.COMMA,s,t,e);case"[":return new S(A.LBRACKET,s,t,e);case"]":return new S(A.RBRACKET,s,t,e);case">":return"="===this.peek()?(this.advance(),new S(A.SYMBOL,">=",t,e)):new S(A.SYMBOL,">",t,e);case"<":return"="===this.peek()?(this.advance(),new S(A.SYMBOL,"<=",t,e)):">"===this.peek()?(this.advance(),new S(A.SYMBOL,"<>",t,e)):new S(A.SYMBOL,"<",t,e);case"=":return"="===this.peek()?(this.advance(),new S(A.SYMBOL,"==",t,e)):new S(A.SYMBOL,"=",t,e);case"!":if("="===this.peek())return this.advance(),new S(A.SYMBOL,"!=",t,e);throw new Error(`Unexpected symbol '!' at ${this.line}:${this.column}`);default:throw new Error(`Unknown symbol '${s}' at ${this.line}:${this.column}`)}}readWord(){const t=this.line,e=this.column,s=this.pos;for(;!this.isAtEnd()&&/[a-zA-Z0-9_*]/.test(this.peek());)this.advance();for(;!this.isAtEnd()&&"."===this.peek()&&(this.advance(),/[a-zA-Z_*]/.test(this.peek()));)for(;!this.isAtEnd()&&/[a-zA-Z0-9_*]/.test(this.peek());)this.advance();const i=this.input.slice(s,this.pos);if("always"===i)return new S(A.ALWAYS,i,t,e);if("never"===i)return new S(A.NEVER,i,t,e);if(i.includes(".")){const s=this.tokens[this.tokens.length-1];return s?.type===A.EFFECT&&i.startsWith("permission.")?new S(A.PERMISSION,i,t,e):new S(A.IDENTIFIER,i,t,e)}if(this.keywords.has(i))return"permit"===i||"allow"===i?new S(A.EFFECT,"permit",t,e):"deny"===i||"forbidden"===i?new S(A.EFFECT,"deny",t,e):new S("all"===i?A.ALL:"any"===i?A.ANY:"of"===i?A.OF:"if"===i?A.IF:"true"===i||"false"===i?A.BOOLEAN:"null"===i?A.NULL:"defined"===i?A.DEFINED:"except"===i?A.EXCEPT:"alias"===i?A.ALIAS:A.KEYWORD,i,t,e);const r=this.tokens[this.tokens.length-1];return new S(r?.type===A.EFFECT?A.PERMISSION:A.IDENTIFIER,i,t,e)}skipWhitespace(){for(;!this.isAtEnd()&&/\s/.test(this.peek());)this.advance()}isDigit(t){return t>="0"&&t<="9"}isAlpha(t){return/[a-zA-Z_]/.test(t)}isSymbol(t){return[".",":",",","[","]",">","<","=","!"].includes(t)}isNewline(){return"\n"===this.peek()}peek(){return this.input[this.pos]}advance(){const t=this.input[this.pos++];return"\n"===t?(this.line++,this.column=1):this.column++,t}isAtEnd(){return this.pos>=this.input.length}}class k extends Error{line;column;context;details;_formattedMessage;_originalStack;constructor(t,e,s,i){super(i.split("\n")[0]),this.line=t,this.column=e,this.context=s,this.details=i,this.name="AbilityDSLSyntaxError",Error.captureStackTrace&&Error.captureStackTrace(this,k),this._originalStack=this.stack,this._formattedMessage=this.formatMessage(),Object.defineProperty(this,"stack",{get:()=>this._formattedMessage,configurable:!0})}static supportsColor(){return"undefined"!=typeof process&&process.stdout?.isTTY}formatMessage(){const t=k.supportsColor(),e=t?"[1m":"",s=t?"[31m":"",i=t?"[33;1m":"",r=t?"[90m":"",n=t?"[0m":"",a=this.context.split("\n"),o=a.findIndex(t=>t.includes("^")||t.includes("~")),c=a.findIndex(t=>t.trim().includes("#")),h=a.map((t,a)=>a===o-1?`${e}${i}${t}${n}`:a===o?`${s}${t}${n}`:a===c?`${r}${t}${n}`:t).join("\n");return`${e}${s}${this.name}: ${this.details}${n}\n\n`+h}toString(){return this._formattedMessage}}class L{tokens;pos=0;dsl;marks=[];lastToken=null;next(){const t=this.tokens[this.pos++];return this.lastToken=t,t}prev(){if(0===this.pos)return null;const t=this.tokens[this.pos--];return this.lastToken=t,t}lookPrev(){return this.lastToken}constructor(t,e){this.tokens=t,this.dsl=e}peek(){return this.tokens[this.pos]}eof(){return this.peek().type===A.EOF}check(t){return!this.eof()&&this.peek().type===t}match(t){return this.check(t)?this.next():null}expect(t,e){const s=this.peek();if(s&&s.type===t)return this.next();this.syntaxError(e,s,[t])}expectOneOf(t,e){const s=this.peek();for(const e of t)if(s&&s.type===e)return this.next();this.syntaxError(e,s,t)}mark(){this.marks.push(this.pos)}reset(){const t=this.marks.pop();void 0!==t&&(this.pos=t)}commit(){this.marks.pop()}syntaxError(t,e,s){const i=this.dsl.split(/\r?\n/),r=e.line-1,n=r>0?i[r-1]:"",a=i[r],o=r+1<i.length?i[r+1]:"",c=" ".repeat(Math.max(0,e.column-1))+"~".repeat(e.value.length),h=String(e.line+1).length,l=t=>String(t).padStart(h," ");let u="";""!==n.trim()&&(u+=`${l(e.line-1)} | ${n}\n`),u+=`${l(e.line)} | ${a}\n`,u+=`${" ".repeat(h)} | ${c}\n`,""!==o.trim()&&(u+=`${l(e.line+1)} | ${o}`);let d=t;if(s&&s?.length>0){const i=e.value,r=this.suggest(i,s),n=`${t}\nDetails: Unexpected value token \`${i}\``;d=r?`${n} Did you mean \`${r}\`?`:n}throw new k(e.line,e.column,u+"\n",d)}suggest(t,e){const s=[];for(const t of e)s.push(t);const i=[...new Set(s)];let r=null,n=3;for(const e of i){const s=this.levenshteinDistance(t.toLowerCase(),e.toLowerCase());s<n&&(n=s,r=e)}return r}levenshteinDistance(t,e){const s=Array.from({length:e.length+1},()=>Array.from({length:t.length+1},()=>0));for(let e=0;e<=t.length;e++)s[0][e]=e;for(let t=0;t<=e.length;t++)s[t][0]=t;for(let i=1;i<=e.length;i++)for(let r=1;r<=t.length;r++){const n=t[r-1]===e[i-1]?0:1;s[i][r]=Math.min(s[i][r-1]+1,s[i-1][r]+1,s[i-1][r-1]+n)}return s[e.length][t.length]}}class O{store={id:void 0,name:void 0,priority:void 0,description:void 0,disabled:void 0,tags:void 0};get(t){return this.store[t]??null}set(t,e,s){return this.store[t]=null===e?void 0:{key:t,value:e,token:s},this}clear(){for(const t of Object.keys(this.store))this.store[t]=void 0}clone(){const t=new O;for(const e of Object.keys(this.store)){const s=this.store[e];t.store[e]=s?{...s}:void 0}return t}get id(){return this.get("id")}get name(){return this.get("name")}get description(){return this.get("description")}get priority(){return this.get("priority")}get disabled(){return this.get("disabled")}get tags(){return this.get("tags")}setID(t,e){return this.set("id",t,e)}setName(t,e){return this.set("name",t,e)}setDescription(t,e){return this.set("description",t,e)}setPriority(t,e){return this.set("priority",t,e)}setDisabled(t,e){return this.set("disabled",t,e)}setTags(t,e){return this.set("tags",t,e)}}const T={policy:new Set(["id","name","description","priority","disabled","tags"]),ruleSet:new Set(["id","name","description","disabled"]),rule:new Set(["id","name","disabled"]),alias:new Set(["name","disabled"])};class x{store=new Map;get(t){return this.store.get(t)||null}set(t,e){return this.store.set(t,e),this}has(t){return this.store.has(t)}}class w{dsl;stream;annBuffer=new O;aliasBuffer=new x;constructor(t){this.dsl=t}parse(){this.annBuffer.clear();const t=new b(this.dsl).tokenize();this.stream=new L(t,this.dsl);const e=[];for(;!this.stream.eof();){if(this.consumeLeadingComments(),this.consumeLeadingAnnotations(),this.consumeLeadingAliases(),!this.isStartOfPolicy()){const t=this.stream.peek();this.stream.syntaxError(`Expected policy, got ${t.type}.`,t,[A.EFFECT])}e.push(this.parsePolicy())}return e}parsePolicy(){this.consumeLeadingComments(),this.consumeLeadingAnnotations(),this.consumeLeadingAliases();const e=this.takeAnnotations("policy"),s=this.stream.expect(A.EFFECT,"Expected effect").value,i=this.stream.expect(A.PERMISSION,"Expected permission"),r=i.value;if(!r.startsWith("permission."))return this.stream.syntaxError(`Unexpected token. The permission key, must be starts with prefix \`permission.\`, but got \`${r}\`.\nDid you mean \`permission.${r}\`?`,i);this.stream.expect(A.IF,'Expected "if"');const n=this.stream.expectOneOf([A.ALL,A.ANY],'Expected "all" or "any"').type===A.ALL?t.and:t.or;this.stream.expect(A.COLON,'Expected ":"');const a=this.parseRuleSets(n);return new E({id:e.id?.value||null,name:e.name?.value||null,description:e.description?.value||null,priority:e.priority?.value||null,permission:r.replace(/^permission\./,""),effect:"permit"===s?p.permit:p.deny,disabled:e.disabled?.value??void 0,tags:e.tags?.value??void 0,compareMethod:n}).addRuleSets(a)}parseRuleSets(t){const e=[];for(this.consumeLeadingComments(),this.consumeLeadingAnnotations();!this.stream.eof()&&!this.isStartOfPolicy();){if(this.isStartOfExcept()){e.push(this.parseExceptGroup(t));continue}if(this.isStartOfGroup()){e.push(this.parseGroup());continue}const s=new v({compareMethod:t});for(;!(this.stream.eof()||(this.consumeLeadingComments(),this.consumeLeadingAnnotations(),this.isStartOfGroup()||this.isStartOfPolicy()||this.isStartOfExcept()));)this.stream.check(A.IDENTIFIER)||this.stream.check(A.ALWAYS)||this.stream.check(A.NEVER)?s.addRule(this.parseRule()):this.stream.syntaxError(`Unexpected token in implicit group: ${this.stream.peek().type}`,this.stream.peek());e.push(s)}return e}parseGroup(){this.consumeLeadingComments(),this.consumeLeadingAnnotations();const e=this.takeAnnotations("ruleSet"),s=this.stream.expectOneOf([A.ALL,A.ANY,A.ALWAYS,A.NEVER],'Expected "all" or "any" or "always" or "never"').type===A.ALL?t.and:t.or;this.stream.check(A.OF)&&this.stream.next(),this.stream.expect(A.COLON,'Expected ":"');const i=new v({id:e.id?.value||null,compareMethod:s,name:e.name?.value||null,description:e.description?.value||null,disabled:e.disabled?.value??void 0});for(;!(this.stream.eof()||(this.consumeLeadingComments(),this.consumeLeadingAnnotations(),this.isStartOfExcept())||this.isStartOfGroup()||this.isStartOfPolicy());)this.stream.check(A.IDENTIFIER)?i.addRule(this.parseRule()):this.stream.syntaxError(`Unexpected token in group: ${this.stream.peek().type}`,this.stream.peek());return i}parseExceptGroup(e){this.consumeLeadingComments(),this.consumeLeadingAnnotations();const s=this.takeAnnotations("ruleSet");this.stream.expect(A.EXCEPT,'Expected "except"');let i=e;this.stream.check(A.ALL)||this.stream.check(A.ANY)?(i=this.stream.next().type===A.ALL?t.and:t.or,this.stream.check(A.OF)&&this.stream.next(),this.stream.expect(A.COLON,'Expected ":" after except group')):this.stream.expect(A.COLON,'Expected ":" after "except"');const r=new v({id:s.id?.value||null,compareMethod:i,name:s.name?.value||null,description:s.description?.value||null,isExcept:!0,disabled:s.disabled?.value??void 0});for(;!(this.stream.eof()||(this.consumeLeadingComments(),this.consumeLeadingAnnotations(),this.isStartOfGroup()||this.isStartOfPolicy()||this.isStartOfExcept()));)this.stream.check(A.IDENTIFIER)?r.addRule(this.parseRule()):this.stream.syntaxError(`Unexpected token in except group: ${this.stream.peek().type}`,this.stream.peek());return r}parseRule(){this.consumeLeadingComments(),this.consumeLeadingAnnotations();const t=this.takeAnnotations("rule"),e=this.stream.check(A.ALWAYS)||this.stream.check(A.NEVER);e||this.stream.check(A.IDENTIFIER)||this.stream.syntaxError(`Expected identifier, but got ${this.stream.peek().type}`,this.stream.peek());const s=e?"":this.stream.expect(A.IDENTIFIER,"Expected field").value;if(this.aliasBuffer.has(s))return this.aliasBuffer.get(s);const{condition:i,operator:r}=this.parseConditionOperator();let n=null,a=null;return r!==A.EQ_NULL&&r!==A.NOT_EQ_NULL&&r!==A.NULL&&r!==A.ALWAYS&&r!==A.NEVER&&r!==A.DEFINED&&(this.stream.mark(),n=this.parseValue(),a=this.stream.lookPrev(),this.stream.commit()),this.consumeLeadingComments(),this.consumeLeadingAnnotations(),this.consumeLeadingAliases(),"string"==typeof n&&a&&a.type===A.IDENTIFIER&&!a.value.includes(".")&&this.stream.syntaxError(`Expected comparison operator or value, got \`${n}\``,a,[A.KEYWORD]),new _({id:t.id?.value||null,subject:s,resource:n,condition:i,name:t.name?.value||null,description:t.description?.value||null,disabled:t.disabled?.value??void 0})}parseConditionOperator(){if(this.stream.mark(),this.matchWord("always"))return this.stream.commit(),{condition:i.always,operator:A.ALWAYS};if(this.stream.reset(),this.stream.mark(),this.matchWord("never"))return this.stream.commit(),{condition:i.never,operator:A.NEVER};if(this.stream.reset(),this.stream.mark(),(this.matchWord("length")||this.matchWord("len"))&&this.matchWord("equals"))return this.stream.commit(),{condition:i.length_equals,operator:A.LEN_EQ};if(this.stream.reset(),this.stream.mark(),(this.matchWord("length")||this.matchWord("len"))&&this.matchSymbol("="))return this.stream.commit(),{condition:i.length_equals,operator:A.LEN_EQ};if(this.stream.reset(),this.stream.mark(),(this.matchWord("length")||this.matchWord("len"))&&this.matchWord("greater")&&this.matchWord("than"))return this.stream.commit(),{condition:i.length_greater_than,operator:A.LEN_GT};if(this.stream.reset(),this.stream.mark(),(this.matchWord("length")||this.matchWord("len"))&&this.matchSymbol(">"))return this.stream.commit(),{condition:i.length_greater_than,operator:A.LEN_GT};if(this.stream.reset(),this.stream.mark(),(this.matchWord("length")||this.matchWord("len"))&&this.matchWord("less")&&this.matchWord("than"))return this.stream.commit(),{condition:i.length_less_than,operator:A.LEN_LT};if(this.stream.reset(),this.stream.mark(),(this.matchWord("length")||this.matchWord("len"))&&this.matchSymbol("<"))return this.stream.commit(),{condition:i.length_less_than,operator:A.LEN_LT};if(this.stream.reset(),this.stream.mark(),this.matchWord("greater")&&this.matchWord("than")&&this.matchWord("or")&&this.matchWord("equal"))return this.stream.commit(),{condition:i.greater_or_equal,operator:A.GTE};if(this.stream.reset(),this.stream.mark(),this.matchWord("greater")&&this.matchWord("than"))return this.stream.commit(),{condition:i.greater_than,operator:A.GT};if(this.stream.reset(),this.stream.mark(),this.matchWord("less")&&this.matchWord("than")&&this.matchWord("or")&&this.matchWord("equal"))return this.stream.commit(),{condition:i.less_or_equal,operator:A.LTE};if(this.stream.reset(),this.matchWord("less")&&this.matchWord("than"))return{condition:i.less_than,operator:A.LT};if(this.stream.reset(),this.stream.mark(),this.matchWord("not")&&this.matchWord("contains"))return this.stream.commit(),{condition:i.not_contains,operator:A.NOT_CONTAINS};if(this.stream.reset(),this.stream.mark(),this.matchWord("not")&&this.matchWord("includes"))return this.stream.commit(),{condition:i.not_contains,operator:A.NOT_CONTAINS};if(this.stream.reset(),this.stream.mark(),this.matchWord("not")&&this.matchWord("has"))return this.stream.commit(),{condition:i.not_contains,operator:A.NOT_CONTAINS};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("equals"))return this.stream.commit(),{condition:i.equals,operator:A.EQ};if(this.stream.reset(),this.stream.mark(),this.matchWord("not")&&this.matchWord("equals"))return this.stream.commit(),{condition:i.not_equals,operator:A.NOT_EQ};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("not")&&this.matchWord("equals"))return this.stream.commit(),{condition:i.not_equals,operator:A.NOT_EQ};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("in"))return this.stream.commit(),{condition:i.in,operator:A.IN};if(this.stream.reset(),this.stream.mark(),this.matchWord("not")&&this.matchWord("in"))return this.stream.commit(),{condition:i.not_in,operator:A.NOT_IN};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("not")&&this.stream.check(A.NULL))return this.stream.next(),this.stream.commit(),{condition:i.not_equals,operator:A.NOT_EQ_NULL};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("null")&&this.stream.check(A.NULL))return this.stream.commit(),this.stream.next(),{condition:i.equals,operator:A.EQ_NULL};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("defined"))return this.stream.commit(),{condition:i.defined,operator:A.DEFINED};if(this.stream.reset(),this.stream.mark(),this.matchWord("is")&&this.matchWord("not")&&this.matchWord("defined"))return this.stream.commit(),{condition:i.not_defined,operator:A.DEFINED};this.stream.reset();const t=this.stream.peek();switch(t.type!==A.SYMBOL&&t.type!==A.KEYWORD&&t.type!==A.NULL&&this.stream.syntaxError(`Expected comparison operator, got \`${t.value}\``,t,[A.SYMBOL,A.KEYWORD,A.NULL]),this.stream.next(),t.type){case A.SYMBOL:if("="===t.value||"=="===t.value)return{condition:i.equals,operator:A.EQ};if("!="===t.value||"<>"===t.value)return{condition:i.not_equals,operator:A.NOT_EQ};if(">"===t.value)return{condition:i.greater_than,operator:A.GT};if("<"===t.value)return{condition:i.less_than,operator:A.LT};if(">="===t.value)return{condition:i.greater_or_equal,operator:A.GTE};if("<="===t.value)return{condition:i.less_or_equal,operator:A.LTE};break;case A.KEYWORD:if("contains"===t.value||"includes"===t.value||"has"===t.value)return{condition:i.contains,operator:A.CONTAINS};if("in"===t.value)return{condition:i.in,operator:A.IN};if("equals"===t.value)return{condition:i.equals,operator:A.EQ};if("gte"===t.value)return{condition:i.greater_or_equal,operator:A.GTE};if("greater"===t.value||"gt"===t.value)return{condition:i.greater_than,operator:A.GT};if("less"===t.value||"lt"===t.value)return{condition:i.less_than,operator:A.LT};if("lte"===t.value)return{condition:i.less_or_equal,operator:A.LTE};if("is"===t.value)return{condition:i.equals,operator:A.EQ}}return this.stream.syntaxError(`Unexpected operator token \`${t.value}\``,t,[A.SYMBOL,A.KEYWORD])}matchWord(t){if(this.stream.eof())return!1;const e=this.stream.peek();return(e.type===A.KEYWORD||e.type===A.IDENTIFIER||e.type===A.ALWAYS||e.type===A.NEVER||e.type===A.DEFINED)&&e.value===t&&(this.stream.next(),!0)}matchSymbol(t){if(this.stream.eof())return!1;const e=this.stream.peek();return e.type===A.SYMBOL&&e.value===t&&(this.stream.next(),!0)}parseValue(){if(this.stream.check(A.LBRACKET))return this.stream.next(),this.parseArray();const t=this.stream.peek();switch(t.type!==A.ALL&&t.type!==A.ANY&&t.type!==A.EFFECT||this.stream.syntaxError(`Unexpected ${t.type} in value position`,t),this.stream.next(),t.type){case A.STRING:return t.value;case A.NUMBER:return Number(t.value);case A.BOOLEAN:return"true"===t.value;case A.NULL:return null;case A.DEFINED:return void 0!==t.value;case A.IDENTIFIER:return t.value;default:this.stream.syntaxError(`Unexpected value token "${t.value}"`,t,[A.KEYWORD])}}parseArray(){const t=[];if(this.stream.check(A.RBRACKET))return this.stream.next(),t;for(;!this.stream.eof()&&!this.stream.check(A.RBRACKET);){const e=this.parseValue();Array.isArray(e)?t.push(...e):"string"==typeof e||"number"==typeof e||"boolean"==typeof e?t.push(e):null===e&&this.stream.syntaxError("Unexpected null in array",this.stream.peek()),this.stream.check(A.COMMA)&&this.stream.next()}return this.stream.expect(A.RBRACKET,'Expected "]"'),t}consumeLeadingComments(){for(;this.stream.check(A.COMMENT);)this.stream.next()}consumeLeadingAliases(){for(;this.stream.check(A.ALIAS);){this.stream.next();const t=this.stream.expect(A.IDENTIFIER,"Expected alias name").value;this.stream.expect(A.COLON,"Expected colon after an alias");const e=this.takeAnnotations("alias");for(;!this.stream.eof()&&!this.isStartOfAlias()&&!this.isStartOfPolicy();){const s=this.parseRule();s.name=e.get("name")?.value||t,s.description=e.get("description")?.value,!0===e.get("disabled")?.value&&(s.disabled=!0),this.aliasBuffer.set(t,s)}}}consumeLeadingAnnotations(){for(;this.stream.check(A.ANNOTATION);){const t=this.stream.next(),e=t.value.trim();if(e.startsWith("@id ")&&this.annBuffer.setID(e.slice(4).trim(),t),e.startsWith("@name ")&&this.annBuffer.setName(e.slice(6).trim(),t),e.startsWith("@description ")&&this.annBuffer.setDescription(e.slice(13).trim(),t),e.startsWith("@priority ")&&this.annBuffer.setPriority(parseInt(e.slice(10).trim(),10),t),e.startsWith("@disabled")){const s=e.slice(9).trim();this.annBuffer.setDisabled(0===s.length||"true"===e.slice(9).trim(),t)}if(e.startsWith("@tags ")){const s=e.slice(6).trim().split(",").map(t=>t.trim());this.annBuffer.setTags(s,t)}}}takeAnnotations(t){const e=this.annBuffer.clone();this.annBuffer.clear();const s=T[t];for(const i of Object.keys(e.store)){const r=e.get(i);r&&(s.has(i)||this.stream.syntaxError(`Annotation @${i} is not allowed on ${t}. Allowed: ${[...s].map(t=>"@"+t).join(", ")}`,r.token??this.stream.peek()))}return e}isStartOfPolicy(){return this.stream.check(A.EFFECT)}isStartOfGroup(){return this.stream.check(A.ALL)||this.stream.check(A.ANY)}isStartOfRule(){return this.stream.check(A.IDENTIFIER)||this.stream.check(A.ALWAYS)||this.stream.check(A.NEVER)}isStartOfExcept(){return this.stream.check(A.EXCEPT)}isStartOfAlias(){return this.stream.check(A.ALIAS)}}function $(t,...e){const s=t.reduce((t,s,i)=>t+s+(e[i]??""),"");return new w(s).parse()}class I{policies;matched;constructor(t){this.policies=t,this.matched=t.filter(t=>t.matchState===c.match)}matchedPolicies(){return this.matched}hasMatched(){return this.matched.length>0}firstMatched(){return this.matchedPolicies()[0]??null}lastMatched(){const t=this.matchedPolicies();return t.length>0?t[t.length-1]:null}firstDenied(){return this.getDenyPolicies()[0]??null}firstPermitted(){return this.getPermitPolicies()[0]??null}getPermitPolicies(){return this.matched.filter(t=>t.effect===p.permit)}getDenyPolicies(){return this.matched.filter(t=>t.effect===p.deny)}hasPermit(){return this.getPermitPolicies().length>0}hasDeny(){return this.getDenyPolicies().length>0}isAllowed(){return this.evaluate()===p.permit}isDenied(){return this.evaluate()===p.deny}}class W extends I{_decisive=null;evaluate(){if(!this.hasMatched())return this._decisive=null,p.deny;const t=this.firstDenied();return t?(this._decisive=t,p.deny):(this._decisive=this.firstPermitted(),p.permit)}decisivePolicy(){return this._decisive}}class M extends I{_decisive=null;evaluate(){const t=this.firstPermitted();return t?(this._decisive=t,p.permit):(this._decisive=null,p.deny)}decisivePolicy(){return this._decisive}}class R extends I{_decisive=null;evaluate(){const t=this.firstDenied();if(t)return this._decisive=t,p.deny;const e=this.firstPermitted();return e?(this._decisive=e,p.permit):(this._decisive=null,p.deny)}decisivePolicy(){return this._decisive}}class D extends I{_decisive=null;evaluate(){const t=this.firstMatched();return t?(this._decisive=t,t.effect):(this._decisive=null,p.deny)}decisivePolicy(){return this._decisive}}class P extends I{_decisive=null;evaluate(){const t=this.matchedPolicies();return 1===t.length?(this._decisive=t[0],t[0].effect):(this._decisive=null,p.deny)}decisivePolicy(){return this._decisive}}class C extends I{_decisive=null;evaluate(){const t=this.matchedPolicies().find(t=>t.effect===p.permit);if(t)return this._decisive=t,p.permit;const e=this.matchedPolicies().find(t=>t.effect===p.deny);return e?(this._decisive=e,p.deny):(this._decisive=null,p.deny)}decisivePolicy(){return this._decisive}}class j extends I{_decisive=null;evaluate(){const t=this.lastMatched();return t?(this._decisive=t,t.effect):(this._decisive=null,p.deny)}decisivePolicy(){return this._decisive}}class q extends I{_decisive=null;evaluate(){const t=this.matchedPolicies();if(0===t.length)return this._decisive=null,p.deny;const e=[...t].sort((t,e)=>e.priority-t.priority)[0];return this._decisive=e,e.effect}decisivePolicy(){return this._decisive}}export{t as AbilityCompare,i as AbilityCondition,b as AbilityDSLLexer,w as AbilityDSLParser,S as AbilityDSLToken,e as AbilityError,h as AbilityExplain,d as AbilityExplainPolicy,l as AbilityExplainRule,u as AbilityExplainRuleSet,N as AbilityJSONParser,c as AbilityMatch,s as AbilityParserError,E as AbilityPolicy,p as AbilityPolicyEffect,f as AbilityResolver,m as AbilityResult,_ as AbilityRule,v as AbilityRuleSet,I as AbilityStrategy,y as AbilityTypeGenerator,W as AllMustPermitStrategy,M as AnyPermitStrategy,R as DenyOverridesStrategy,D as FirstMatchStrategy,P as OnlyOneApplicableStrategy,C as PermitOverridesStrategy,q as PriorityStrategy,j as SequentialLastMatchStrategy,A as TokenTypes,$ as ability,r as fromLiteral,a as isConditionEqual,o as isConditionNotEqual,n as toLiteral};
|