@erpg/dicecore 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +9 -0
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +9 -0
- package/dist/v3/cache.d.cts +23 -0
- package/dist/v3/cache.d.ts +23 -0
- package/dist/v3/compiler.d.cts +50 -0
- package/dist/v3/compiler.d.ts +50 -0
- package/dist/v3/engine.d.cts +7 -0
- package/dist/v3/engine.d.ts +7 -0
- package/dist/v3/errors.d.cts +37 -0
- package/dist/v3/errors.d.ts +37 -0
- package/dist/v3/executor.d.cts +11 -0
- package/dist/v3/executor.d.ts +11 -0
- package/dist/v3/freeze.d.cts +5 -0
- package/dist/v3/freeze.d.ts +5 -0
- package/dist/v3/index.d.cts +8 -0
- package/dist/v3/index.d.ts +8 -0
- package/dist/v3/math.d.cts +12 -0
- package/dist/v3/math.d.ts +12 -0
- package/dist/v3/normalization.d.cts +10 -0
- package/dist/v3/normalization.d.ts +10 -0
- package/dist/v3/roll-count-expression.d.cts +2 -0
- package/dist/v3/roll-count-expression.d.ts +2 -0
- package/dist/v3/runtime/budget.d.cts +57 -0
- package/dist/v3/runtime/budget.d.ts +57 -0
- package/dist/v3/runtime/context.d.cts +27 -0
- package/dist/v3/runtime/context.d.ts +27 -0
- package/dist/v3/runtime/index.d.cts +7 -0
- package/dist/v3/runtime/index.d.ts +7 -0
- package/dist/v3/runtime/journal.d.cts +23 -0
- package/dist/v3/runtime/journal.d.ts +23 -0
- package/dist/v3/runtime/limits.d.cts +25 -0
- package/dist/v3/runtime/limits.d.ts +25 -0
- package/dist/v3/runtime/mt19937.d.cts +23 -0
- package/dist/v3/runtime/mt19937.d.ts +23 -0
- package/dist/v3/runtime/replay.d.cts +38 -0
- package/dist/v3/runtime/replay.d.ts +38 -0
- package/dist/v3/runtime/xoshiro128ss.d.cts +14 -0
- package/dist/v3/runtime/xoshiro128ss.d.ts +14 -0
- package/dist/v3/syntax/ast.d.cts +132 -0
- package/dist/v3/syntax/ast.d.ts +132 -0
- package/dist/v3/syntax/index.d.cts +4 -0
- package/dist/v3/syntax/index.d.ts +4 -0
- package/dist/v3/syntax/parser.d.cts +7 -0
- package/dist/v3/syntax/parser.d.ts +7 -0
- package/dist/v3/syntax/scanner.d.cts +3 -0
- package/dist/v3/syntax/scanner.d.ts +3 -0
- package/dist/v3/syntax/tokens.d.cts +38 -0
- package/dist/v3/syntax/tokens.d.ts +38 -0
- package/dist/v3/types.d.cts +251 -0
- package/dist/v3/types.d.ts +251 -0
- package/licence.txt +23 -0
- package/package.json +105 -0
- package/readme.md +255 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* @erpg/dicecore - ERPG dice core with ergonomic RPG notation, grouped rolls, structured UI data, deterministic replay, and safe parse-only inspection.
|
|
3
|
+
*
|
|
4
|
+
* @version 3.1.0
|
|
5
|
+
* @license MIT
|
|
6
|
+
* @author Arkanus
|
|
7
|
+
* @link https://github.com/arkanus-app/rpg-dice-roller
|
|
8
|
+
*/
|
|
9
|
+
"use strict";class e{maxEntries;maxWeight;entries=new Map;currentWeight=0;hitCount=0;missCount=0;evictionCount=0;constructor(e,t){this.maxEntries=e,this.maxWeight=t}get(e){const t=this.entries.get(e);if(void 0!==t)return this.hitCount+=1,this.entries.delete(e),this.entries.set(e,t),t.value;this.missCount+=1}set(e,t,n=1){const i=this.entries.get(e);void 0!==i&&(this.entries.delete(e),this.currentWeight-=i.weight),0===this.maxEntries||0===this.maxWeight||n>this.maxWeight||(this.entries.set(e,{value:t,weight:n}),this.currentWeight+=n,this.evictOverflow())}clear(){this.entries.clear(),this.currentWeight=0,this.hitCount=0,this.missCount=0,this.evictionCount=0}stats(){return{entries:this.entries.size,weight:this.currentWeight,hits:this.hitCount,misses:this.missCount,evictions:this.evictionCount}}evictOverflow(){for(;this.entries.size>this.maxEntries||this.currentWeight>this.maxWeight;){const e=this.entries.entries().next().value;if(void 0===e)return;const[t,n]=e;this.entries.delete(t),this.currentWeight-=n.weight,this.evictionCount+=1}}}const t=new Set(["DICE_NOTATION_REQUIRED","INPUT_TOO_LONG","AST_TOO_DEEP","TOO_MANY_NODES","TOO_MANY_ROLLS","TOO_MANY_INITIAL_DICE","GENERATED_DICE_LIMIT_EXCEEDED","RANDOM_BUDGET_EXCEEDED","EVENT_LIMIT_EXCEEDED","MODIFIER_STEP_LIMIT_EXCEEDED","RESOLVED_GROUP_LIMIT_EXCEEDED","RESULT_LIMIT_EXCEEDED","OUTPUT_LIMIT_EXCEEDED","DICE_SIDES_LIMIT_EXCEEDED","INVALID_NOTATION","UNSUPPORTED_NOTATION","UNSUPPORTED_GROUP_MODIFIER","NON_TERMINATING_MODIFIER","IMPOSSIBLE_UNIQUE","ROLL_EXECUTION_LIMIT","RNG_UNAVAILABLE","INVALID_SEED","INVALID_REPLAY","REPLAY_PLAN_MISMATCH","INVALID_LIMIT","UNSUPPORTED_REPLAY_VERSION","NON_FINITE_RESULT","INVALID_ERROR_DATA"]);function n(e){if("object"!=typeof e||null===e)return!1;try{return!Array.isArray(e)}catch{return!1}}function i(e,t){if(null===e||"string"==typeof e||"boolean"==typeof e)return!0;if("number"==typeof e)return Number.isFinite(e);if("object"!=typeof e)return!1;if(t.has(e))return!1;const n=new Set(t);n.add(e);try{return Array.isArray(e)?e.every(e=>i(e,n)):Object.keys(e).every(t=>i(e[t],n))}catch{return!1}}function r(e){return n(e)&&i(e,new Set)}class s extends Error{code;span;input;details;constructor(e,t){super(e),this.name="DiceRollError",this.code=t.code,this.span=t.span??null,this.input=t.input??"",this.details=t.details??{}}static fromJSON(e){if(!a(e))throw new s("Value is not valid serialized dice error data",{code:"INVALID_ERROR_DATA"});return new s(e.message,{code:e.code,span:e.span,input:e.input,details:e.details})}toJSON(){return{name:"DiceRollError",code:this.code,message:this.message,span:this.span,input:this.input,details:this.details}}}function o(e){return e instanceof s}function a(e){if(!n(e))return!1;try{return"DiceRollError"===e.name&&"string"==typeof e.code&&t.has(e.code)&&"string"==typeof e.message&&(null===e.span||function(e){if(!n(e))return!1;try{return Number.isSafeInteger(e.start)&&Number.isSafeInteger(e.end)&&"number"==typeof e.start&&"number"==typeof e.end&&e.start>=0&&e.end>=e.start}catch{return!1}}(e.span))&&"string"==typeof e.input&&r(e.details)}catch{return!1}}function u(e){Object.freeze(e.states),Object.freeze(e)}function c(e){"transform"===e.type&&"group"===e.subject&&(Object.freeze(e.from),Object.freeze(e.to)),Object.freeze(e)}function l(e){Object.freeze(e.span),Object.freeze(e.states),Object.freeze(e.childIds),Object.freeze(e)}function d(e){null!==e&&Object.freeze(e)}function p(e){Object.freeze(e.diceRange),Object.freeze(e.groupRange),Object.freeze(e.eventRange),d(e.pool),Object.freeze(e)}function m(e){d(e.pool),Object.freeze(e)}function h(e){Object.freeze(e.span),Object.freeze(e.childIds),Object.freeze(e)}function f(e){if("always"===e)return!0;if("never"===e)return!1;const t=globalThis;return"development"===t.process?.env?.NODE_ENV}const g="decimal12-v1";function I(e,t){if(!Number.isFinite(e))throw new s("Dice expression produced a non-finite result",{code:"NON_FINITE_RESULT",input:t,details:{value:String(e)}});return Object.is(e,-0)?0:e}function x(e,t){const n=I(e,t);return I(Number.isSafeInteger(n)?n:Number(n.toPrecision(12)),t)}function v(e,t,n,i){let r;switch(e){case"+":r=t+n;break;case"-":r=t-n;break;case"*":r=t*n;break;case"/":r=t/n;break;case"%":r=t%n;break;case"^":r=t**n}return x(r,i)}function b(e,t,n){let i;switch(e){case"abs":i=Math.abs(t);break;case"ceil":i=Math.ceil(t);break;case"cos":i=Math.cos(t);break;case"exp":i=Math.exp(t);break;case"floor":i=Math.floor(t);break;case"log":i=Math.log(t);break;case"round":i=Math.round(t);break;case"sign":i=Math.sign(t);break;case"sin":i=Math.sin(t);break;case"sqrt":i=Math.sqrt(t);break;case"tan":i=Math.tan(t)}return x(i,n)}function N(e,t,n,i){let r;switch(e){case"max":r=Math.max(t,n);break;case"min":r=Math.min(t,n);break;case"pow":r=Math.pow(t,n)}return x(r,i)}function D(e){const t=Number(x(e,"").toFixed(2));return Object.is(t,-0)?0:t}function E(e,t){return`${e}@${t.start}:${t.end}`}const w=["floor","round","sqrt","ceil","sign","abs","cos","exp","log","sin","tan","pow","max","min","dF","cs","cf"],A=Object.freeze({"(":"left-parenthesis",")":"right-parenthesis","{":"left-brace","}":"right-brace",",":"comma",".":"dot","!":"bang"});function O(e,t){return{start:e,end:t}}function S(e,t,n,i){throw new s(t,{code:"INVALID_NOTATION",span:n,input:e,details:i})}function y(e){return void 0!==e&&e>="0"&&e<="9"}function R(e){if(void 0===e)return!1;const t=e.charCodeAt(0);return 9===t||10===t||11===t||12===t||13===t||32===t||160===t||5760===t||t>=8192&&t<=8202||8232===t||8233===t||8239===t||8287===t||12288===t||65279===t}function k(e){if(void 0===e)return!1;const t=e.charCodeAt(0);return t>=65&&t<=90||t>=97&&t<=122}function _(e){return"+"===e||"-"===e||"*"===e||"/"===e||"%"===e||"^"===e}function L(e,t){let n=t;for(;y(e[n]);)n+=1;if("."===e[n]&&y(e[n+1]))for(n+=1;y(e[n]);)n+=1;const i=e.slice(t,n),r=Number(i);return Number.isFinite(r)?{kind:"number",lexeme:i,value:r,span:O(t,n)}:S(e,`Numeric literal is not finite at offset ${t}`,O(t,n),{found:i})}function T(e,t){const n=w.find(n=>e.startsWith(n,t));if(void 0!==n)return{kind:"identifier",lexeme:n,value:n,span:O(t,t+n.length)};const i=e[t];return void 0!==i&&"dkrusfpolha".includes(i)?{kind:"identifier",lexeme:i,value:i,span:O(t,t+1)}:S(e,`Unexpected identifier at offset ${t}`,O(t,t+1),{found:i??""})}function M(e,t,n){const i=O(n,n+t.length);switch(e){case"left-parenthesis":case"right-parenthesis":case"left-brace":case"right-brace":case"comma":case"dot":case"bang":return{kind:e,lexeme:t,span:i};default:throw new Error("Invalid punctuation token kind")}}const C=["abs","ceil","cos","exp","floor","log","round","sign","sin","sqrt","tan"],j=["pow","max","min"],z={"+":10,"-":10,"*":20,"/":20,"%":20,"^":30,"**":30},P=Object.freeze({maxDepth:Number.MAX_SAFE_INTEGER,maxNodes:Number.MAX_SAFE_INTEGER});function U(e){return C.some(t=>t===e)}function V(e){return j.some(t=>t===e)}function F(e,t){return{start:e.start,end:t.end}}class ${input;tokens;cursor=0;recursionDepth=0;limits;constructor(e,t){this.input=e,this.limits=t,this.tokens=function(e){const t=[];let n=0;for(;n<e.length;){const i=e[n];if(R(i))n+=1;else if(y(i)){const i=L(e,n);t.push(i),n=i.span.end}else if(k(i)){const i=T(e,n);t.push(i),n=i.span.end}else if(e.startsWith("**",n))t.push({kind:"operator",lexeme:"**",value:"**",span:O(n,n+2)}),n+=2;else if(e.startsWith("<=",n)||e.startsWith(">=",n)||e.startsWith("<>",n)){const i=e.slice(n,n+2);"<="!==i&&">="!==i&&"<>"!==i||t.push({kind:"comparison",lexeme:i,value:i,span:O(n,n+2)}),n+=2}else if(_(i))t.push({kind:"operator",lexeme:i,value:i,span:O(n,n+1)}),n+=1;else if("="===i||"<"===i||">"===i)t.push({kind:"comparison",lexeme:i,value:i,span:O(n,n+1)}),n+=1;else{const r=void 0===i?void 0:A[i];if(void 0===r)return S(e,`Unexpected character at offset ${n}`,O(n,n+1),{found:i??""});t.push(M(r,i??"",n)),n+=1}}return t.push({kind:"eof",lexeme:"",span:O(e.length,e.length)}),t}(e)}parse(){if(0===this.input.length)return this.fail("Dice notation is required",this.current().span,{});const e=this.parseExpression(0),t=this.current();return"eof"!==t.kind?this.fail(`Unexpected token "${t.lexeme}" at offset ${t.span.start}`,t.span,{found:t.lexeme,expected:"end of notation"}):(this.assertTreeLimits(e),e)}current(e=0){const t=this.cursor+e,n=this.tokens[t];return void 0!==n?n:{kind:"eof",lexeme:"",span:{start:this.input.length,end:this.input.length}}}consume(){const e=this.current();return"eof"!==e.kind&&(this.cursor+=1),e}fail(e,t,n){throw new s(e,{code:"INVALID_NOTATION",span:t,input:this.input,details:n})}failLimit(e,t,n,i){throw new s("AST_TOO_DEEP"===e?"AST depth exceeds the parser limit":"AST node count exceeds the parser limit",{code:e,span:i,input:this.input,details:{limit:t,actual:n}})}enterExpression(){this.recursionDepth+=1,this.recursionDepth>this.limits.maxDepth&&this.failLimit("AST_TOO_DEEP",this.limits.maxDepth,this.recursionDepth,this.current().span)}leaveExpression(){this.recursionDepth-=1}countedChildren(e){switch(e.kind){case"number":case"compare-point":case"drop":case"keep":case"min":case"max":case"sort":return[];case"unary":return[e.operand];case"binary":return[e.left,e.right];case"parenthesized":return[e.expression];case"function":return e.arguments;case"dice":return"standard"===e.diceKind?[e.quantity,e.sides,...e.modifiers]:[e.quantity,...e.modifiers];case"group":return[...e.expressions,...e.modifiers];case"explode":case"reroll":case"unique":case"critical-success":case"critical-failure":return null===e.compare?[]:[e.compare];case"target":return null===e.failure?[e.success]:[e.success,e.failure]}}assertTreeLimits(e){const t=[{node:e,depth:1}];let n=0;for(;t.length>0;){const e=t.pop();if(void 0===e)break;n+=1,n>this.limits.maxNodes&&this.failLimit("TOO_MANY_NODES",this.limits.maxNodes,n,e.node.span),e.depth>this.limits.maxDepth&&this.failLimit("AST_TOO_DEEP",this.limits.maxDepth,e.depth,e.node.span);const i=this.countedChildren(e.node);for(let n=i.length-1;n>=0;n-=1){const r=i[n];void 0!==r&&t.push({node:r,depth:e.depth+1})}}}expect(e,t){const n=this.current();return n.kind!==e?this.fail(`Expected ${t} at offset ${n.span.start}`,n.span,{found:n.lexeme,expected:t}):this.consume()}isIdentifier(e,t=0){const n=this.current(t);return"identifier"===n.kind&&n.value===e}parseExpression(e){this.enterExpression();try{let t=this.parsePrefix();for(;;){const n=this.current();if("operator"!==n.kind)break;const i=z[n.value];if(i<e)break;this.consume();const r="^"===n.value||"**"===n.value,s=this.parseExpression(r?i:i+1),o=F(t.span,s.span);t={kind:"binary",id:E("binary",o),span:o,operator:n.value,left:t,right:s}}return t}finally{this.leaveExpression()}}parsePrefix(){const e=this.current();if("operator"===e.kind&&("+"===e.value||"-"===e.value)){const t=e.value;this.consume();const n=this.parseExpression(25),i=F(e.span,n.span);return{kind:"unary",id:E("unary",i),span:i,operator:t,operand:n}}return this.parsePrimary()}parsePrimary(){const e=this.current();if("number"===e.kind)return this.parseDiceSuffix(this.parseNumber(null));if("left-parenthesis"===e.kind)return this.parseDiceSuffix(this.parseParenthesized());if("left-brace"===e.kind)return this.parseGroup();if("identifier"===e.kind){if("d"===e.value||"dF"===e.value)return this.parseDice(null);if(U(e.value)||V(e.value))return this.parseFunction()}return this.fail(`Expected an expression at offset ${e.span.start}`,e.span,{found:e.lexeme,expected:"number, dice, group, parenthesis, or function"})}parseNumber(e){const t=null===e?null:this.tokens[this.cursor-1],n=this.expect("number","a number");if("number"!==n.kind)return this.fail("Internal number token mismatch",n.span,{});const i=null==t?n.span:F(t.span,n.span),r="-"===e?-1:1,s=null===e?n.lexeme:`${e}${n.lexeme}`;return{kind:"number",id:E("number",i),span:i,value:r*n.value,raw:s,implicit:!1}}implicitOne(e){const t={start:e,end:e};return{kind:"number",id:E("implicit-number",t),span:t,value:1,raw:"1",implicit:!0}}parseParenthesized(){const e=this.expect("left-parenthesis",'"("'),t=this.parseExpression(0),n=this.expect("right-parenthesis",'")"'),i=F(e.span,n.span);return{kind:"parenthesized",id:E("parenthesized",i),span:i,expression:t}}parseDiceSuffix(e){return this.isIdentifier("d")||this.isIdentifier("dF")?(this.validateDiceArgument(e,"quantity"),this.parseDice(e)):e}validateDiceArgument(e,t){"number"===e.kind&&(!Number.isInteger(e.value)||e.value<1||e.raw.length>1&&e.raw.startsWith("0"))&&this.fail(`Dice ${t} must be a positive integer`,e.span,{value:e.value,argument:t})}parseDice(e){const t=this.consume();if("identifier"!==t.kind||"d"!==t.value&&"dF"!==t.value)return this.fail("Expected a dice marker",t.span,{found:t.lexeme});const n=e??this.implicitOne(t.span.start),i=e?.span??t.span;if("dF"===t.value){let e=2,r=t.span;if("dot"===this.current().kind){this.consume();const t=this.expect("number","Fudge variant 1 or 2");if("number"!==t.kind||1!==t.value&&2!==t.value||1!==t.lexeme.length)return this.fail("Fudge dice variant must be 1 or 2",t.span,{found:t.lexeme});e=t.value,r=t.span}const s=this.parseModifiers(),o=F(i,0===s.length?r:s[s.length-1]?.span??r);return{kind:"dice",diceKind:"fudge",id:E("dice",o),span:o,quantity:n,variant:e,modifiers:s}}const r=this.current();if("operator"===r.kind&&"%"===r.value){this.consume();const e=this.parseModifiers(),t=F(i,0===e.length?r.span:e[e.length-1]?.span??r.span);return{kind:"dice",diceKind:"percentile",id:E("dice",t),span:t,quantity:n,modifiers:e}}const s="left-parenthesis"===r.kind?this.parseParenthesized():this.parseNumber(null);this.validateDiceArgument(s,"sides");const o=this.parseModifiers(),a=F(i,0===o.length?s.span:o[o.length-1]?.span??s.span);return{kind:"dice",diceKind:"standard",id:E("dice",a),span:a,quantity:n,sides:s,modifiers:o}}parseFunction(){const e=this.consume();if("identifier"!==e.kind)return this.fail("Expected a function name",e.span,{});this.expect("left-parenthesis",'"("');const t=this.parseExpression(0);if(U(e.value)){const n=this.expect("right-parenthesis",'")"'),i=F(e.span,n.span);return{kind:"function",functionKind:"unary",name:e.value,arguments:[t],id:E("function",i),span:i}}this.expect("comma",'","');const n=this.parseExpression(0),i=this.expect("right-parenthesis",'")"'),r=F(e.span,i.span);return V(e.value)?{kind:"function",functionKind:"binary",name:e.value,arguments:[t,n],id:E("function",r),span:r}:this.fail("Unsupported function",e.span,{found:e.value})}parseGroup(){const e=this.expect("left-brace",'"{"'),t=[this.parseExpression(0)];for(;"comma"===this.current().kind;)this.consume(),t.push(this.parseExpression(0));const n=this.expect("right-brace",'"}"'),i=this.parseModifiers(),r=0===i.length?n.span:i[i.length-1]?.span??n.span,s=F(e.span,r);return{kind:"group",id:E("group",s),span:s,expressions:t,modifiers:i}}isComparePointStart(){const e=this.current();return"comparison"===e.kind||"bang"===e.kind&&"comparison"===this.current(1).kind&&"="===this.current(1).lexeme}parseComparePoint(){const e=this.current();let t,n;if("bang"===e.kind){this.consume();const i=this.expect("comparison",'"=" after "!"');if("comparison"!==i.kind||"="!==i.value)return this.fail('Expected "=" after "!"',i.span,{found:i.lexeme});t="!=",n=F(e.span,i.span)}else{if("comparison"!==e.kind)return this.fail("Expected a comparison operator",e.span,{found:e.lexeme});this.consume(),t=e.value,n=e.span}let i=null;const r=this.current();"operator"!==r.kind||"+"!==r.value&&"-"!==r.value||(i=r.value,this.consume());const s=this.parseNumber(i),o=F(n,s.span);return{kind:"compare-point",id:E("compare-point",o),span:o,operator:t,value:s.value}}parseModifiers(){const e=[];for(;;){const t=this.parseModifier();if(null===t)break;e.push(t)}return e}parseModifier(){const e=this.current();if("bang"===e.kind)return this.parseExplode();if("comparison"===e.kind)return this.parseTarget();if("identifier"!==e.kind)return null;switch(e.value){case"d":return this.parseDropKeep("drop");case"k":return this.parseDropKeep("keep");case"max":return this.parseMinMax("max");case"min":return this.parseMinMax("min");case"r":return this.parseRerollUnique("reroll");case"u":return this.parseRerollUnique("unique");case"cs":return this.parseCritical("critical-success");case"cf":return this.parseCritical("critical-failure");case"s":return this.parseSort();default:return null}}parseExplode(){const e=this.expect("bang",'"!"');let t=!1;"bang"===this.current().kind&&(t=!0,this.consume());let n=!1;this.isIdentifier("p")&&(n=!0,this.consume());const i=this.isComparePointStart()?this.parseComparePoint():null,r=i?.span??this.tokens[this.cursor-1]?.span??e.span,s=F(e.span,r);return{kind:"explode",id:E("explode",s),span:s,compound:t,penetrate:n,compare:i}}parseTarget(){const e=this.parseComparePoint();let t=null;this.isIdentifier("f")&&(this.consume(),t=this.parseComparePoint());const n=F(e.span,t?.span??e.span);return{kind:"target",id:E("target",n),span:n,success:e,failure:t}}parsePositiveInteger(e){const t=this.parseNumber(null);return!Number.isInteger(t.value)||t.value<1||t.raw.length>1&&t.raw.startsWith("0")?this.fail(`${e} must be a positive integer`,t.span,{value:t.value}):t}parseDropKeep(e){const t=this.consume();let n="drop"===e?"lowest":"highest";this.isIdentifier("l")?(this.consume(),n="lowest"):this.isIdentifier("h")&&(this.consume(),n="highest");const i=this.parsePositiveInteger(`${e} quantity`),r=F(t.span,i.span);return{kind:e,id:E(e,r),span:r,selection:n,quantity:i.value}}parseSignedFloat(){const e=this.current();return"operator"!==e.kind||"+"!==e.value&&"-"!==e.value?this.parseNumber(null):(this.consume(),this.parseNumber(e.value))}parseMinMax(e){const t=this.consume(),n=this.parseSignedFloat(),i=F(t.span,n.span);return{kind:e,id:E(e,i),span:i,value:n.value}}parseRerollUnique(e){const t=this.consume();let n=!1;this.isIdentifier("o")&&(n=!0,this.consume());const i=this.isComparePointStart()?this.parseComparePoint():null,r=i?.span??this.tokens[this.cursor-1]?.span??t.span,s=F(t.span,r);return{kind:e,id:E(e,s),span:s,once:n,compare:i}}parseCritical(e){const t=this.consume(),n=this.isComparePointStart()?this.parseComparePoint():null,i=F(t.span,n?.span??t.span);return{kind:e,id:E(e,i),span:i,compare:n}}parseSort(){const e=this.consume();let t="ascending",n=e.span;this.isIdentifier("a")?n=this.consume().span:this.isIdentifier("d")&&(t="descending",n=this.consume().span);const i=F(e.span,n);return{kind:"sort",id:E("sort",i),span:i,direction:t}}}function G(e,t=P){return new $(e,t).parse()}const q=Object.freeze({maxDepth:64,maxNodes:512}),Y=Object.freeze({"(":")","[":"]","{":"}"}),X=new Set(Object.values(Y));function W(e){switch(e.kind){case"number":return[];case"unary":return[e.operand];case"binary":return[e.left,e.right];case"parenthesized":return[e.expression];case"function":return e.arguments;case"dice":return"standard"===e.diceKind?[e.quantity,e.sides]:[e.quantity];case"group":return e.expressions}}function K(e,t){const n=new Map,i=e=>n.get(e.id)??null;for(const r of function(e){const t=[],n=[{node:e,visited:!1}];for(;n.length>0;){const e=n.pop();if(void 0===e)break;if(e.visited){t.push(e.node);continue}n.push({node:e.node,visited:!0});const i=W(e.node);for(let e=i.length-1;e>=0;e-=1){const t=i[e];void 0!==t&&n.push({node:t,visited:!1})}}return t}(e)){let e;switch(r.kind){case"number":e=r.value;break;case"dice":case"group":e=null;break;case"unary":{const n=i(r.operand);e=null===n?null:x("-"===r.operator?-n:n,t);break}case"parenthesized":e=i(r.expression);break;case"binary":{const n=i(r.left),s=i(r.right);e=null===n||null===s?null:v("**"===r.operator?"^":r.operator,n,s,t);break}case"function":{const n=i(r.arguments[0]);if(null===n)e=null;else if("unary"===r.functionKind)e=b(r.name,n,t);else{const s=i(r.arguments[1]);e=null===s?null:N(r.name,n,s,t)}break}}null!==e&&n.set(r.id,e)}return i(e)}function B(e){const t=function(e){let t=e.trim();for(;;){const e=Y[t.charAt(0)];if(void 0===e||t.charAt(t.length-1)!==e)return t;const n=[];let i=!1;for(let e=0;e<t.length;e+=1){const r=t.charAt(e),s=Y[r];if(void 0===s){if(X.has(r)){if(n.pop()!==r)return t;if(0===n.length&&e<t.length-1){i=!0;break}}}else n.push(s)}if(i||0!==n.length)return t;t=t.slice(1,-1).trim()}}(e).replace(/\s+/gu,"");if(0===t.length)return null;try{return K(G(t,q),t)}catch{return null}}function Q(e){return e>="0"&&e<="9"}function H(e){return/^[a-z]$/i.test(e)}function J(e){return""===e||!/[a-z0-9_]/i.test(e)}function Z(e,t,n){let i=t;for(;i<e.length&&n(e.charAt(i));)i+=1;return[e.slice(t,i),i]}function ee(e){const t=B(e);return null!==t&&Number.isSafeInteger(t)&&t>=0}function te(e,t){let n=t;for(;n<e.length&&/\s/u.test(e.charAt(n));)n+=1;return e.charAt(n)}function ne(e){const t=[];let n="",i=0,r=!1;const s=e=>{const n=e.trim();n.length>0&&t.push(n)};for(;i<e.length;){const t=e.charAt(i),o=e.charAt(i+1);if("/"===t&&"*"===o){const t=e.indexOf("*/",i+2),n=t<0?e.length:t;s(e.slice(i+2,n)),i=t<0?e.length:t+2;continue}if("/"===t&&"/"===o){const t=/[\n\r\u2028\u2029]/u.exec(e.slice(i+2)),n=void 0===t?.index?e.length:i+2+t.index;s(e.slice(i+2,n)),i=n;continue}if("["===t){const t=e.indexOf("]",i+1),r=t<0?e.length:t,o=e.slice(i,r+1);if(0===n.length&&t>=0&&"#"===te(e,t+1)&&ee(o)){n+=o,i=t+1;continue}s(e.slice(i+1,r)),i=t<0?e.length:t+1;continue}if("#"===t){const o=n.replace(/\s+/gu,""),a=/^\d+$/u.test(o),u=a?null:B(o),c=null!==u&&Number.isSafeInteger(u)&&u>=0;if(!r&&(a||c)){c&&(n=String(u)),n+=t,r=!0,i+=1;continue}const l=/[\n\r\u2028\u2029]/u.exec(e.slice(i+1)),d=void 0===l?.index?e.length:i+1+l.index;s(e.slice(i+1,d)),i=d;continue}/\s/u.test(t)||(n+=t),i+=1}return{notation:n,comment:t.join(" ").trim()}}function ie(e,t){const n=e.charAt(t);if("("===n)return["",t];if("%"===n)return["%",t+1];if("F"===n.toUpperCase()){let n=t+1;return"."===e.charAt(n)&&["1","2"].includes(e.charAt(n+1))?(n+=2,[`F.${e.charAt(n-1)}`,n]):["F",n]}return Q(n)?Z(e,t,Q):["20",t]}function re(e,t){const n=e.toLowerCase();return"f"===n&&J(t)&&!["<",">","=","!"].includes(t)?"4dF":"ei"===n&&(Q(t)||["<",">","=","!",""].includes(t))?Q(t)?"!>=":"!":"km"===n?Q(t)?"kl":"kl1":"kh"===n||"kl"===n?Q(t)?n:`${n}1`:"k"===n?Q(t)?"k":"k1":e}function se(e){let t="",n=0;for(;n<e.length;){const i=e.charAt(n);if(Q(i)){const[i,r]=Z(e,n,Q),s=e.charAt(r);if("d"===s.toLowerCase()){const[s,o]=ie(e,r+1);t+=0===Number(i)?"0":`${i}d${s}`,n=o;continue}if("f"===s.toLowerCase()&&J(e.charAt(r+1))&&!["<",">","=","!"].includes(e.charAt(r+1))){t+=`${i}dF`,n=r+1;continue}t+=i,n=r;continue}if("d"===i.toLowerCase()){const i=e.charAt(n+1);if("f"===i.toLowerCase()){const[i,r]=ie(e,n+1);t+=`d${i}`,n=r;continue}if(""===i||J(i)||Q(i)||"%"===i){const[i,r]=ie(e,n+1);t+=`d${i}`,n=r;continue}}if(H(i)){const[i,r]=Z(e,n,H);t+=re(i,e.charAt(r)),n=r;continue}t+=i,n+=1}return t}function oe(e){let t=e,n="";for(;t!==n;)n=t,t=t.replace(/\+-/gu,"-").replace(/-\+/gu,"-").replace(/\+\+/gu,"+").replace(/--/gu,"+");return t.replace(/[+-]{3,}/gu,"+").replace(/^[+-]/u,"")}function ae(e){return oe(se(ne(e).notation))}function ue(e){const t=ne(e),n=oe(se(t.notation)),i=/^(\d+)#/u.exec(n),r=i?.[1],s=void 0===r?1:Number.parseInt(r,10),o=null===i?n:n.slice(i[0].length);return{input:e,comment:t.comment,notation:o,normalizedNotation:n,rollCount:s,isMultiRoll:null!==i}}function ce(e){if(!Number.isSafeInteger(e)||e<0)throw new s("Budget consumption must be a non-negative safe integer",{code:"ROLL_EXECUTION_LIMIT",details:{count:Number.isFinite(e)?e:String(e)}})}class le{limits;astNodes=0;rolls=0;initialDice=0;generatedDice=0;randomCalls=0;modifierSteps=0;events=0;resolvedGroups=0;resultItems=0;constructor(e){this.limits=e}assertInputLength(e){e.length>this.limits.maxInputLength&&this.throwLimit({code:"INPUT_TOO_LONG",message:"Dice input exceeds the maximum length",limitName:"maxInputLength"},e.length,{inputLength:e.length},e)}consumeAstNode(e){if(!Number.isSafeInteger(e)||e<1)throw new s("AST depth must be a positive safe integer",{code:"ROLL_EXECUTION_LIMIT",details:{depth:e}});e>this.limits.maxAstDepth&&this.throwLimit({code:"AST_TOO_DEEP",message:"AST exceeds the maximum depth",limitName:"maxAstDepth"},e,{depth:e}),this.astNodes=this.consume(this.astNodes,1,{code:"TOO_MANY_NODES",message:"AST exceeds the maximum node count",limitName:"maxAstNodes"})}consumeRolls(e=1){this.rolls=this.consume(this.rolls,e,{code:"TOO_MANY_ROLLS",message:"Roll count exceeds the execution limit",limitName:"maxRolls"})}consumeInitialDice(e=1){this.initialDice=this.consume(this.initialDice,e,{code:"TOO_MANY_INITIAL_DICE",message:"Initial dice count exceeds the execution limit",limitName:"maxInitialDice"})}consumeGeneratedDice(e=1){this.generatedDice=this.consume(this.generatedDice,e,{code:"GENERATED_DICE_LIMIT_EXCEEDED",message:"Generated dice count exceeds the execution limit",limitName:"maxGeneratedDice"})}consumeRandomCalls(e=1){this.randomCalls=this.consume(this.randomCalls,e,{code:"RANDOM_BUDGET_EXCEEDED",message:"Random call count exceeds the execution limit",limitName:"maxRandomCalls"})}consumeEvents(e=1){this.events=this.consume(this.events,e,{code:"EVENT_LIMIT_EXCEEDED",message:"Event count exceeds the execution limit",limitName:"maxEvents"})}consumeModifierSteps(e=1){this.modifierSteps=this.consume(this.modifierSteps,e,{code:"MODIFIER_STEP_LIMIT_EXCEEDED",message:"Modifier step count exceeds the execution limit",limitName:"maxModifierSteps"})}consumeResolvedGroups(e=1){this.resolvedGroups=this.consume(this.resolvedGroups,e,{code:"RESOLVED_GROUP_LIMIT_EXCEEDED",message:"Resolved group count exceeds the execution limit",limitName:"maxResolvedGroups"})}consumeResultItems(e=1){this.resultItems=this.consume(this.resultItems,e,{code:"RESULT_LIMIT_EXCEEDED",message:"Result item count exceeds the execution limit",limitName:"maxResultItems"})}assertOutputLength(e){ce(e),e>this.limits.maxOutputLength&&this.throwLimit({code:"OUTPUT_LIMIT_EXCEEDED",message:"Output exceeds the maximum length",limitName:"maxOutputLength"},e,{outputLength:e})}snapshot(){return Object.freeze({astNodes:this.astNodes,rolls:this.rolls,initialDice:this.initialDice,generatedDice:this.generatedDice,randomCalls:this.randomCalls,modifierSteps:this.modifierSteps,events:this.events,resolvedGroups:this.resolvedGroups,resultItems:this.resultItems})}stats(){return Object.freeze({rolls:this.rolls,initialDice:this.initialDice,generatedDice:this.generatedDice,randomCalls:this.randomCalls,modifierSteps:this.modifierSteps,events:this.events,resolvedGroups:this.resolvedGroups,resultItems:this.resultItems})}consume(e,t,n){ce(t);const i=e+t,r=this.limits[n.limitName];return(!Number.isSafeInteger(i)||i>r)&&this.throwLimit(n,i,{consumed:i}),i}throwLimit(e,t,n,i=""){const r=this.limits[e.limitName];throw new s(e.message,{code:e.code,input:i,details:{...n,limitName:e.limitName,limit:r,actual:t}})}}const de=Number.MAX_SAFE_INTEGER,pe=new WeakMap;function me(e,t){return e>=de-t?de:e+t}function he(e,t){return 0===e||0===t?0:e>Math.floor(de/t)?de:e*t}function fe(e,t,n){if(!Number.isFinite(e))throw new s("Dice argument produced a non-finite result",{code:"NON_FINITE_RESULT",input:t,span:n,details:{value:String(e)}});const i=Number.isSafeInteger(e)?e:Number(e.toPrecision(12));return Object.is(i,-0)?0:i}function ge(e,t,n,i){const r=i.get(e.id);if(void 0===r)throw new s("Dice arguments must be constant expressions",{code:"INVALID_NOTATION",input:t,span:e.span,details:{argument:n,nodeKind:e.kind}});if(!Number.isSafeInteger(r)||r<1)throw new s(`Dice ${n} must be a positive safe integer`,{code:"INVALID_NOTATION",input:t,span:e.span,details:{argument:n,value:Number.isFinite(r)?r:String(r)}});return r}function Ie(e){switch(e.kind){case"min":return 1;case"max":return 2;case"explode":return 3;case"reroll":return 4;case"unique":return 5;case"keep":return 6;case"drop":return 7;case"target":return 8;case"critical-success":return 9;case"critical-failure":return 10;case"sort":return 11}}function xe(e){const t=new Set,n=[];for(let i=e.length-1;i>=0;i-=1){const r=e[i];void 0===r||t.has(r.kind)||(t.add(r.kind),n.push(r))}return n.reverse(),n.sort((e,t)=>Ie(e)-Ie(t)),Object.freeze(n)}function ve(e,t,n){switch(e.operator){case"=":return t===n&&t===e.value;case"!=":case"<>":return e.value<t||e.value>n;case"<":return n<e.value;case"<=":return n<=e.value;case">":return t>e.value;case">=":return t>=e.value}}function be(e,t){for(const n of e.modifiers)if("keep"!==n.kind&&"drop"!==n.kind&&"sort"!==n.kind)throw new s(`Modifier ${n.kind} is not supported on roll groups`,{code:"UNSUPPORTED_GROUP_MODIFIER",input:t,span:n.span,details:{modifier:n.kind}})}function Ne(e,t,n,i){const r=ge(e.quantity,t,"quantity",i);let o,a,u,c;if("standard"===e.diceKind){const r=ge(e.sides,t,"sides",i);if(r>n.maxSides)throw new s("Dice sides exceed the configured limit",{code:"DICE_SIDES_LIMIT_EXCEEDED",input:t,span:e.sides.span,details:{sides:r,limit:n.maxSides}});o=r,a=1,u=r,c=r}else"percentile"===e.diceKind?(o=100,a=1,u=100,c=100):(o="F",a=-1,u=1,c=3);const l=xe(e.modifiers);for(const e of l){if("explode"===e.kind&&(null===e.compare?a===u:ve(e.compare,a,u)))throw new s("Explode modifier cannot terminate for this die",{code:"NON_TERMINATING_MODIFIER",input:t,span:e.span,details:{reason:"non-terminating-explode",minimum:a,maximum:u}});if("reroll"===e.kind&&!e.once&&(null===e.compare?a===u:ve(e.compare,a,u)))throw new s("Reroll modifier cannot terminate for this die",{code:"NON_TERMINATING_MODIFIER",input:t,span:e.span,details:{reason:"non-terminating-reroll",minimum:a,maximum:u}});if("unique"===e.kind&&!e.once&&r>c&&(null===e.compare||ve(e.compare,a,u)))throw new s("Unique modifier cannot produce enough distinct faces",{code:"IMPOSSIBLE_UNIQUE",input:t,span:e.span,details:{reason:"impossible-unique",quantity:r,possibleFaces:c}})}return Object.freeze({nodeId:e.id,quantity:r,sides:o,minimum:a,maximum:u,possibleFaces:c,modifiers:l})}function De(e){switch(e.kind){case"number":return[];case"unary":return[e.operand];case"binary":return[e.left,e.right];case"parenthesized":return[e.expression];case"function":return e.arguments;case"dice":return"standard"===e.diceKind?[e.quantity,e.sides]:[e.quantity];case"group":return e.expressions}}function Ee(e){switch(e.kind){case"number":case"compare-point":case"drop":case"keep":case"min":case"max":case"sort":return[];case"unary":return[e.operand];case"binary":return[e.left,e.right];case"parenthesized":return[e.expression];case"function":return e.arguments;case"dice":return"standard"===e.diceKind?[e.quantity,e.sides,...e.modifiers]:[e.quantity,...e.modifiers];case"group":return[...e.expressions,...e.modifiers];case"explode":case"reroll":case"unique":case"critical-success":case"critical-failure":return null===e.compare?[]:[e.compare];case"target":return null===e.failure?[e.success]:[e.success,e.failure]}}function we(e,t,n){const i=e=>t.get(e.id)??null;switch(e.kind){case"number":return e.value;case"dice":case"group":return null;case"unary":{const t=i(e.operand);return null===t?null:"-"===e.operator?-t:t}case"parenthesized":return i(e.expression);case"binary":{const t=i(e.left),r=i(e.right);if(null===t||null===r)return null;let s;switch(e.operator){case"+":s=t+r;break;case"-":s=t-r;break;case"*":s=t*r;break;case"/":s=t/r;break;case"%":s=t%r;break;case"^":case"**":s=t**r}return fe(s,n,e.span)}case"function":{const t=i(e.arguments[0]);if(null===t)return null;if("unary"===e.functionKind){let i;switch(e.name){case"abs":i=Math.abs(t);break;case"ceil":i=Math.ceil(t);break;case"cos":i=Math.cos(t);break;case"exp":i=Math.exp(t);break;case"floor":i=Math.floor(t);break;case"log":i=Math.log(t);break;case"round":i=Math.round(t);break;case"sign":i=Math.sign(t);break;case"sin":i=Math.sin(t);break;case"sqrt":i=Math.sqrt(t);break;case"tan":i=Math.tan(t)}return fe(i,n,e.span)}const r=i(e.arguments[1]);if(null===r)return null;let s;switch(e.name){case"max":s=Math.max(t,r);break;case"min":s=Math.min(t,r);break;case"pow":s=Math.pow(t,r)}return fe(s,n,e.span)}}}function Ae(e){return[2166136261,2654435769,2246822507,3266489909].map(t=>function(e,t){let n=t;for(let t=0;t<e.length;t+=1)n^=e.charCodeAt(t),n=Math.imul(n,16777619),n^=n>>>13;return n>>>0}(`dicecore:1:${e}`,t).toString(16).padStart(8,"0")).join("")}function Oe(e,t){if("string"!=typeof e)throw new s("Dice input must be a string",{code:"INVALID_NOTATION",details:{receivedType:typeof e}});new le(t).assertInputLength(e);const n=ue(e);return function(e,t){if(0===e.notation.length)throw new s("Dice notation is required",{code:"DICE_NOTATION_REQUIRED",input:e.input});if(!Number.isSafeInteger(e.rollCount)||e.rollCount<1)throw new s("Roll count must be a positive safe integer",{code:"INVALID_NOTATION",input:e.input,details:{rollCount:Number.isFinite(e.rollCount)?e.rollCount:String(e.rollCount)}});if(e.rollCount>t.maxRolls)throw new s("Roll count exceeds the execution limit",{code:"TOO_MANY_ROLLS",input:e.input,details:{rollCount:e.rollCount,limit:t.maxRolls}})}(n,t),{normalized:n}}function Se(e,t,n){let i;try{i=G(e,{maxDepth:n.maxAstDepth,maxNodes:n.maxAstNodes})}catch(e){throw function(e,t){return o(e)?e.input===t?e:new s(e.message,{code:e.code,input:t,span:e.span,details:e.details}):new s("Invalid dice notation",{code:"INVALID_NOTATION",input:t,details:{cause:e instanceof Error?e.message:"Unknown parser error"}})}(e,t)}const r=function(e){const t=[],n=[{node:e,depth:1,visited:!1}];let i=1;for(;n.length>0;){const e=n.pop();if(void 0===e)break;if(i=Math.max(i,e.depth),e.visited){t.push(e.node);continue}n.push({node:e.node,depth:e.depth,visited:!0});const r=De(e.node);for(let t=r.length-1;t>=0;t-=1){const i=r[t];void 0!==i&&n.push({node:i,depth:e.depth+1,visited:!1})}}return{nodes:Object.freeze(t),maxDepth:i}}(i),a=function(e){const t=[{node:e,depth:1}];let n=0,i=1;for(;t.length>0;){const e=t.pop();if(void 0===e)break;n+=1,i=Math.max(i,e.depth);const r=Ee(e.node);for(let n=r.length-1;n>=0;n-=1){const i=r[n];void 0!==i&&t.push({node:i,depth:e.depth+1})}}return{nodeCount:n,maxDepth:i}}(i),u=new Map,c=new Map;let l=0,d=0;for(const e of r.nodes)if("group"===e.kind&&be(e,t),"dice"===e.kind){const i=Ne(e,t,n,c);u.set(e.id,i),l=me(l,i.quantity),"number"==typeof i.sides&&(d=Math.max(d,i.sides))}else{const n=we(e,c,t);null!==n&&c.set(e.id,n)}return Object.freeze({compilerVersion:1,notation:e,programFingerprint:Ae(e),ast:i,postOrder:r.nodes,nodeCount:a.nodeCount,maxDepth:a.maxDepth,staticDice:l,maximumSides:d,diceSpecs:u,constants:c})}function ye(e,t,n,i,r){if(i.notation!==t)throw new s("Compiled program does not match normalized notation",{code:"UNSUPPORTED_NOTATION",input:e});if(i.nodeCount>r.maxAstNodes)throw new s("AST node count exceeds the execution limit",{code:"TOO_MANY_NODES",input:e,details:{actual:i.nodeCount,limit:r.maxAstNodes}});if(i.maxDepth>r.maxAstDepth)throw new s("AST depth exceeds the execution limit",{code:"AST_TOO_DEEP",input:e,details:{actual:i.maxDepth,limit:r.maxAstDepth}});if(i.maximumSides>r.maxSides)throw new s("Dice sides exceed the configured limit",{code:"DICE_SIDES_LIMIT_EXCEEDED",input:e,details:{sides:i.maximumSides,limit:r.maxSides}});if(he(i.staticDice,n)>r.maxInitialDice)throw new s("Initial dice count exceeds the execution limit",{code:"TOO_MANY_INITIAL_DICE",input:e,details:{quantity:i.staticDice,rollCount:n,limit:r.maxInitialDice}})}function Re(e){switch(e.kind){case"number":case"dice":return[];case"unary":return[e.operand];case"binary":return[e.left,e.right];case"parenthesized":return[e.expression];case"function":return e.arguments;case"group":return e.expressions}}function ke(e){switch(e.kind){case"dice":return"dice";case"function":return"function";case"group":return"group";case"number":case"unary":case"binary":case"parenthesized":return"expression"}}function _e(e){return`group:${e.id}`}function Le(e,t){const n=[],i=[e];for(;i.length>0;){const e=i.pop();if(void 0===e)break;const r=Re(e);n.push({id:_e(e),sourceNodeId:e.id,kind:ke(e),notation:t.slice(e.span.start,e.span.end),span:e.span,childIds:r.map(_e)});for(let e=r.length-1;e>=0;e-=1){const t=r[e];void 0!==t&&i.push(t)}}return n}function Te(e,t){switch(e.kind){case"explode":return t.maxModifierSteps;case"reroll":case"unique":return e.once?1:t.maxModifierSteps;case"target":case"drop":case"keep":case"min":case"max":case"critical-success":case"critical-failure":case"sort":return 0}}function Me(e,t,n){let i={staticDice:0,worstCaseGeneratedDice:0,worstCaseRandomCalls:0};for(const t of e.diceSpecs.values()){let e=0,r=1;for(const i of t.modifiers){const t=Te(i,n);r=me(r,t),"explode"===i.kind&&(e=me(e,t))}i={staticDice:me(i.staticDice,t.quantity),worstCaseGeneratedDice:me(i.worstCaseGeneratedDice,he(t.quantity,e)),worstCaseRandomCalls:me(i.worstCaseRandomCalls,he(t.quantity,r))}}return{...i,totalStaticDice:he(i.staticDice,t),totalWorstCaseGeneratedDice:he(i.worstCaseGeneratedDice,t),totalWorstCaseRandomCalls:he(i.worstCaseRandomCalls,t)}}function Ce(e,t,n){const i=n??Se(e.normalized.notation,e.normalized.input,t);ye(e.normalized.input,e.normalized.notation,e.normalized.rollCount,i,t);const r=e.normalized,s=function(e){return e.groups.forEach(h),Object.freeze(e.groups),Object.freeze(e.cost),Object.freeze(e)}({type:"roll-plan",schemaVersion:3,compilerVersion:1,planFingerprint:Ae(r.normalizedNotation),input:r.input,comment:r.comment,notation:r.notation,normalizedNotation:r.normalizedNotation,isMultiRoll:r.isMultiRoll,rollCount:r.rollCount,groups:Le(i.ast,r.notation),cost:Me(i,r.rollCount,t)});return pe.set(s,i),s}function je(e){const t=pe.get(e);if(void 0===t)throw new s("Roll plan was not created by this compiler instance",{code:"UNSUPPORTED_NOTATION",input:e.input,details:{schemaVersion:e.schemaVersion}});return t}class ze{journal=[];budget;materialize;eventCount=0;constructor(e=null,t=!0){this.budget=e,this.materialize=t}get length(){return this.eventCount}record(e){if(this.budget?.consumeEvents(),this.budget?.consumeResultItems(),this.eventCount+=1,!this.materialize)return null;const t={sequence:this.eventCount,...e};return this.journal.push(t),t}slice(e,t=this.journal.length){return this.materialize?this.journal.slice(e,t):[]}toArray(){return this.materialize?this.journal.slice():[]}}const Pe=Object.freeze({maxInputLength:4096,maxAstDepth:64,maxAstNodes:1e4,maxRolls:100,maxInitialDice:1e4,maxGeneratedDice:2e4,maxRandomCalls:1e5,maxEvents:1e5,maxSides:4294967296,maxSeedLength:1024,maxModifierSteps:1e5,maxResolvedGroups:1e5,maxResultItems:25e4,maxOutputLength:1e6});function Ue(e,t,n){let i;try{i=e[t]}catch{throw new s(`Unable to read ${t}`,{code:"INVALID_LIMIT",details:{limit:t}})}if(void 0===i)return n;if("number"!=typeof i)throw new s(`${t} must be a number`,{code:"INVALID_LIMIT",details:{limit:t,valueType:typeof i}});return function(e,t){if(!Number.isSafeInteger(t)||t<1)throw new s(`${e} must be a positive safe integer`,{code:"INVALID_LIMIT",details:{limit:e,value:Number.isFinite(t)?t:String(t)}});return t}(t,i)}function Ve(e){try{if("object"!=typeof e||null===e||Array.isArray(e))throw new s("Dice limit overrides must be a non-null object",{code:"INVALID_LIMIT"})}catch(e){if(e instanceof s)throw e;throw new s("Dice limit overrides could not be read",{code:"INVALID_LIMIT"})}}function Fe(e,t,n){const i=Ue(t,n,e[n]);if(i>e[n])throw new s(`${n} cannot exceed the engine cap`,{code:"INVALID_LIMIT",details:{limit:n,requested:i,engineCap:e[n]}});return i}function $e(e){return Object.freeze(e)}function Ge(e={}){return Ve(e),$e({maxInputLength:Ue(e,"maxInputLength",Pe.maxInputLength),maxAstDepth:Ue(e,"maxAstDepth",Pe.maxAstDepth),maxAstNodes:Ue(e,"maxAstNodes",Pe.maxAstNodes),maxRolls:Ue(e,"maxRolls",Pe.maxRolls),maxInitialDice:Ue(e,"maxInitialDice",Pe.maxInitialDice),maxGeneratedDice:Ue(e,"maxGeneratedDice",Pe.maxGeneratedDice),maxRandomCalls:Ue(e,"maxRandomCalls",Pe.maxRandomCalls),maxEvents:Ue(e,"maxEvents",Pe.maxEvents),maxSides:Ue(e,"maxSides",Pe.maxSides),maxSeedLength:Ue(e,"maxSeedLength",Pe.maxSeedLength),maxModifierSteps:Ue(e,"maxModifierSteps",Pe.maxModifierSteps),maxResolvedGroups:Ue(e,"maxResolvedGroups",Pe.maxResolvedGroups),maxResultItems:Ue(e,"maxResultItems",Pe.maxResultItems),maxOutputLength:Ue(e,"maxOutputLength",Pe.maxOutputLength)})}const qe=624,Ye=397,Xe=2567483615,We=2147483648,Ke=2147483647,Be=4294967296;let Qe=null,He=null;function Je(e){if(!Number.isSafeInteger(e))throw new s("MT19937 seed words must be safe integers",{code:"INVALID_SEED",details:{seed:Number.isFinite(e)?e:String(e)}});return e>>>0}class Ze{state=new Uint32Array(qe);index=qe;budget;constructor(e,t=null){this.budget=t,"number"==typeof e?this.initializeSeed(Je(e)):this.restoreCachedSeedArray(e)?this.index=0:(this.initializeSeedArray(e),this.twist(),this.cacheSeedArray(e))}nextUint32(){this.budget?.consumeRandomCalls(),this.index>=qe&&this.twist();let e=this.readState(this.index);return this.index+=1,e^=e>>>11,e^=e<<7&2636928640,e^=e<<15&4022730752,e^=e>>>18,e>>>0}integer(e,t){if(!Number.isSafeInteger(e)||!Number.isSafeInteger(t)||e>t)throw new RangeError("Random integer bounds must be ordered safe integers");const n=t-e+1;if(!Number.isSafeInteger(n)||n<1||n>Be)throw new RangeError("Random integer range must contain at most 2^32 values");if(n===Be)return e+this.nextUint32();const i=Math.floor(Be/n)*n;let r=this.nextUint32();for(;r>=i;)r=this.nextUint32();return e+r%n}real(){return this.nextUint32()/Be}readState(e){return this.state[e]??0}writeState(e,t){this.state[e]=t>>>0}initializeSeed(e){this.writeState(0,e);for(let e=1;e<qe;e+=1){const t=this.readState(e-1),n=t^t>>>30;this.writeState(e,Math.imul(1812433253,n)+e)}this.index=qe}initializeSeedArray(e){if(e.length<1)throw new s("MT19937 requires at least one seed word",{code:"INVALID_SEED"});this.initializeSeed(19650218);let t=1,n=0,i=Math.max(qe,e.length);for(;i>0;){const r=this.readState(t-1),s=this.readState(t),o=Je(e[n]??0),a=Math.imul(r^r>>>30,1664525);this.writeState(t,(s^a)+o+n),t+=1,n+=1,t>=qe&&(this.writeState(0,this.readState(623)),t=1),n>=e.length&&(n=0),i-=1}for(i=623;i>0;){const e=this.readState(t-1),n=this.readState(t),r=Math.imul(e^e>>>30,1566083941);this.writeState(t,(n^r)-t),t+=1,t>=qe&&(this.writeState(0,this.readState(623)),t=1),i-=1}this.writeState(0,We),this.index=qe}restoreCachedSeedArray(e){const t=Qe,n=He;if(null===t||null===n||t.length!==e.length)return!1;for(let n=0;n<t.length;n+=1)if(t[n]!==e[n])return!1;return this.state.set(n),!0}cacheSeedArray(e){const t=new Uint32Array(e.length);for(let n=0;n<e.length;n+=1)t[n]=Je(e[n]??0);Qe=t,He=this.state.slice()}twist(){let e=0;for(;e<227;e+=1){const t=this.readState(e)&We|this.readState(e+1)&Ke,n=1&~t?0:Xe;this.writeState(e,this.readState(e+Ye)^t>>>1^n)}for(;e<623;e+=1){const t=this.readState(e)&We|this.readState(e+1)&Ke,n=1&~t?0:Xe;this.writeState(e,this.readState(e+Ye-qe)^t>>>1^n)}const t=this.readState(623)&We|this.readState(0)&Ke,n=1&~t?0:Xe;this.writeState(623,this.readState(396)^t>>>1^n),this.index=0}}const et=/^[0-9a-f]{32}$/u;function tt(){const e=globalThis.crypto;return"function"==typeof e?.getRandomValues?e:null}function nt(e){let t="";for(let n=0;n<e.length;n+=1)t+=(e[n]??0).toString(16).padStart(8,"0");return t}function it(e){return new s(e,{code:"INVALID_REPLAY"})}function rt(e){if("object"!=typeof e||null===e)return!1;try{return!Array.isArray(e)}catch{return!1}}function st(e){if(!rt(e)||!function(e){const t=["algorithm","algorithmVersion","executionVersion","mathProfile","origin","planFingerprint","schemaVersion","seedMaterial"];try{return Object.keys(e).sort().join(",")===t.join(",")}catch{return!1}}(e))return!1;try{return 2===e.schemaVersion&&("mt19937"===e.algorithm||"xoshiro128ss"===e.algorithm)&&1===e.algorithmVersion&&1===e.executionVersion&&e.mathProfile===g&&("provided-number"===e.origin||"provided-string"===e.origin||"crypto"===e.origin)&&"string"==typeof e.seedMaterial&&et.test(e.seedMaterial)&&"string"==typeof e.planFingerprint&&et.test(e.planFingerprint)}catch{return!1}}function ot(e,t){if(!rt(e))throw it("Replay descriptor must be a non-null object");try{if(2!==e.schemaVersion||1!==e.algorithmVersion||1!==e.executionVersion||e.mathProfile!==g||"mt19937"!==e.algorithm&&"xoshiro128ss"!==e.algorithm)throw new s("The replay algorithm or version is not supported",{code:"UNSUPPORTED_REPLAY_VERSION"})}catch(e){if(e instanceof s)throw e;throw it("Replay descriptor could not be read")}if(!st(e))throw it("Replay descriptor contains malformed or unexpected fields");if(void 0!==t&&e.planFingerprint!==t)throw new s("Replay descriptor belongs to a different roll plan",{code:"REPLAY_PLAN_MISMATCH",details:{expectedPlanFingerprint:t,actualPlanFingerprint:e.planFingerprint}});return e}function at(e,t=Pe.maxSeedLength){const n=function(e,t=Pe.maxSeedLength){if(!Number.isSafeInteger(t)||t<1)throw new s("maxSeedLength must be a positive safe integer",{code:"INVALID_LIMIT",details:{maxSeedLength:t}});if("number"==typeof e){if(!Number.isFinite(e))throw new s("Numeric seeds must be finite",{code:"INVALID_SEED",details:{seed:String(e)}});return`number:${Object.is(e,-0)?"-0":e.toString(10)}`}if("string"!=typeof e)throw new s("Seeds must be finite numbers or strings",{code:"INVALID_SEED"});if(e.length>t)throw new s("Text seed exceeds the maximum length",{code:"INVALID_SEED",details:{seedLength:e.length,maxSeedLength:t}});return`string:${e}`}(e,t),i=function(e){let t=1779033703^e.length;for(let n=0;n<e.length;n+=1)t=Math.imul(t^e.charCodeAt(n),3432918353),t=t<<13|t>>>19;const n=[];for(let e=0;e<4;e+=1)t=Math.imul(t^t>>>16,2246822507),t=Math.imul(t^t>>>13,3266489909),t^=t>>>16,n.push(t>>>0);return Object.freeze(n)}(n);return Object.freeze({canonicalSeed:n,seedMaterial:nt(i),origin:"number"==typeof e?"provided-number":"provided-string",words:i})}function ut(e,t){const n=ot(e,t),i=function(e){const t=[];for(let n=0;n<4;n+=1)t.push(Number.parseInt(e.slice(8*n,8*(n+1)),16));return Object.freeze(t)}(n.seedMaterial);return Object.freeze({canonicalSeed:`replay:${n.seedMaterial}`,seedMaterial:n.seedMaterial,origin:n.origin,words:i})}function ct(e,t=tt(),n=Pe.maxSeedLength){return void 0===e?function(e=tt()){if(null===e)throw new s("A cryptographic random source is not available",{code:"RNG_UNAVAILABLE"});const t=new Uint32Array(4);try{e.getRandomValues(t)}catch{throw new s("The cryptographic random source failed",{code:"RNG_UNAVAILABLE"})}const n=Object.freeze(Array.from(t)),i=nt(n);return Object.freeze({canonicalSeed:`crypto:${i}`,seedMaterial:i,origin:"crypto",words:n})}(t):at(e,n)}const lt=4294967296;function dt(e,t){return e<<t|e>>>32-t}function pt(e){if(!Number.isSafeInteger(e))throw new s("xoshiro128** seed words must be safe integers",{code:"INVALID_SEED",details:{seed:Number.isFinite(e)?e:String(e)}});return e>>>0}class mt{state0;state1;state2;state3;budget;constructor(e,t=null){if(4!==e.length)throw new s("xoshiro128** requires exactly four seed words",{code:"INVALID_SEED",details:{wordCount:e.length}});this.budget=t,this.state0=0|pt(e[0]??0),this.state1=0|pt(e[1]??0),this.state2=0|pt(e[2]??0),this.state3=0|pt(e[3]??0),0===(this.state0|this.state1|this.state2|this.state3)&&(this.state3=-1640531527)}nextUint32(){this.budget?.consumeRandomCalls();const e=this.state0;let t=this.state1,n=this.state2,i=this.state3;const r=Math.imul(dt(Math.imul(t,5),7),9)>>>0,s=t<<9;return n^=e,i^=t,t^=n,this.state0=e^i,this.state1=t,this.state2=n^s,this.state3=dt(i,11),r}integer(e,t){if(!Number.isSafeInteger(e)||!Number.isSafeInteger(t)||e>t)throw new RangeError("Random integer bounds must be ordered safe integers");const n=t-e+1;if(!Number.isSafeInteger(n)||n<1||n>lt)throw new RangeError("Random integer range must contain at most 2^32 values");if(n===lt)return e+this.nextUint32();const i=Math.floor(lt/n)*n;let r=this.nextUint32();for(;r>=i;)r=this.nextUint32();return e+r%n}real(){return this.nextUint32()/lt}}class ht{limits;budget;random;journal;replay;constructor(e={}){if(this.limits=e.resolvedLimits??Ge(e.limits),this.budget=new le(this.limits),void 0!==e.seed&&void 0!==e.replay)throw new s("seed and replay are mutually exclusive",{code:"INVALID_REPLAY"});if(void 0!==e.replay&&void 0!==e.randomAlgorithm)throw new s("A replay descriptor determines its random algorithm",{code:"INVALID_REPLAY"});if(void 0!==e.collectEvents&&"boolean"!=typeof e.collectEvents)throw new s("collectEvents must be a boolean",{code:"ROLL_EXECUTION_LIMIT"});let t,n;if(void 0===e.replay){if(t=e.randomAlgorithm??"mt19937","mt19937"!==t&&"xoshiro128ss"!==t)throw new s("The requested random algorithm is not supported",{code:"INVALID_REPLAY"});n=ct(e.seed,e.cryptoSource,this.limits.maxSeedLength),this.replay=function(e,t={}){const n=t.algorithm??"mt19937",i=t.planFingerprint??"00000000000000000000000000000000";if("mt19937"!==n&&"xoshiro128ss"!==n||!et.test(e.seedMaterial)||!et.test(i))throw it("Replay seed material and plan fingerprint must be 128-bit hex strings");return Object.freeze({schemaVersion:2,algorithm:n,algorithmVersion:1,executionVersion:1,mathProfile:g,origin:e.origin,seedMaterial:e.seedMaterial,planFingerprint:i})}(n,{algorithm:t,...void 0===e.planFingerprint?{}:{planFingerprint:e.planFingerprint}})}else{const i=ot(e.replay,e.planFingerprint);t=i.algorithm,n=ut(i,e.planFingerprint),this.replay=i}this.random="mt19937"===t?new Ze(n.words,this.budget):new mt(n.words,this.budget),this.journal=new ze(this.budget,e.collectEvents??!0)}}function ft(e={}){return new ht(e)}function gt(e,t){return`roll-${t}:group:${e.id}`}function It(e,t){return e.plan.notation.slice(t.span.start,t.span.end)}function xt(e,t){e.states.includes(t)||e.states.push(t)}function vt(e){e.contribution=e.active&&e.included?e.value:0}function bt(e,t){return function(e,t,n){switch(e){case"=":return t===n;case"!=":case"<>":return t!==n;case"<":return t<n;case">":return t>n;case"<=":return t<=n;case">=":return t>=n}}(e.operator,t,e.value)}function Nt(e,t,n){return Dt(e,t,n.context)}function Dt(e,t,n){switch(e.diceKind){case"standard":return n.random.integer(t.minimum,t.maximum);case"percentile":return n.random.integer(1,100);case"fudge":if(2===e.variant)return n.random.integer(1,3)-2;{const e=n.random.integer(1,6);return 1===e?-1:6===e?1:0}}}function Et(e,t,n,i,r){r?n.context.budget.consumeGeneratedDice():n.context.budget.consumeInitialDice(),n.context.budget.consumeResultItems(),n.nextDieIndex+=1;const s=Nt(e,t,n),o={id:`roll-${n.rollIndex}-die-${n.nextDieIndex}`,sourceNodeId:e.id,parentDieId:i,rollIndex:n.rollIndex,groupId:gt(e,n.rollIndex),sides:t.sides,rawValue:s,value:s,contribution:s,included:!0,active:!0,states:[]};return n.dice.push(o),n.context.journal.record({type:"roll",subject:"die",dieId:o.id,parentDieId:i,rollIndex:n.rollIndex,sourceNodeId:e.id,value:s}),o}function wt(e,t,n){for(const i of e)if(i.active&&i.value<t){const e=i.value;i.value=t,xt(i,"minimum"),vt(i),n.context.journal.record({type:"transform",subject:"die",dieId:i.id,parentDieId:i.parentDieId,rollIndex:n.rollIndex,sourceNodeId:i.sourceNodeId,from:e,to:i.value,reason:"minimum"})}}function At(e,t,n){for(const i of e)if(i.active&&i.value>t){const e=i.value;i.value=t,xt(i,"maximum"),vt(i),n.context.journal.record({type:"transform",subject:"die",dieId:i.id,parentDieId:i.parentDieId,rollIndex:n.rollIndex,sourceNodeId:i.sourceNodeId,from:e,to:i.value,reason:"maximum"})}}function Ot(e,t,n,i,r){const s=e.filter(e=>e.active),o=i.maximum;for(const a of s){let s=a,u=s.value;const c=[a];for(;;){if(!(null===t.compare?u===o:bt(t.compare,u)))break;r.context.budget.consumeModifierSteps(),xt(s,"exploded"),t.penetrate&&xt(s,"penetrated");const a=Et(n,i,r,s.id,!0);if(u=a.value,t.penetrate){const e=a.value;a.value-=1,vt(a),r.context.journal.record({type:"transform",subject:"die",dieId:a.id,parentDieId:a.parentDieId,rollIndex:r.rollIndex,sourceNodeId:n.id,from:e,to:a.value,reason:"penetrate"})}e.push(a),c.push(a),r.context.journal.record({type:"explode",subject:"die",dieId:s.id,parentDieId:s.parentDieId,rollIndex:r.rollIndex,sourceNodeId:n.id,childDieId:a.id,value:a.value,reason:t.compound?"compound":t.penetrate?"penetrate":"explode"}),s=a}if(t.compound&&c.length>1){const e=a.value;a.value=c.reduce((e,t)=>e+t.value,0),xt(a,"compound"),vt(a),r.context.journal.record({type:"transform",subject:"die",dieId:a.id,parentDieId:a.parentDieId,rollIndex:r.rollIndex,sourceNodeId:n.id,from:e,to:a.value,reason:"compound"});for(let e=1;e<c.length;e+=1){const t=c[e];void 0!==t&&(t.active=!1,t.included=!1,vt(t),r.context.journal.record({type:"exclude",subject:"die",dieId:t.id,parentDieId:t.parentDieId,rollIndex:r.rollIndex,sourceNodeId:n.id,reason:"compound-absorbed"}))}}}}function St(e,t,n,i,r){const s=i.minimum;for(const o of e)if(o.active)for(;;){if(!(null===t.compare?o.value===s:bt(t.compare,o.value)))break;r.context.budget.consumeModifierSteps();const e=o.value,a=Nt(n,i,r);if(o.value=a,xt(o,"rerolled"),vt(o),r.context.journal.record({type:"reroll",subject:"die",dieId:o.id,parentDieId:o.parentDieId,rollIndex:r.rollIndex,sourceNodeId:n.id,from:e,to:a,reason:t.once?"reroll-once":"reroll"}),t.once)break}}function yt(e,t,n,i,r){const s=e.filter(e=>e.active),o=new Set;for(let e=0;e<s.length;e+=1){const a=s[e];if(void 0!==a){for(;;){const e=o.has(a.value),s=null===t.compare||bt(t.compare,a.value);if(!e||!s)break;r.context.budget.consumeModifierSteps();const u=a.value,c=Nt(n,i,r);if(a.value=c,xt(a,"unique-rerolled"),vt(a),r.context.journal.record({type:"reroll",subject:"die",dieId:a.id,parentDieId:a.parentDieId,rollIndex:r.rollIndex,sourceNodeId:n.id,from:u,to:c,reason:t.once?"unique-once":"unique"}),t.once)break}o.add(a.value)}}}function Rt(e,t,n,i){const r=e.map((e,t)=>({index:t,value:e.value})).sort((e,t)=>e.value-t.value||e.index-t.index),s=("lowest"===n?r.slice(0,i):r.slice(Math.max(0,r.length-i))).map(e=>e.index);if("drop"===t)return s;const o=new Set(s);return r.filter(e=>!o.has(e.index)).map(e=>e.index)}function kt(e,t,n){const i=e.filter(e=>e.active),r=Rt(i,t.kind,t.selection,t.quantity);for(const e of r){const r=i[e];void 0!==r&&r.included&&(r.included=!1,xt(r,"dropped"),vt(r),n.context.journal.record({type:"exclude",subject:"die",dieId:r.id,parentDieId:r.parentDieId,rollIndex:n.rollIndex,sourceNodeId:r.sourceNodeId,reason:t.kind}))}}function _t(e,t,n){for(const i of e){if(!i.active)continue;let e;bt(t.success,i.value)?(e="success",xt(i,"target-success"),i.contribution=i.included?1:0):null!==t.failure&&bt(t.failure,i.value)?(e="failure",xt(i,"target-failure"),i.contribution=i.included?-1:0):(e="neutral",xt(i,"target-neutral"),i.contribution=0),n.context.journal.record({type:"classify",subject:"die",dieId:i.id,parentDieId:i.parentDieId,rollIndex:n.rollIndex,sourceNodeId:i.sourceNodeId,outcome:e})}}function Lt(e,t,n,i){const r="critical-success"===t.kind?n.maximum:n.minimum;for(const n of e)n.active&&(null===t.compare?n.value===r:bt(t.compare,n.value))&&(xt(n,t.kind),i.context.journal.record({type:"classify",subject:"die",dieId:n.id,parentDieId:n.parentDieId,rollIndex:i.rollIndex,sourceNodeId:n.sourceNodeId,outcome:t.kind}))}function Tt(e,t,n,i,r=[]){const s=gt(e,t.rollIndex),o="dice"===e.kind?"dice":"function"===e.kind?"function":"group"===e.kind?"group":"expression",a={id:s,sourceNodeId:e.id,rollIndex:t.rollIndex,kind:o,notation:It(t,e),span:e.span,value:n,contribution:n,included:!0,states:r.slice(),childIds:i};return t.context.budget.consumeResolvedGroups(),t.context.budget.consumeResultItems(),t.groups.push(a),t.groupById.set(s,a),s}function Mt(e,t){const n=t.program.diceSpecs.get(e.id);if(void 0===n)throw new s("Compiled dice specification is missing",{code:"UNSUPPORTED_NOTATION",input:t.plan.input,span:e.span,details:{nodeId:e.id}});const i=t.dice.length,r=[];for(let i=0;i<n.quantity;i+=1)r.push(Et(e,n,t,null,!1));const o=function(e,t,n,i,r){let s=e;for(const o of t)switch(o.kind){case"min":wt(e,o.value,r);break;case"max":At(e,o.value,r);break;case"explode":Ot(e,o,n,i,r);break;case"reroll":St(e,o,n,i,r);break;case"unique":yt(e,o,n,i,r);break;case"keep":case"drop":kt(e,o,r);break;case"target":_t(e,o,r);break;case"critical-success":case"critical-failure":Lt(e,o,i,r);break;case"sort":s=e.slice().sort((e,t)=>"ascending"===o.direction?e.value-t.value:t.value-e.value)}return s}(r,n.modifiers,e,n,t),a=D(r.reduce((e,t)=>e+t.contribution,0)),u=Tt(e,t,a,o.map(e=>e.id));return{value:a,rendered:t.renderOutput?`[${o.map(e=>e.value).join(", ")}]`:"",groupId:u,diceRange:{start:i,count:t.dice.length-i}}}function Ct(e,t,n){const i=t.groupById.get(e);if(void 0!==i&&i.included){i.included=!1,i.contribution=0,i.states.push("dropped"),t.context.journal.record({type:"exclude",subject:"group",groupId:i.id,rollIndex:t.rollIndex,sourceNodeId:i.sourceNodeId,reason:n,value:i.value});for(const e of i.childIds)t.groupById.has(e)&&Ct(e,t,n)}}function jt(e,t,n){e.included=!1,null!==e.evaluation.groupId&&Ct(e.evaluation.groupId,t,n);const i=e.evaluation.diceRange.start+e.evaluation.diceRange.count;for(let r=e.evaluation.diceRange.start;r<i;r+=1){const e=t.dice[r];void 0!==e&&(e.included&&(e.included=!1,xt(e,"dropped"),vt(e),t.context.journal.record({type:"exclude",subject:"die",dieId:e.id,parentDieId:e.parentDieId,rollIndex:t.rollIndex,sourceNodeId:e.sourceNodeId,reason:n})))}}function zt(e,t){const n=t.dice.length,i=e.expressions.map(e=>{const n=Pt(e,t);return{evaluation:n,value:n.value,included:!0}}),r=xe(e.modifiers),o=function(e,t,n){let i=e;for(const r of t)switch(r.kind){case"keep":case"drop":{const t=Rt(e,r.kind,r.selection,r.quantity);for(const i of t){const t=e[i];void 0!==t&&t.included&&jt(t,n,r.kind)}break}case"min":case"max":case"target":case"critical-success":case"critical-failure":case"explode":case"reroll":case"unique":throw new s(`Modifier ${r.kind} is not supported on roll groups`,{code:"UNSUPPORTED_GROUP_MODIFIER",input:n.plan.input,span:r.span,details:{modifier:r.kind}});case"sort":i=e.slice().sort((e,t)=>"ascending"===r.direction?e.value-t.value:t.value-e.value)}return i}(i,r,t),a=D(i.reduce((e,t)=>e+(t.included?t.value:0),0)),u=i.flatMap(e=>null===e.evaluation.groupId?[]:[e.evaluation.groupId]),c=o.flatMap(e=>null===e.evaluation.groupId?[]:[e.evaluation.groupId]),l=r.find(e=>"sort"===e.kind),d=void 0===l?[]:["ascending"===l.direction?"sorted-ascending":"sorted-descending"],p=Tt(e,t,a,c,d);return void 0!==l&&t.context.journal.record({type:"transform",subject:"group",groupId:p,rollIndex:t.rollIndex,sourceNodeId:e.id,from:u,to:c,reason:"ascending"===l.direction?"sort-ascending":"sort-descending"}),{value:a,rendered:t.renderOutput?`{${o.map(e=>e.evaluation.rendered).join(", ")}}`:"",groupId:p,diceRange:{start:n,count:t.dice.length-n}}}function Pt(e,t){switch(e.kind){case"number":{const n=Tt(e,t,e.value,[]);return{value:e.value,rendered:t.renderOutput?e.raw:"",groupId:n,diceRange:{start:t.dice.length,count:0}}}case"unary":{const n=Pt(e.operand,t),i="-"===e.operator?-n.value:n.value,r=Tt(e,t,i,null===n.groupId?[]:[n.groupId]);return{value:i,rendered:t.renderOutput?`${e.operator}${n.rendered}`:"",groupId:r,diceRange:n.diceRange}}case"binary":{const n=Pt(e.left,t),i=Pt(e.right,t),r=v("**"===e.operator?"^":e.operator,n.value,i.value,t.plan.input),s=Tt(e,t,r,[n.groupId,i.groupId].filter(e=>null!==e));return{value:r,rendered:t.renderOutput?`${n.rendered}${e.operator}${i.rendered}`:"",groupId:s,diceRange:{start:n.diceRange.start,count:n.diceRange.count+i.diceRange.count}}}case"parenthesized":{const n=Pt(e.expression,t),i=Tt(e,t,n.value,null===n.groupId?[]:[n.groupId]);return{value:n.value,rendered:t.renderOutput?`(${n.rendered})`:"",groupId:i,diceRange:n.diceRange}}case"function":{if("unary"===e.functionKind){const n=Pt(e.arguments[0],t),i=b(e.name,n.value,t.plan.input),r=Tt(e,t,i,null===n.groupId?[]:[n.groupId]);return{value:i,rendered:t.renderOutput?`${e.name}(${n.rendered})`:"",groupId:r,diceRange:n.diceRange}}const n=Pt(e.arguments[0],t),i=Pt(e.arguments[1],t),r=N(e.name,n.value,i.value,t.plan.input),s=Tt(e,t,r,[n.groupId,i.groupId].filter(e=>null!==e));return{value:r,rendered:t.renderOutput?`${e.name}(${n.rendered},${i.rendered})`:"",groupId:s,diceRange:{start:n.diceRange.start,count:n.diceRange.count+i.diceRange.count}}}case"dice":return Mt(e,t);case"group":return zt(e,t)}}function Ut(e,t){const n=[];for(let i=0;i<e.dice.length;i+=1){const r=e.dice[i];void 0!==r&&(r.active&&r.included&&e.context.journal.record({type:"include",subject:"die",dieId:r.id,parentDieId:r.parentDieId,rollIndex:r.rollIndex,sourceNodeId:r.sourceNodeId,contribution:r.contribution}),t&&n.push({id:r.id,sourceNodeId:r.sourceNodeId,parentDieId:r.parentDieId,rollIndex:r.rollIndex,rollDieIndex:i+1,groupId:r.groupId,sides:r.sides,rawValue:r.rawValue,value:r.value,contribution:r.contribution,included:r.included&&r.active,states:r.states.slice()}))}return n}function Vt(e,t){const n=[];for(const i of e.groups)i.included&&e.context.journal.record({type:"include",subject:"group",groupId:i.id,rollIndex:i.rollIndex,sourceNodeId:i.sourceNodeId,value:i.value,contribution:i.contribution}),t&&n.push({id:i.id,sourceNodeId:i.sourceNodeId,rollIndex:i.rollIndex,kind:i.kind,notation:i.notation,span:i.span,value:i.value,contribution:i.contribution,included:i.included,states:i.states.slice(),childIds:i.childIds});return n}function Ft(e){let t=!1,n=0,i=0;for(const r of e){const e=r.states.includes("target-success"),s=r.states.includes("target-failure");(e||s||r.states.includes("target-neutral"))&&(t=!0),r.active&&r.included&&e?n+=1:r.active&&r.included&&s&&(i+=1)}return t?{successes:n,failures:i,netSuccesses:n-i}:null}function $t(e){let t=!1,n=0,i=0;for(const r of e)null!==r.pool&&(t=!0,n+=r.pool.successes,i+=r.pool.failures);return t?{successes:n,failures:i,netSuccesses:n-i}:null}function Gt(e,t,n){return void 0!==t.replay?ft({resolvedLimits:t.limits,replay:t.replay,planFingerprint:e.planFingerprint,collectEvents:n}):void 0!==t.seed?ft({resolvedLimits:t.limits,seed:t.seed,planFingerprint:e.planFingerprint,...void 0===t.randomAlgorithm?{}:{randomAlgorithm:t.randomAlgorithm},collectEvents:n}):ft({resolvedLimits:t.limits,planFingerprint:e.planFingerprint,...void 0===t.randomAlgorithm?{}:{randomAlgorithm:t.randomAlgorithm},collectEvents:n})}function qt(e){const t=e.budget.snapshot();return{rolls:t.rolls,initialDice:t.initialDice,generatedDice:t.generatedDice,randomCalls:t.randomCalls,modifierSteps:t.modifierSteps,events:t.events,resolvedGroups:t.resolvedGroups,resultItems:t.resultItems}}function Yt(e,t=1){e.budget.consumeEvents(t),e.budget.consumeResultItems(t)}function Xt(e,t,n,i){let r;switch(e.kind){case"number":r=e.value;break;case"unary":{const s=Xt(e.operand,t,n,i);r="-"===e.operator?-s:s;break}case"binary":r=v("**"===e.operator?"^":e.operator,Xt(e.left,t,n,i),Xt(e.right,t,n,i),i);break;case"parenthesized":r=Xt(e.expression,t,n,i);break;case"function":r="unary"===e.functionKind?b(e.name,Xt(e.arguments[0],t,n,i),i):N(e.name,Xt(e.arguments[0],t,n,i),Xt(e.arguments[1],t,n,i),i);break;case"dice":{const o=t.diceSpecs.get(e.id);if(void 0===o)throw new s("Compiled dice specification is missing",{code:"UNSUPPORTED_NOTATION",input:i,span:e.span,details:{nodeId:e.id}});let a=0;for(let t=0;t<o.quantity;t+=1)n.budget.consumeInitialDice(),n.budget.consumeResultItems(),a+=Dt(e,o,n),Yt(n,2);r=D(a);break}case"group":{let s=0;for(const r of e.expressions)s+=Xt(r,t,n,i);r=D(s);break}}return function(e){e.budget.consumeResolvedGroups(),e.budget.consumeResultItems(),Yt(e)}(n),r}function Wt(e,t,n){const i="full"===n,r=je(e);if(!i&&function(e){for(const t of e.diceSpecs.values())if(t.modifiers.length>0)return!1;for(const t of e.postOrder)if("group"===t.kind&&t.modifiers.length>0)return!1;return!0}(r))return function(e,t,n){const i=Gt(e,n,!1);i.budget.consumeRolls(e.rollCount);const r=[];for(let n=1;n<=e.rollCount;n+=1)i.budget.consumeResultItems(),r.push({index:n,total:D(Xt(t.ast,t,i,e.input)),pool:null});return{type:"dice-roll-summary",schemaVersion:3,input:e.input,notation:e.notation,normalizedNotation:e.normalizedNotation,comment:e.comment,total:D(r.reduce((e,t)=>e+t.total,0)),replay:i.replay,stats:qt(i),rolls:r,pool:null}}(e,r,t);const s=Gt(e,t,i);s.budget.consumeRolls(e.rollCount);const o=r.ast,a=[],u=[],c=[],l=[],d=[];for(let t=1;t<=e.rollCount;t+=1){s.budget.consumeResultItems();const n=s.journal.length,p=a.length,m=u.length,h={context:s,plan:e,program:r,rollIndex:t,dice:[],groups:[],groupById:new Map,renderOutput:i,nextDieIndex:0},f=Pt(o,h),g=D(f.value),I=Ut(h,i),x=Vt(h,i),v=Ft(h.dice);if(i){a.push(...I),u.push(...x);const i=e.notation.length+2+f.rendered.length+3+String(g).length;s.budget.assertOutputLength(i),d.push(`${e.notation}: ${f.rendered} = ${g}`),c.push({index:t,total:g,pool:v,diceRange:{start:p,count:I.length},groupRange:{start:m,count:x.length},eventRange:{start:n,count:s.journal.length-n}})}else l.push({index:t,total:g,pool:v})}const p=s.journal.toArray(),m=i?c:l,h=D(m.reduce((e,t)=>e+t.total,0)),f={schemaVersion:3,input:e.input,notation:e.notation,normalizedNotation:e.normalizedNotation,comment:e.comment,total:h,replay:s.replay,stats:qt(s),pool:$t(m)};if(!i)return{...f,type:"dice-roll-summary",rolls:l};const g=function(e,t,n){if(1===e.length){const t=e[0]??"";return n.budget.assertOutputLength(t.length),t}const i=`Total: ${t}`;let r=i.length;for(let t=0;t<e.length;t+=1){const n=e[t]??"";r+=String(t+1).length+2+n.length+1}return n.budget.assertOutputLength(r),[...e.map((e,t)=>`${t+1}. ${e}`),i].join("\n")}(d,h,s);return{...f,type:"dice-roll",output:g,rolls:c,groups:u,dice:a,events:p}}function Kt(e,t){const n=Wt(e,t,"full");if("dice-roll"!==n.type)throw new TypeError("Full execution returned an invalid result kind");return n}function Bt(e,t){const n=Wt(e,t,"summary");if("dice-roll-summary"!==n.type)throw new TypeError("Summary execution returned an invalid result kind");return n}const Qt=Number.MAX_SAFE_INTEGER;function Ht(e,t,n){const i=t??n;if("number"!=typeof i||!Number.isSafeInteger(i)||i<0)throw new RangeError(`${e} must be a non-negative safe integer`);return i}function Jt(e){return"object"==typeof e&&null!==e}function Zt(e,t){return function(e,t){return t in e}(e,t)?e[t]:void 0}function en(e,t,n){try{if(!Jt(e)||Array.isArray(e))throw new s("Dice options must be a non-null object",{code:n});return Zt(e,t)}catch(e){if(o(e))throw e;throw new s(`Unable to read dice option ${t}`,{code:n,details:{option:t}})}}function tn(e){const t=en(e,"limits","INVALID_LIMIT"),n=en(e,"seed","INVALID_REPLAY"),i=en(e,"replay","INVALID_REPLAY"),r=en(e,"randomAlgorithm","INVALID_REPLAY");if(void 0!==n&&"string"!=typeof n&&"number"!=typeof n)throw new s("Seeds must be finite numbers or strings",{code:"INVALID_SEED"});if(void 0!==r&&"mt19937"!==r&&"xoshiro128ss"!==r)throw new s("The requested random algorithm is not supported",{code:"INVALID_REPLAY"});if(void 0!==i&&(void 0!==n||void 0!==r))throw new s("Replay cannot be combined with seed or randomAlgorithm",{code:"INVALID_REPLAY"});return{limits:t,randomAlgorithm:r,replay:i,seed:n}}function nn(e,t){return void 0===t?e:function(e,t={}){return Ve(t),$e({maxInputLength:Fe(e,t,"maxInputLength"),maxAstDepth:Fe(e,t,"maxAstDepth"),maxAstNodes:Fe(e,t,"maxAstNodes"),maxRolls:Fe(e,t,"maxRolls"),maxInitialDice:Fe(e,t,"maxInitialDice"),maxGeneratedDice:Fe(e,t,"maxGeneratedDice"),maxRandomCalls:Fe(e,t,"maxRandomCalls"),maxEvents:Fe(e,t,"maxEvents"),maxSides:Fe(e,t,"maxSides"),maxSeedLength:Fe(e,t,"maxSeedLength"),maxModifierSteps:Fe(e,t,"maxModifierSteps"),maxResolvedGroups:Fe(e,t,"maxResolvedGroups"),maxResultItems:Fe(e,t,"maxResultItems"),maxOutputLength:Fe(e,t,"maxOutputLength")})}(e,t)}function rn(e,t){return ot(e,t.planFingerprint)}class sn{limits;freezeResults;randomAlgorithm;inputCache;programCache;ownedPlans=new WeakSet;constructor(t){const n=function(e){const t=en(e,"limits","INVALID_LIMIT"),n=en(e,"cache","INVALID_LIMIT"),i=en(e,"freezeResults","INVALID_LIMIT"),r=en(e,"randomAlgorithm","INVALID_REPLAY");if(void 0!==i&&"development"!==i&&"always"!==i&&"never"!==i)throw new s("freezeResults uses an unsupported mode",{code:"INVALID_LIMIT"});if(void 0!==r&&"mt19937"!==r&&"xoshiro128ss"!==r)throw new s("The requested random algorithm is not supported",{code:"INVALID_REPLAY"});return{cache:n,freezeResults:i,limits:t,randomAlgorithm:r}}(t);this.limits=Ge(n.limits??{}),this.freezeResults=n.freezeResults??"never",this.randomAlgorithm=n.randomAlgorithm??"mt19937";const i=function(e){if(!1===e)return{maxInputEntries:0,maxProgramEntries:0,maxProgramNodes:0};let t,n,i,r;try{if(void 0!==e&&(!Jt(e)||Array.isArray(e)))throw new RangeError("cache must be false or a cache options object");t=void 0===e?{}:e}catch(e){if(e instanceof RangeError)throw e;throw new RangeError("cache options could not be read")}try{n=Zt(t,"maxInputEntries"),i=Zt(t,"maxProgramEntries"),r=Zt(t,"maxProgramNodes")}catch{throw new RangeError("cache options could not be read")}return{maxInputEntries:Ht("maxInputEntries",n,500),maxProgramEntries:Ht("maxProgramEntries",i,200),maxProgramNodes:Ht("maxProgramNodes",r,1e5)}}(n.cache);this.inputCache=new e(i.maxInputEntries,Qt),this.programCache=new e(i.maxProgramEntries,i.maxProgramNodes)}clearCache(){this.inputCache.clear(),this.programCache.clear()}getCacheStats(){const e=this.inputCache.stats(),t=this.programCache.stats();return{inputEntries:e.entries,programEntries:t.entries,programNodes:t.weight,hits:e.hits+t.hits,misses:e.misses+t.misses,evictions:e.evictions+t.evictions}}compile(e,t={}){if("string"!=typeof e)throw new s("Dice input must be a string",{code:"INVALID_NOTATION",details:{receivedType:typeof e}});const n=nn(this.limits,function(e){return en(e,"limits","INVALID_LIMIT")}(t));if(e.length>n.maxInputLength)throw new s("Dice input exceeds the configured length limit",{code:"INPUT_TOO_LONG",input:e,details:{actual:e.length,limit:n.maxInputLength}});const i=function(e,t){return`${function(e){return[e.maxInputLength,e.maxAstDepth,e.maxAstNodes,e.maxRolls,e.maxInitialDice,e.maxSides,e.maxModifierSteps].join(":")}(t)}\0${e}`}(e,n),r=this.inputCache.get(i);if(void 0!==r)return r;const o=Oe(e,n),a=o.normalized.notation;let u=this.programCache.get(a);void 0===u&&(u=Se(a,e,n),this.programCache.set(a,u,u.nodeCount));const c=Ce(o,n,u);return this.ownedPlans.add(c),this.inputCache.set(i,c),c}inspect(e,t={}){try{return{type:"dice-notation-inspection",input:(n=this.compile(e,t)).input,notation:n.notation,normalizedNotation:n.normalizedNotation,comment:n.comment,isValid:!0,plan:n,groups:n.groups,cost:n.cost,error:null}}catch(t){return function(e,t){const n="string"==typeof e?e:"",i=o(t)?t:new s("Invalid dice notation",{code:"INVALID_NOTATION",input:n,details:{cause:t instanceof Error?t.message:"Unknown compiler error"}}),r="INPUT_TOO_LONG"===i.code?{notation:"",normalizedNotation:"",comment:""}:ue(n);return{type:"dice-notation-inspection",input:n,notation:r.notation,normalizedNotation:r.normalizedNotation,comment:r.comment,isValid:!1,plan:null,groups:[],cost:null,error:i}}(e,t)}var n}normalize(e){return ae(e)}roll(e,t={}){const n=tn(t),i=nn(this.limits,n.limits),r=this.resolvePlan(e,i),s=void 0!==n.replay?Kt(r,{limits:i,replay:rn(n.replay,r)}):void 0===n.seed?Kt(r,{limits:i,randomAlgorithm:n.randomAlgorithm??this.randomAlgorithm}):Kt(r,{limits:i,seed:n.seed,randomAlgorithm:n.randomAlgorithm??this.randomAlgorithm});return f(this.freezeResults)?function(e){return e.rolls.forEach(p),e.dice.forEach(u),e.groups.forEach(l),e.events.forEach(c),Object.freeze(e.rolls),Object.freeze(e.dice),Object.freeze(e.groups),Object.freeze(e.events),Object.freeze(e.replay),Object.freeze(e.stats),d(e.pool),Object.freeze(e)}(s):s}rollSummary(e,t={}){const n=tn(t),i=nn(this.limits,n.limits),r=this.resolvePlan(e,i),s=void 0!==n.replay?Bt(r,{limits:i,replay:rn(n.replay,r)}):void 0===n.seed?Bt(r,{limits:i,randomAlgorithm:n.randomAlgorithm??this.randomAlgorithm}):Bt(r,{limits:i,seed:n.seed,randomAlgorithm:n.randomAlgorithm??this.randomAlgorithm});return f(this.freezeResults)?function(e){return e.rolls.forEach(m),Object.freeze(e.rolls),Object.freeze(e.replay),Object.freeze(e.stats),d(e.pool),Object.freeze(e)}(s):s}verify(e,t={}){return this.inspect(e,t).isValid}resolvePlan(e,t){if("string"==typeof e)return this.compile(e,{limits:t});if(function(e){return pe.has(e)}(e))return this.ownedPlans.has(e)&&t===this.limits||function(e,t){if(new le(t).assertInputLength(e.input),e.rollCount>t.maxRolls)throw new s("Roll count exceeds the execution limit",{code:"TOO_MANY_ROLLS",input:e.input,details:{rollCount:e.rollCount,limit:t.maxRolls}});ye(e.input,e.notation,e.rollCount,je(e),t)}(e,t),e;const n=function(e){try{if(!Jt(e)||"roll-plan"!==Zt(e,"type")||3!==Zt(e,"schemaVersion")||1!==Zt(e,"compilerVersion"))throw new s("Roll plan is invalid or uses an unsupported schema",{code:"UNSUPPORTED_NOTATION"});const t=Zt(e,"input"),n=Zt(e,"planFingerprint");if("string"!=typeof t||"string"!=typeof n||32!==n.length||!/^[0-9a-f]{32}$/u.test(n))throw new s("Roll plan envelope is malformed",{code:"UNSUPPORTED_NOTATION"});return{input:t,planFingerprint:n}}catch(e){if(o(e))throw e;throw new s("Roll plan could not be read safely",{code:"UNSUPPORTED_NOTATION",details:{cause:e instanceof Error?e.message:"External plan access failed"}})}}(e),i=this.compile(n.input,{limits:t});if(n.planFingerprint!==i.planFingerprint)throw new s("Roll plan does not match its source input",{code:"UNSUPPORTED_NOTATION",input:n.input,details:{expectedFingerprint:i.planFingerprint,receivedFingerprint:n.planFingerprint}});return i}}function on(e={}){return new sn(e)}const an=on();exports.DEFAULT_DICE_LIMITS=Pe,exports.DiceRollError=s,exports.compileRpgDice=function(e,t={}){return an.compile(e,t)},exports.createDiceEngine=on,exports.inspectRpgDiceNotation=function(e,t={}){return an.inspect(e,t)},exports.isDiceRollError=o,exports.isDiceRollErrorData=a,exports.normalizeRpgDiceNotation=ae,exports.rollRpgDice=function(e,t={}){return an.roll(e,t)},exports.rollRpgDiceSummary=function(e,t={}){return an.rollSummary(e,t)},exports.verifyRpgDiceNotation=function(e,t={}){return an.verify(e,t)};
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './v3/index.cjs';
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './v3/index.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* @erpg/dicecore - ERPG dice core with ergonomic RPG notation, grouped rolls, structured UI data, deterministic replay, and safe parse-only inspection.
|
|
3
|
+
*
|
|
4
|
+
* @version 3.1.0
|
|
5
|
+
* @license MIT
|
|
6
|
+
* @author Arkanus
|
|
7
|
+
* @link https://github.com/arkanus-app/rpg-dice-roller
|
|
8
|
+
*/
|
|
9
|
+
class e{maxEntries;maxWeight;entries=new Map;currentWeight=0;hitCount=0;missCount=0;evictionCount=0;constructor(e,t){this.maxEntries=e,this.maxWeight=t}get(e){const t=this.entries.get(e);if(void 0!==t)return this.hitCount+=1,this.entries.delete(e),this.entries.set(e,t),t.value;this.missCount+=1}set(e,t,n=1){const i=this.entries.get(e);void 0!==i&&(this.entries.delete(e),this.currentWeight-=i.weight),0===this.maxEntries||0===this.maxWeight||n>this.maxWeight||(this.entries.set(e,{value:t,weight:n}),this.currentWeight+=n,this.evictOverflow())}clear(){this.entries.clear(),this.currentWeight=0,this.hitCount=0,this.missCount=0,this.evictionCount=0}stats(){return{entries:this.entries.size,weight:this.currentWeight,hits:this.hitCount,misses:this.missCount,evictions:this.evictionCount}}evictOverflow(){for(;this.entries.size>this.maxEntries||this.currentWeight>this.maxWeight;){const e=this.entries.entries().next().value;if(void 0===e)return;const[t,n]=e;this.entries.delete(t),this.currentWeight-=n.weight,this.evictionCount+=1}}}const t=new Set(["DICE_NOTATION_REQUIRED","INPUT_TOO_LONG","AST_TOO_DEEP","TOO_MANY_NODES","TOO_MANY_ROLLS","TOO_MANY_INITIAL_DICE","GENERATED_DICE_LIMIT_EXCEEDED","RANDOM_BUDGET_EXCEEDED","EVENT_LIMIT_EXCEEDED","MODIFIER_STEP_LIMIT_EXCEEDED","RESOLVED_GROUP_LIMIT_EXCEEDED","RESULT_LIMIT_EXCEEDED","OUTPUT_LIMIT_EXCEEDED","DICE_SIDES_LIMIT_EXCEEDED","INVALID_NOTATION","UNSUPPORTED_NOTATION","UNSUPPORTED_GROUP_MODIFIER","NON_TERMINATING_MODIFIER","IMPOSSIBLE_UNIQUE","ROLL_EXECUTION_LIMIT","RNG_UNAVAILABLE","INVALID_SEED","INVALID_REPLAY","REPLAY_PLAN_MISMATCH","INVALID_LIMIT","UNSUPPORTED_REPLAY_VERSION","NON_FINITE_RESULT","INVALID_ERROR_DATA"]);function n(e){if("object"!=typeof e||null===e)return!1;try{return!Array.isArray(e)}catch{return!1}}function i(e,t){if(null===e||"string"==typeof e||"boolean"==typeof e)return!0;if("number"==typeof e)return Number.isFinite(e);if("object"!=typeof e)return!1;if(t.has(e))return!1;const n=new Set(t);n.add(e);try{return Array.isArray(e)?e.every(e=>i(e,n)):Object.keys(e).every(t=>i(e[t],n))}catch{return!1}}function r(e){return n(e)&&i(e,new Set)}class s extends Error{code;span;input;details;constructor(e,t){super(e),this.name="DiceRollError",this.code=t.code,this.span=t.span??null,this.input=t.input??"",this.details=t.details??{}}static fromJSON(e){if(!a(e))throw new s("Value is not valid serialized dice error data",{code:"INVALID_ERROR_DATA"});return new s(e.message,{code:e.code,span:e.span,input:e.input,details:e.details})}toJSON(){return{name:"DiceRollError",code:this.code,message:this.message,span:this.span,input:this.input,details:this.details}}}function o(e){return e instanceof s}function a(e){if(!n(e))return!1;try{return"DiceRollError"===e.name&&"string"==typeof e.code&&t.has(e.code)&&"string"==typeof e.message&&(null===e.span||function(e){if(!n(e))return!1;try{return Number.isSafeInteger(e.start)&&Number.isSafeInteger(e.end)&&"number"==typeof e.start&&"number"==typeof e.end&&e.start>=0&&e.end>=e.start}catch{return!1}}(e.span))&&"string"==typeof e.input&&r(e.details)}catch{return!1}}function u(e){Object.freeze(e.states),Object.freeze(e)}function c(e){"transform"===e.type&&"group"===e.subject&&(Object.freeze(e.from),Object.freeze(e.to)),Object.freeze(e)}function l(e){Object.freeze(e.span),Object.freeze(e.states),Object.freeze(e.childIds),Object.freeze(e)}function d(e){null!==e&&Object.freeze(e)}function p(e){Object.freeze(e.diceRange),Object.freeze(e.groupRange),Object.freeze(e.eventRange),d(e.pool),Object.freeze(e)}function m(e){d(e.pool),Object.freeze(e)}function h(e){Object.freeze(e.span),Object.freeze(e.childIds),Object.freeze(e)}function f(e){if("always"===e)return!0;if("never"===e)return!1;const t=globalThis;return"development"===t.process?.env?.NODE_ENV}const g="decimal12-v1";function I(e,t){if(!Number.isFinite(e))throw new s("Dice expression produced a non-finite result",{code:"NON_FINITE_RESULT",input:t,details:{value:String(e)}});return Object.is(e,-0)?0:e}function x(e,t){const n=I(e,t);return I(Number.isSafeInteger(n)?n:Number(n.toPrecision(12)),t)}function v(e,t,n,i){let r;switch(e){case"+":r=t+n;break;case"-":r=t-n;break;case"*":r=t*n;break;case"/":r=t/n;break;case"%":r=t%n;break;case"^":r=t**n}return x(r,i)}function b(e,t,n){let i;switch(e){case"abs":i=Math.abs(t);break;case"ceil":i=Math.ceil(t);break;case"cos":i=Math.cos(t);break;case"exp":i=Math.exp(t);break;case"floor":i=Math.floor(t);break;case"log":i=Math.log(t);break;case"round":i=Math.round(t);break;case"sign":i=Math.sign(t);break;case"sin":i=Math.sin(t);break;case"sqrt":i=Math.sqrt(t);break;case"tan":i=Math.tan(t)}return x(i,n)}function N(e,t,n,i){let r;switch(e){case"max":r=Math.max(t,n);break;case"min":r=Math.min(t,n);break;case"pow":r=Math.pow(t,n)}return x(r,i)}function E(e){const t=Number(x(e,"").toFixed(2));return Object.is(t,-0)?0:t}function w(e,t){return`${e}@${t.start}:${t.end}`}const D=["floor","round","sqrt","ceil","sign","abs","cos","exp","log","sin","tan","pow","max","min","dF","cs","cf"],A=Object.freeze({"(":"left-parenthesis",")":"right-parenthesis","{":"left-brace","}":"right-brace",",":"comma",".":"dot","!":"bang"});function O(e,t){return{start:e,end:t}}function S(e,t,n,i){throw new s(t,{code:"INVALID_NOTATION",span:n,input:e,details:i})}function y(e){return void 0!==e&&e>="0"&&e<="9"}function R(e){if(void 0===e)return!1;const t=e.charCodeAt(0);return 9===t||10===t||11===t||12===t||13===t||32===t||160===t||5760===t||t>=8192&&t<=8202||8232===t||8233===t||8239===t||8287===t||12288===t||65279===t}function k(e){if(void 0===e)return!1;const t=e.charCodeAt(0);return t>=65&&t<=90||t>=97&&t<=122}function _(e){return"+"===e||"-"===e||"*"===e||"/"===e||"%"===e||"^"===e}function L(e,t){let n=t;for(;y(e[n]);)n+=1;if("."===e[n]&&y(e[n+1]))for(n+=1;y(e[n]);)n+=1;const i=e.slice(t,n),r=Number(i);return Number.isFinite(r)?{kind:"number",lexeme:i,value:r,span:O(t,n)}:S(e,`Numeric literal is not finite at offset ${t}`,O(t,n),{found:i})}function T(e,t){const n=D.find(n=>e.startsWith(n,t));if(void 0!==n)return{kind:"identifier",lexeme:n,value:n,span:O(t,t+n.length)};const i=e[t];return void 0!==i&&"dkrusfpolha".includes(i)?{kind:"identifier",lexeme:i,value:i,span:O(t,t+1)}:S(e,`Unexpected identifier at offset ${t}`,O(t,t+1),{found:i??""})}function M(e,t,n){const i=O(n,n+t.length);switch(e){case"left-parenthesis":case"right-parenthesis":case"left-brace":case"right-brace":case"comma":case"dot":case"bang":return{kind:e,lexeme:t,span:i};default:throw new Error("Invalid punctuation token kind")}}const C=["abs","ceil","cos","exp","floor","log","round","sign","sin","sqrt","tan"],j=["pow","max","min"],z={"+":10,"-":10,"*":20,"/":20,"%":20,"^":30,"**":30},P=Object.freeze({maxDepth:Number.MAX_SAFE_INTEGER,maxNodes:Number.MAX_SAFE_INTEGER});function U(e){return C.some(t=>t===e)}function V(e){return j.some(t=>t===e)}function F(e,t){return{start:e.start,end:t.end}}class ${input;tokens;cursor=0;recursionDepth=0;limits;constructor(e,t){this.input=e,this.limits=t,this.tokens=function(e){const t=[];let n=0;for(;n<e.length;){const i=e[n];if(R(i))n+=1;else if(y(i)){const i=L(e,n);t.push(i),n=i.span.end}else if(k(i)){const i=T(e,n);t.push(i),n=i.span.end}else if(e.startsWith("**",n))t.push({kind:"operator",lexeme:"**",value:"**",span:O(n,n+2)}),n+=2;else if(e.startsWith("<=",n)||e.startsWith(">=",n)||e.startsWith("<>",n)){const i=e.slice(n,n+2);"<="!==i&&">="!==i&&"<>"!==i||t.push({kind:"comparison",lexeme:i,value:i,span:O(n,n+2)}),n+=2}else if(_(i))t.push({kind:"operator",lexeme:i,value:i,span:O(n,n+1)}),n+=1;else if("="===i||"<"===i||">"===i)t.push({kind:"comparison",lexeme:i,value:i,span:O(n,n+1)}),n+=1;else{const r=void 0===i?void 0:A[i];if(void 0===r)return S(e,`Unexpected character at offset ${n}`,O(n,n+1),{found:i??""});t.push(M(r,i??"",n)),n+=1}}return t.push({kind:"eof",lexeme:"",span:O(e.length,e.length)}),t}(e)}parse(){if(0===this.input.length)return this.fail("Dice notation is required",this.current().span,{});const e=this.parseExpression(0),t=this.current();return"eof"!==t.kind?this.fail(`Unexpected token "${t.lexeme}" at offset ${t.span.start}`,t.span,{found:t.lexeme,expected:"end of notation"}):(this.assertTreeLimits(e),e)}current(e=0){const t=this.cursor+e,n=this.tokens[t];return void 0!==n?n:{kind:"eof",lexeme:"",span:{start:this.input.length,end:this.input.length}}}consume(){const e=this.current();return"eof"!==e.kind&&(this.cursor+=1),e}fail(e,t,n){throw new s(e,{code:"INVALID_NOTATION",span:t,input:this.input,details:n})}failLimit(e,t,n,i){throw new s("AST_TOO_DEEP"===e?"AST depth exceeds the parser limit":"AST node count exceeds the parser limit",{code:e,span:i,input:this.input,details:{limit:t,actual:n}})}enterExpression(){this.recursionDepth+=1,this.recursionDepth>this.limits.maxDepth&&this.failLimit("AST_TOO_DEEP",this.limits.maxDepth,this.recursionDepth,this.current().span)}leaveExpression(){this.recursionDepth-=1}countedChildren(e){switch(e.kind){case"number":case"compare-point":case"drop":case"keep":case"min":case"max":case"sort":return[];case"unary":return[e.operand];case"binary":return[e.left,e.right];case"parenthesized":return[e.expression];case"function":return e.arguments;case"dice":return"standard"===e.diceKind?[e.quantity,e.sides,...e.modifiers]:[e.quantity,...e.modifiers];case"group":return[...e.expressions,...e.modifiers];case"explode":case"reroll":case"unique":case"critical-success":case"critical-failure":return null===e.compare?[]:[e.compare];case"target":return null===e.failure?[e.success]:[e.success,e.failure]}}assertTreeLimits(e){const t=[{node:e,depth:1}];let n=0;for(;t.length>0;){const e=t.pop();if(void 0===e)break;n+=1,n>this.limits.maxNodes&&this.failLimit("TOO_MANY_NODES",this.limits.maxNodes,n,e.node.span),e.depth>this.limits.maxDepth&&this.failLimit("AST_TOO_DEEP",this.limits.maxDepth,e.depth,e.node.span);const i=this.countedChildren(e.node);for(let n=i.length-1;n>=0;n-=1){const r=i[n];void 0!==r&&t.push({node:r,depth:e.depth+1})}}}expect(e,t){const n=this.current();return n.kind!==e?this.fail(`Expected ${t} at offset ${n.span.start}`,n.span,{found:n.lexeme,expected:t}):this.consume()}isIdentifier(e,t=0){const n=this.current(t);return"identifier"===n.kind&&n.value===e}parseExpression(e){this.enterExpression();try{let t=this.parsePrefix();for(;;){const n=this.current();if("operator"!==n.kind)break;const i=z[n.value];if(i<e)break;this.consume();const r="^"===n.value||"**"===n.value,s=this.parseExpression(r?i:i+1),o=F(t.span,s.span);t={kind:"binary",id:w("binary",o),span:o,operator:n.value,left:t,right:s}}return t}finally{this.leaveExpression()}}parsePrefix(){const e=this.current();if("operator"===e.kind&&("+"===e.value||"-"===e.value)){const t=e.value;this.consume();const n=this.parseExpression(25),i=F(e.span,n.span);return{kind:"unary",id:w("unary",i),span:i,operator:t,operand:n}}return this.parsePrimary()}parsePrimary(){const e=this.current();if("number"===e.kind)return this.parseDiceSuffix(this.parseNumber(null));if("left-parenthesis"===e.kind)return this.parseDiceSuffix(this.parseParenthesized());if("left-brace"===e.kind)return this.parseGroup();if("identifier"===e.kind){if("d"===e.value||"dF"===e.value)return this.parseDice(null);if(U(e.value)||V(e.value))return this.parseFunction()}return this.fail(`Expected an expression at offset ${e.span.start}`,e.span,{found:e.lexeme,expected:"number, dice, group, parenthesis, or function"})}parseNumber(e){const t=null===e?null:this.tokens[this.cursor-1],n=this.expect("number","a number");if("number"!==n.kind)return this.fail("Internal number token mismatch",n.span,{});const i=null==t?n.span:F(t.span,n.span),r="-"===e?-1:1,s=null===e?n.lexeme:`${e}${n.lexeme}`;return{kind:"number",id:w("number",i),span:i,value:r*n.value,raw:s,implicit:!1}}implicitOne(e){const t={start:e,end:e};return{kind:"number",id:w("implicit-number",t),span:t,value:1,raw:"1",implicit:!0}}parseParenthesized(){const e=this.expect("left-parenthesis",'"("'),t=this.parseExpression(0),n=this.expect("right-parenthesis",'")"'),i=F(e.span,n.span);return{kind:"parenthesized",id:w("parenthesized",i),span:i,expression:t}}parseDiceSuffix(e){return this.isIdentifier("d")||this.isIdentifier("dF")?(this.validateDiceArgument(e,"quantity"),this.parseDice(e)):e}validateDiceArgument(e,t){"number"===e.kind&&(!Number.isInteger(e.value)||e.value<1||e.raw.length>1&&e.raw.startsWith("0"))&&this.fail(`Dice ${t} must be a positive integer`,e.span,{value:e.value,argument:t})}parseDice(e){const t=this.consume();if("identifier"!==t.kind||"d"!==t.value&&"dF"!==t.value)return this.fail("Expected a dice marker",t.span,{found:t.lexeme});const n=e??this.implicitOne(t.span.start),i=e?.span??t.span;if("dF"===t.value){let e=2,r=t.span;if("dot"===this.current().kind){this.consume();const t=this.expect("number","Fudge variant 1 or 2");if("number"!==t.kind||1!==t.value&&2!==t.value||1!==t.lexeme.length)return this.fail("Fudge dice variant must be 1 or 2",t.span,{found:t.lexeme});e=t.value,r=t.span}const s=this.parseModifiers(),o=F(i,0===s.length?r:s[s.length-1]?.span??r);return{kind:"dice",diceKind:"fudge",id:w("dice",o),span:o,quantity:n,variant:e,modifiers:s}}const r=this.current();if("operator"===r.kind&&"%"===r.value){this.consume();const e=this.parseModifiers(),t=F(i,0===e.length?r.span:e[e.length-1]?.span??r.span);return{kind:"dice",diceKind:"percentile",id:w("dice",t),span:t,quantity:n,modifiers:e}}const s="left-parenthesis"===r.kind?this.parseParenthesized():this.parseNumber(null);this.validateDiceArgument(s,"sides");const o=this.parseModifiers(),a=F(i,0===o.length?s.span:o[o.length-1]?.span??s.span);return{kind:"dice",diceKind:"standard",id:w("dice",a),span:a,quantity:n,sides:s,modifiers:o}}parseFunction(){const e=this.consume();if("identifier"!==e.kind)return this.fail("Expected a function name",e.span,{});this.expect("left-parenthesis",'"("');const t=this.parseExpression(0);if(U(e.value)){const n=this.expect("right-parenthesis",'")"'),i=F(e.span,n.span);return{kind:"function",functionKind:"unary",name:e.value,arguments:[t],id:w("function",i),span:i}}this.expect("comma",'","');const n=this.parseExpression(0),i=this.expect("right-parenthesis",'")"'),r=F(e.span,i.span);return V(e.value)?{kind:"function",functionKind:"binary",name:e.value,arguments:[t,n],id:w("function",r),span:r}:this.fail("Unsupported function",e.span,{found:e.value})}parseGroup(){const e=this.expect("left-brace",'"{"'),t=[this.parseExpression(0)];for(;"comma"===this.current().kind;)this.consume(),t.push(this.parseExpression(0));const n=this.expect("right-brace",'"}"'),i=this.parseModifiers(),r=0===i.length?n.span:i[i.length-1]?.span??n.span,s=F(e.span,r);return{kind:"group",id:w("group",s),span:s,expressions:t,modifiers:i}}isComparePointStart(){const e=this.current();return"comparison"===e.kind||"bang"===e.kind&&"comparison"===this.current(1).kind&&"="===this.current(1).lexeme}parseComparePoint(){const e=this.current();let t,n;if("bang"===e.kind){this.consume();const i=this.expect("comparison",'"=" after "!"');if("comparison"!==i.kind||"="!==i.value)return this.fail('Expected "=" after "!"',i.span,{found:i.lexeme});t="!=",n=F(e.span,i.span)}else{if("comparison"!==e.kind)return this.fail("Expected a comparison operator",e.span,{found:e.lexeme});this.consume(),t=e.value,n=e.span}let i=null;const r=this.current();"operator"!==r.kind||"+"!==r.value&&"-"!==r.value||(i=r.value,this.consume());const s=this.parseNumber(i),o=F(n,s.span);return{kind:"compare-point",id:w("compare-point",o),span:o,operator:t,value:s.value}}parseModifiers(){const e=[];for(;;){const t=this.parseModifier();if(null===t)break;e.push(t)}return e}parseModifier(){const e=this.current();if("bang"===e.kind)return this.parseExplode();if("comparison"===e.kind)return this.parseTarget();if("identifier"!==e.kind)return null;switch(e.value){case"d":return this.parseDropKeep("drop");case"k":return this.parseDropKeep("keep");case"max":return this.parseMinMax("max");case"min":return this.parseMinMax("min");case"r":return this.parseRerollUnique("reroll");case"u":return this.parseRerollUnique("unique");case"cs":return this.parseCritical("critical-success");case"cf":return this.parseCritical("critical-failure");case"s":return this.parseSort();default:return null}}parseExplode(){const e=this.expect("bang",'"!"');let t=!1;"bang"===this.current().kind&&(t=!0,this.consume());let n=!1;this.isIdentifier("p")&&(n=!0,this.consume());const i=this.isComparePointStart()?this.parseComparePoint():null,r=i?.span??this.tokens[this.cursor-1]?.span??e.span,s=F(e.span,r);return{kind:"explode",id:w("explode",s),span:s,compound:t,penetrate:n,compare:i}}parseTarget(){const e=this.parseComparePoint();let t=null;this.isIdentifier("f")&&(this.consume(),t=this.parseComparePoint());const n=F(e.span,t?.span??e.span);return{kind:"target",id:w("target",n),span:n,success:e,failure:t}}parsePositiveInteger(e){const t=this.parseNumber(null);return!Number.isInteger(t.value)||t.value<1||t.raw.length>1&&t.raw.startsWith("0")?this.fail(`${e} must be a positive integer`,t.span,{value:t.value}):t}parseDropKeep(e){const t=this.consume();let n="drop"===e?"lowest":"highest";this.isIdentifier("l")?(this.consume(),n="lowest"):this.isIdentifier("h")&&(this.consume(),n="highest");const i=this.parsePositiveInteger(`${e} quantity`),r=F(t.span,i.span);return{kind:e,id:w(e,r),span:r,selection:n,quantity:i.value}}parseSignedFloat(){const e=this.current();return"operator"!==e.kind||"+"!==e.value&&"-"!==e.value?this.parseNumber(null):(this.consume(),this.parseNumber(e.value))}parseMinMax(e){const t=this.consume(),n=this.parseSignedFloat(),i=F(t.span,n.span);return{kind:e,id:w(e,i),span:i,value:n.value}}parseRerollUnique(e){const t=this.consume();let n=!1;this.isIdentifier("o")&&(n=!0,this.consume());const i=this.isComparePointStart()?this.parseComparePoint():null,r=i?.span??this.tokens[this.cursor-1]?.span??t.span,s=F(t.span,r);return{kind:e,id:w(e,s),span:s,once:n,compare:i}}parseCritical(e){const t=this.consume(),n=this.isComparePointStart()?this.parseComparePoint():null,i=F(t.span,n?.span??t.span);return{kind:e,id:w(e,i),span:i,compare:n}}parseSort(){const e=this.consume();let t="ascending",n=e.span;this.isIdentifier("a")?n=this.consume().span:this.isIdentifier("d")&&(t="descending",n=this.consume().span);const i=F(e.span,n);return{kind:"sort",id:w("sort",i),span:i,direction:t}}}function G(e,t=P){return new $(e,t).parse()}const q=Object.freeze({maxDepth:64,maxNodes:512}),Y=Object.freeze({"(":")","[":"]","{":"}"}),X=new Set(Object.values(Y));function W(e){switch(e.kind){case"number":return[];case"unary":return[e.operand];case"binary":return[e.left,e.right];case"parenthesized":return[e.expression];case"function":return e.arguments;case"dice":return"standard"===e.diceKind?[e.quantity,e.sides]:[e.quantity];case"group":return e.expressions}}function K(e,t){const n=new Map,i=e=>n.get(e.id)??null;for(const r of function(e){const t=[],n=[{node:e,visited:!1}];for(;n.length>0;){const e=n.pop();if(void 0===e)break;if(e.visited){t.push(e.node);continue}n.push({node:e.node,visited:!0});const i=W(e.node);for(let e=i.length-1;e>=0;e-=1){const t=i[e];void 0!==t&&n.push({node:t,visited:!1})}}return t}(e)){let e;switch(r.kind){case"number":e=r.value;break;case"dice":case"group":e=null;break;case"unary":{const n=i(r.operand);e=null===n?null:x("-"===r.operator?-n:n,t);break}case"parenthesized":e=i(r.expression);break;case"binary":{const n=i(r.left),s=i(r.right);e=null===n||null===s?null:v("**"===r.operator?"^":r.operator,n,s,t);break}case"function":{const n=i(r.arguments[0]);if(null===n)e=null;else if("unary"===r.functionKind)e=b(r.name,n,t);else{const s=i(r.arguments[1]);e=null===s?null:N(r.name,n,s,t)}break}}null!==e&&n.set(r.id,e)}return i(e)}function B(e){const t=function(e){let t=e.trim();for(;;){const e=Y[t.charAt(0)];if(void 0===e||t.charAt(t.length-1)!==e)return t;const n=[];let i=!1;for(let e=0;e<t.length;e+=1){const r=t.charAt(e),s=Y[r];if(void 0===s){if(X.has(r)){if(n.pop()!==r)return t;if(0===n.length&&e<t.length-1){i=!0;break}}}else n.push(s)}if(i||0!==n.length)return t;t=t.slice(1,-1).trim()}}(e).replace(/\s+/gu,"");if(0===t.length)return null;try{return K(G(t,q),t)}catch{return null}}function Q(e){return e>="0"&&e<="9"}function H(e){return/^[a-z]$/i.test(e)}function J(e){return""===e||!/[a-z0-9_]/i.test(e)}function Z(e,t,n){let i=t;for(;i<e.length&&n(e.charAt(i));)i+=1;return[e.slice(t,i),i]}function ee(e){const t=B(e);return null!==t&&Number.isSafeInteger(t)&&t>=0}function te(e,t){let n=t;for(;n<e.length&&/\s/u.test(e.charAt(n));)n+=1;return e.charAt(n)}function ne(e){const t=[];let n="",i=0,r=!1;const s=e=>{const n=e.trim();n.length>0&&t.push(n)};for(;i<e.length;){const t=e.charAt(i),o=e.charAt(i+1);if("/"===t&&"*"===o){const t=e.indexOf("*/",i+2),n=t<0?e.length:t;s(e.slice(i+2,n)),i=t<0?e.length:t+2;continue}if("/"===t&&"/"===o){const t=/[\n\r\u2028\u2029]/u.exec(e.slice(i+2)),n=void 0===t?.index?e.length:i+2+t.index;s(e.slice(i+2,n)),i=n;continue}if("["===t){const t=e.indexOf("]",i+1),r=t<0?e.length:t,o=e.slice(i,r+1);if(0===n.length&&t>=0&&"#"===te(e,t+1)&&ee(o)){n+=o,i=t+1;continue}s(e.slice(i+1,r)),i=t<0?e.length:t+1;continue}if("#"===t){const o=n.replace(/\s+/gu,""),a=/^\d+$/u.test(o),u=a?null:B(o),c=null!==u&&Number.isSafeInteger(u)&&u>=0;if(!r&&(a||c)){c&&(n=String(u)),n+=t,r=!0,i+=1;continue}const l=/[\n\r\u2028\u2029]/u.exec(e.slice(i+1)),d=void 0===l?.index?e.length:i+1+l.index;s(e.slice(i+1,d)),i=d;continue}/\s/u.test(t)||(n+=t),i+=1}return{notation:n,comment:t.join(" ").trim()}}function ie(e,t){const n=e.charAt(t);if("("===n)return["",t];if("%"===n)return["%",t+1];if("F"===n.toUpperCase()){let n=t+1;return"."===e.charAt(n)&&["1","2"].includes(e.charAt(n+1))?(n+=2,[`F.${e.charAt(n-1)}`,n]):["F",n]}return Q(n)?Z(e,t,Q):["20",t]}function re(e,t){const n=e.toLowerCase();return"f"===n&&J(t)&&!["<",">","=","!"].includes(t)?"4dF":"ei"===n&&(Q(t)||["<",">","=","!",""].includes(t))?Q(t)?"!>=":"!":"km"===n?Q(t)?"kl":"kl1":"kh"===n||"kl"===n?Q(t)?n:`${n}1`:"k"===n?Q(t)?"k":"k1":e}function se(e){let t="",n=0;for(;n<e.length;){const i=e.charAt(n);if(Q(i)){const[i,r]=Z(e,n,Q),s=e.charAt(r);if("d"===s.toLowerCase()){const[s,o]=ie(e,r+1);t+=0===Number(i)?"0":`${i}d${s}`,n=o;continue}if("f"===s.toLowerCase()&&J(e.charAt(r+1))&&!["<",">","=","!"].includes(e.charAt(r+1))){t+=`${i}dF`,n=r+1;continue}t+=i,n=r;continue}if("d"===i.toLowerCase()){const i=e.charAt(n+1);if("f"===i.toLowerCase()){const[i,r]=ie(e,n+1);t+=`d${i}`,n=r;continue}if(""===i||J(i)||Q(i)||"%"===i){const[i,r]=ie(e,n+1);t+=`d${i}`,n=r;continue}}if(H(i)){const[i,r]=Z(e,n,H);t+=re(i,e.charAt(r)),n=r;continue}t+=i,n+=1}return t}function oe(e){let t=e,n="";for(;t!==n;)n=t,t=t.replace(/\+-/gu,"-").replace(/-\+/gu,"-").replace(/\+\+/gu,"+").replace(/--/gu,"+");return t.replace(/[+-]{3,}/gu,"+").replace(/^[+-]/u,"")}function ae(e){return oe(se(ne(e).notation))}function ue(e){const t=ne(e),n=oe(se(t.notation)),i=/^(\d+)#/u.exec(n),r=i?.[1],s=void 0===r?1:Number.parseInt(r,10),o=null===i?n:n.slice(i[0].length);return{input:e,comment:t.comment,notation:o,normalizedNotation:n,rollCount:s,isMultiRoll:null!==i}}function ce(e){if(!Number.isSafeInteger(e)||e<0)throw new s("Budget consumption must be a non-negative safe integer",{code:"ROLL_EXECUTION_LIMIT",details:{count:Number.isFinite(e)?e:String(e)}})}class le{limits;astNodes=0;rolls=0;initialDice=0;generatedDice=0;randomCalls=0;modifierSteps=0;events=0;resolvedGroups=0;resultItems=0;constructor(e){this.limits=e}assertInputLength(e){e.length>this.limits.maxInputLength&&this.throwLimit({code:"INPUT_TOO_LONG",message:"Dice input exceeds the maximum length",limitName:"maxInputLength"},e.length,{inputLength:e.length},e)}consumeAstNode(e){if(!Number.isSafeInteger(e)||e<1)throw new s("AST depth must be a positive safe integer",{code:"ROLL_EXECUTION_LIMIT",details:{depth:e}});e>this.limits.maxAstDepth&&this.throwLimit({code:"AST_TOO_DEEP",message:"AST exceeds the maximum depth",limitName:"maxAstDepth"},e,{depth:e}),this.astNodes=this.consume(this.astNodes,1,{code:"TOO_MANY_NODES",message:"AST exceeds the maximum node count",limitName:"maxAstNodes"})}consumeRolls(e=1){this.rolls=this.consume(this.rolls,e,{code:"TOO_MANY_ROLLS",message:"Roll count exceeds the execution limit",limitName:"maxRolls"})}consumeInitialDice(e=1){this.initialDice=this.consume(this.initialDice,e,{code:"TOO_MANY_INITIAL_DICE",message:"Initial dice count exceeds the execution limit",limitName:"maxInitialDice"})}consumeGeneratedDice(e=1){this.generatedDice=this.consume(this.generatedDice,e,{code:"GENERATED_DICE_LIMIT_EXCEEDED",message:"Generated dice count exceeds the execution limit",limitName:"maxGeneratedDice"})}consumeRandomCalls(e=1){this.randomCalls=this.consume(this.randomCalls,e,{code:"RANDOM_BUDGET_EXCEEDED",message:"Random call count exceeds the execution limit",limitName:"maxRandomCalls"})}consumeEvents(e=1){this.events=this.consume(this.events,e,{code:"EVENT_LIMIT_EXCEEDED",message:"Event count exceeds the execution limit",limitName:"maxEvents"})}consumeModifierSteps(e=1){this.modifierSteps=this.consume(this.modifierSteps,e,{code:"MODIFIER_STEP_LIMIT_EXCEEDED",message:"Modifier step count exceeds the execution limit",limitName:"maxModifierSteps"})}consumeResolvedGroups(e=1){this.resolvedGroups=this.consume(this.resolvedGroups,e,{code:"RESOLVED_GROUP_LIMIT_EXCEEDED",message:"Resolved group count exceeds the execution limit",limitName:"maxResolvedGroups"})}consumeResultItems(e=1){this.resultItems=this.consume(this.resultItems,e,{code:"RESULT_LIMIT_EXCEEDED",message:"Result item count exceeds the execution limit",limitName:"maxResultItems"})}assertOutputLength(e){ce(e),e>this.limits.maxOutputLength&&this.throwLimit({code:"OUTPUT_LIMIT_EXCEEDED",message:"Output exceeds the maximum length",limitName:"maxOutputLength"},e,{outputLength:e})}snapshot(){return Object.freeze({astNodes:this.astNodes,rolls:this.rolls,initialDice:this.initialDice,generatedDice:this.generatedDice,randomCalls:this.randomCalls,modifierSteps:this.modifierSteps,events:this.events,resolvedGroups:this.resolvedGroups,resultItems:this.resultItems})}stats(){return Object.freeze({rolls:this.rolls,initialDice:this.initialDice,generatedDice:this.generatedDice,randomCalls:this.randomCalls,modifierSteps:this.modifierSteps,events:this.events,resolvedGroups:this.resolvedGroups,resultItems:this.resultItems})}consume(e,t,n){ce(t);const i=e+t,r=this.limits[n.limitName];return(!Number.isSafeInteger(i)||i>r)&&this.throwLimit(n,i,{consumed:i}),i}throwLimit(e,t,n,i=""){const r=this.limits[e.limitName];throw new s(e.message,{code:e.code,input:i,details:{...n,limitName:e.limitName,limit:r,actual:t}})}}const de=Number.MAX_SAFE_INTEGER,pe=new WeakMap;function me(e,t){return e>=de-t?de:e+t}function he(e,t){return 0===e||0===t?0:e>Math.floor(de/t)?de:e*t}function fe(e,t,n){if(!Number.isFinite(e))throw new s("Dice argument produced a non-finite result",{code:"NON_FINITE_RESULT",input:t,span:n,details:{value:String(e)}});const i=Number.isSafeInteger(e)?e:Number(e.toPrecision(12));return Object.is(i,-0)?0:i}function ge(e,t,n,i){const r=i.get(e.id);if(void 0===r)throw new s("Dice arguments must be constant expressions",{code:"INVALID_NOTATION",input:t,span:e.span,details:{argument:n,nodeKind:e.kind}});if(!Number.isSafeInteger(r)||r<1)throw new s(`Dice ${n} must be a positive safe integer`,{code:"INVALID_NOTATION",input:t,span:e.span,details:{argument:n,value:Number.isFinite(r)?r:String(r)}});return r}function Ie(e){switch(e.kind){case"min":return 1;case"max":return 2;case"explode":return 3;case"reroll":return 4;case"unique":return 5;case"keep":return 6;case"drop":return 7;case"target":return 8;case"critical-success":return 9;case"critical-failure":return 10;case"sort":return 11}}function xe(e){const t=new Set,n=[];for(let i=e.length-1;i>=0;i-=1){const r=e[i];void 0===r||t.has(r.kind)||(t.add(r.kind),n.push(r))}return n.reverse(),n.sort((e,t)=>Ie(e)-Ie(t)),Object.freeze(n)}function ve(e,t,n){switch(e.operator){case"=":return t===n&&t===e.value;case"!=":case"<>":return e.value<t||e.value>n;case"<":return n<e.value;case"<=":return n<=e.value;case">":return t>e.value;case">=":return t>=e.value}}function be(e,t){for(const n of e.modifiers)if("keep"!==n.kind&&"drop"!==n.kind&&"sort"!==n.kind)throw new s(`Modifier ${n.kind} is not supported on roll groups`,{code:"UNSUPPORTED_GROUP_MODIFIER",input:t,span:n.span,details:{modifier:n.kind}})}function Ne(e,t,n,i){const r=ge(e.quantity,t,"quantity",i);let o,a,u,c;if("standard"===e.diceKind){const r=ge(e.sides,t,"sides",i);if(r>n.maxSides)throw new s("Dice sides exceed the configured limit",{code:"DICE_SIDES_LIMIT_EXCEEDED",input:t,span:e.sides.span,details:{sides:r,limit:n.maxSides}});o=r,a=1,u=r,c=r}else"percentile"===e.diceKind?(o=100,a=1,u=100,c=100):(o="F",a=-1,u=1,c=3);const l=xe(e.modifiers);for(const e of l){if("explode"===e.kind&&(null===e.compare?a===u:ve(e.compare,a,u)))throw new s("Explode modifier cannot terminate for this die",{code:"NON_TERMINATING_MODIFIER",input:t,span:e.span,details:{reason:"non-terminating-explode",minimum:a,maximum:u}});if("reroll"===e.kind&&!e.once&&(null===e.compare?a===u:ve(e.compare,a,u)))throw new s("Reroll modifier cannot terminate for this die",{code:"NON_TERMINATING_MODIFIER",input:t,span:e.span,details:{reason:"non-terminating-reroll",minimum:a,maximum:u}});if("unique"===e.kind&&!e.once&&r>c&&(null===e.compare||ve(e.compare,a,u)))throw new s("Unique modifier cannot produce enough distinct faces",{code:"IMPOSSIBLE_UNIQUE",input:t,span:e.span,details:{reason:"impossible-unique",quantity:r,possibleFaces:c}})}return Object.freeze({nodeId:e.id,quantity:r,sides:o,minimum:a,maximum:u,possibleFaces:c,modifiers:l})}function Ee(e){switch(e.kind){case"number":return[];case"unary":return[e.operand];case"binary":return[e.left,e.right];case"parenthesized":return[e.expression];case"function":return e.arguments;case"dice":return"standard"===e.diceKind?[e.quantity,e.sides]:[e.quantity];case"group":return e.expressions}}function we(e){switch(e.kind){case"number":case"compare-point":case"drop":case"keep":case"min":case"max":case"sort":return[];case"unary":return[e.operand];case"binary":return[e.left,e.right];case"parenthesized":return[e.expression];case"function":return e.arguments;case"dice":return"standard"===e.diceKind?[e.quantity,e.sides,...e.modifiers]:[e.quantity,...e.modifiers];case"group":return[...e.expressions,...e.modifiers];case"explode":case"reroll":case"unique":case"critical-success":case"critical-failure":return null===e.compare?[]:[e.compare];case"target":return null===e.failure?[e.success]:[e.success,e.failure]}}function De(e,t,n){const i=e=>t.get(e.id)??null;switch(e.kind){case"number":return e.value;case"dice":case"group":return null;case"unary":{const t=i(e.operand);return null===t?null:"-"===e.operator?-t:t}case"parenthesized":return i(e.expression);case"binary":{const t=i(e.left),r=i(e.right);if(null===t||null===r)return null;let s;switch(e.operator){case"+":s=t+r;break;case"-":s=t-r;break;case"*":s=t*r;break;case"/":s=t/r;break;case"%":s=t%r;break;case"^":case"**":s=t**r}return fe(s,n,e.span)}case"function":{const t=i(e.arguments[0]);if(null===t)return null;if("unary"===e.functionKind){let i;switch(e.name){case"abs":i=Math.abs(t);break;case"ceil":i=Math.ceil(t);break;case"cos":i=Math.cos(t);break;case"exp":i=Math.exp(t);break;case"floor":i=Math.floor(t);break;case"log":i=Math.log(t);break;case"round":i=Math.round(t);break;case"sign":i=Math.sign(t);break;case"sin":i=Math.sin(t);break;case"sqrt":i=Math.sqrt(t);break;case"tan":i=Math.tan(t)}return fe(i,n,e.span)}const r=i(e.arguments[1]);if(null===r)return null;let s;switch(e.name){case"max":s=Math.max(t,r);break;case"min":s=Math.min(t,r);break;case"pow":s=Math.pow(t,r)}return fe(s,n,e.span)}}}function Ae(e){return[2166136261,2654435769,2246822507,3266489909].map(t=>function(e,t){let n=t;for(let t=0;t<e.length;t+=1)n^=e.charCodeAt(t),n=Math.imul(n,16777619),n^=n>>>13;return n>>>0}(`dicecore:1:${e}`,t).toString(16).padStart(8,"0")).join("")}function Oe(e,t){if("string"!=typeof e)throw new s("Dice input must be a string",{code:"INVALID_NOTATION",details:{receivedType:typeof e}});new le(t).assertInputLength(e);const n=ue(e);return function(e,t){if(0===e.notation.length)throw new s("Dice notation is required",{code:"DICE_NOTATION_REQUIRED",input:e.input});if(!Number.isSafeInteger(e.rollCount)||e.rollCount<1)throw new s("Roll count must be a positive safe integer",{code:"INVALID_NOTATION",input:e.input,details:{rollCount:Number.isFinite(e.rollCount)?e.rollCount:String(e.rollCount)}});if(e.rollCount>t.maxRolls)throw new s("Roll count exceeds the execution limit",{code:"TOO_MANY_ROLLS",input:e.input,details:{rollCount:e.rollCount,limit:t.maxRolls}})}(n,t),{normalized:n}}function Se(e,t,n){let i;try{i=G(e,{maxDepth:n.maxAstDepth,maxNodes:n.maxAstNodes})}catch(e){throw function(e,t){return o(e)?e.input===t?e:new s(e.message,{code:e.code,input:t,span:e.span,details:e.details}):new s("Invalid dice notation",{code:"INVALID_NOTATION",input:t,details:{cause:e instanceof Error?e.message:"Unknown parser error"}})}(e,t)}const r=function(e){const t=[],n=[{node:e,depth:1,visited:!1}];let i=1;for(;n.length>0;){const e=n.pop();if(void 0===e)break;if(i=Math.max(i,e.depth),e.visited){t.push(e.node);continue}n.push({node:e.node,depth:e.depth,visited:!0});const r=Ee(e.node);for(let t=r.length-1;t>=0;t-=1){const i=r[t];void 0!==i&&n.push({node:i,depth:e.depth+1,visited:!1})}}return{nodes:Object.freeze(t),maxDepth:i}}(i),a=function(e){const t=[{node:e,depth:1}];let n=0,i=1;for(;t.length>0;){const e=t.pop();if(void 0===e)break;n+=1,i=Math.max(i,e.depth);const r=we(e.node);for(let n=r.length-1;n>=0;n-=1){const i=r[n];void 0!==i&&t.push({node:i,depth:e.depth+1})}}return{nodeCount:n,maxDepth:i}}(i),u=new Map,c=new Map;let l=0,d=0;for(const e of r.nodes)if("group"===e.kind&&be(e,t),"dice"===e.kind){const i=Ne(e,t,n,c);u.set(e.id,i),l=me(l,i.quantity),"number"==typeof i.sides&&(d=Math.max(d,i.sides))}else{const n=De(e,c,t);null!==n&&c.set(e.id,n)}return Object.freeze({compilerVersion:1,notation:e,programFingerprint:Ae(e),ast:i,postOrder:r.nodes,nodeCount:a.nodeCount,maxDepth:a.maxDepth,staticDice:l,maximumSides:d,diceSpecs:u,constants:c})}function ye(e,t,n,i,r){if(i.notation!==t)throw new s("Compiled program does not match normalized notation",{code:"UNSUPPORTED_NOTATION",input:e});if(i.nodeCount>r.maxAstNodes)throw new s("AST node count exceeds the execution limit",{code:"TOO_MANY_NODES",input:e,details:{actual:i.nodeCount,limit:r.maxAstNodes}});if(i.maxDepth>r.maxAstDepth)throw new s("AST depth exceeds the execution limit",{code:"AST_TOO_DEEP",input:e,details:{actual:i.maxDepth,limit:r.maxAstDepth}});if(i.maximumSides>r.maxSides)throw new s("Dice sides exceed the configured limit",{code:"DICE_SIDES_LIMIT_EXCEEDED",input:e,details:{sides:i.maximumSides,limit:r.maxSides}});if(he(i.staticDice,n)>r.maxInitialDice)throw new s("Initial dice count exceeds the execution limit",{code:"TOO_MANY_INITIAL_DICE",input:e,details:{quantity:i.staticDice,rollCount:n,limit:r.maxInitialDice}})}function Re(e){switch(e.kind){case"number":case"dice":return[];case"unary":return[e.operand];case"binary":return[e.left,e.right];case"parenthesized":return[e.expression];case"function":return e.arguments;case"group":return e.expressions}}function ke(e){switch(e.kind){case"dice":return"dice";case"function":return"function";case"group":return"group";case"number":case"unary":case"binary":case"parenthesized":return"expression"}}function _e(e){return`group:${e.id}`}function Le(e,t){const n=[],i=[e];for(;i.length>0;){const e=i.pop();if(void 0===e)break;const r=Re(e);n.push({id:_e(e),sourceNodeId:e.id,kind:ke(e),notation:t.slice(e.span.start,e.span.end),span:e.span,childIds:r.map(_e)});for(let e=r.length-1;e>=0;e-=1){const t=r[e];void 0!==t&&i.push(t)}}return n}function Te(e,t){switch(e.kind){case"explode":return t.maxModifierSteps;case"reroll":case"unique":return e.once?1:t.maxModifierSteps;case"target":case"drop":case"keep":case"min":case"max":case"critical-success":case"critical-failure":case"sort":return 0}}function Me(e,t,n){let i={staticDice:0,worstCaseGeneratedDice:0,worstCaseRandomCalls:0};for(const t of e.diceSpecs.values()){let e=0,r=1;for(const i of t.modifiers){const t=Te(i,n);r=me(r,t),"explode"===i.kind&&(e=me(e,t))}i={staticDice:me(i.staticDice,t.quantity),worstCaseGeneratedDice:me(i.worstCaseGeneratedDice,he(t.quantity,e)),worstCaseRandomCalls:me(i.worstCaseRandomCalls,he(t.quantity,r))}}return{...i,totalStaticDice:he(i.staticDice,t),totalWorstCaseGeneratedDice:he(i.worstCaseGeneratedDice,t),totalWorstCaseRandomCalls:he(i.worstCaseRandomCalls,t)}}function Ce(e,t,n){const i=n??Se(e.normalized.notation,e.normalized.input,t);ye(e.normalized.input,e.normalized.notation,e.normalized.rollCount,i,t);const r=e.normalized,s=function(e){return e.groups.forEach(h),Object.freeze(e.groups),Object.freeze(e.cost),Object.freeze(e)}({type:"roll-plan",schemaVersion:3,compilerVersion:1,planFingerprint:Ae(r.normalizedNotation),input:r.input,comment:r.comment,notation:r.notation,normalizedNotation:r.normalizedNotation,isMultiRoll:r.isMultiRoll,rollCount:r.rollCount,groups:Le(i.ast,r.notation),cost:Me(i,r.rollCount,t)});return pe.set(s,i),s}function je(e){const t=pe.get(e);if(void 0===t)throw new s("Roll plan was not created by this compiler instance",{code:"UNSUPPORTED_NOTATION",input:e.input,details:{schemaVersion:e.schemaVersion}});return t}class ze{journal=[];budget;materialize;eventCount=0;constructor(e=null,t=!0){this.budget=e,this.materialize=t}get length(){return this.eventCount}record(e){if(this.budget?.consumeEvents(),this.budget?.consumeResultItems(),this.eventCount+=1,!this.materialize)return null;const t={sequence:this.eventCount,...e};return this.journal.push(t),t}slice(e,t=this.journal.length){return this.materialize?this.journal.slice(e,t):[]}toArray(){return this.materialize?this.journal.slice():[]}}const Pe=Object.freeze({maxInputLength:4096,maxAstDepth:64,maxAstNodes:1e4,maxRolls:100,maxInitialDice:1e4,maxGeneratedDice:2e4,maxRandomCalls:1e5,maxEvents:1e5,maxSides:4294967296,maxSeedLength:1024,maxModifierSteps:1e5,maxResolvedGroups:1e5,maxResultItems:25e4,maxOutputLength:1e6});function Ue(e,t,n){let i;try{i=e[t]}catch{throw new s(`Unable to read ${t}`,{code:"INVALID_LIMIT",details:{limit:t}})}if(void 0===i)return n;if("number"!=typeof i)throw new s(`${t} must be a number`,{code:"INVALID_LIMIT",details:{limit:t,valueType:typeof i}});return function(e,t){if(!Number.isSafeInteger(t)||t<1)throw new s(`${e} must be a positive safe integer`,{code:"INVALID_LIMIT",details:{limit:e,value:Number.isFinite(t)?t:String(t)}});return t}(t,i)}function Ve(e){try{if("object"!=typeof e||null===e||Array.isArray(e))throw new s("Dice limit overrides must be a non-null object",{code:"INVALID_LIMIT"})}catch(e){if(e instanceof s)throw e;throw new s("Dice limit overrides could not be read",{code:"INVALID_LIMIT"})}}function Fe(e,t,n){const i=Ue(t,n,e[n]);if(i>e[n])throw new s(`${n} cannot exceed the engine cap`,{code:"INVALID_LIMIT",details:{limit:n,requested:i,engineCap:e[n]}});return i}function $e(e){return Object.freeze(e)}function Ge(e={}){return Ve(e),$e({maxInputLength:Ue(e,"maxInputLength",Pe.maxInputLength),maxAstDepth:Ue(e,"maxAstDepth",Pe.maxAstDepth),maxAstNodes:Ue(e,"maxAstNodes",Pe.maxAstNodes),maxRolls:Ue(e,"maxRolls",Pe.maxRolls),maxInitialDice:Ue(e,"maxInitialDice",Pe.maxInitialDice),maxGeneratedDice:Ue(e,"maxGeneratedDice",Pe.maxGeneratedDice),maxRandomCalls:Ue(e,"maxRandomCalls",Pe.maxRandomCalls),maxEvents:Ue(e,"maxEvents",Pe.maxEvents),maxSides:Ue(e,"maxSides",Pe.maxSides),maxSeedLength:Ue(e,"maxSeedLength",Pe.maxSeedLength),maxModifierSteps:Ue(e,"maxModifierSteps",Pe.maxModifierSteps),maxResolvedGroups:Ue(e,"maxResolvedGroups",Pe.maxResolvedGroups),maxResultItems:Ue(e,"maxResultItems",Pe.maxResultItems),maxOutputLength:Ue(e,"maxOutputLength",Pe.maxOutputLength)})}const qe=624,Ye=397,Xe=2567483615,We=2147483648,Ke=2147483647,Be=4294967296;let Qe=null,He=null;function Je(e){if(!Number.isSafeInteger(e))throw new s("MT19937 seed words must be safe integers",{code:"INVALID_SEED",details:{seed:Number.isFinite(e)?e:String(e)}});return e>>>0}class Ze{state=new Uint32Array(qe);index=qe;budget;constructor(e,t=null){this.budget=t,"number"==typeof e?this.initializeSeed(Je(e)):this.restoreCachedSeedArray(e)?this.index=0:(this.initializeSeedArray(e),this.twist(),this.cacheSeedArray(e))}nextUint32(){this.budget?.consumeRandomCalls(),this.index>=qe&&this.twist();let e=this.readState(this.index);return this.index+=1,e^=e>>>11,e^=e<<7&2636928640,e^=e<<15&4022730752,e^=e>>>18,e>>>0}integer(e,t){if(!Number.isSafeInteger(e)||!Number.isSafeInteger(t)||e>t)throw new RangeError("Random integer bounds must be ordered safe integers");const n=t-e+1;if(!Number.isSafeInteger(n)||n<1||n>Be)throw new RangeError("Random integer range must contain at most 2^32 values");if(n===Be)return e+this.nextUint32();const i=Math.floor(Be/n)*n;let r=this.nextUint32();for(;r>=i;)r=this.nextUint32();return e+r%n}real(){return this.nextUint32()/Be}readState(e){return this.state[e]??0}writeState(e,t){this.state[e]=t>>>0}initializeSeed(e){this.writeState(0,e);for(let e=1;e<qe;e+=1){const t=this.readState(e-1),n=t^t>>>30;this.writeState(e,Math.imul(1812433253,n)+e)}this.index=qe}initializeSeedArray(e){if(e.length<1)throw new s("MT19937 requires at least one seed word",{code:"INVALID_SEED"});this.initializeSeed(19650218);let t=1,n=0,i=Math.max(qe,e.length);for(;i>0;){const r=this.readState(t-1),s=this.readState(t),o=Je(e[n]??0),a=Math.imul(r^r>>>30,1664525);this.writeState(t,(s^a)+o+n),t+=1,n+=1,t>=qe&&(this.writeState(0,this.readState(623)),t=1),n>=e.length&&(n=0),i-=1}for(i=623;i>0;){const e=this.readState(t-1),n=this.readState(t),r=Math.imul(e^e>>>30,1566083941);this.writeState(t,(n^r)-t),t+=1,t>=qe&&(this.writeState(0,this.readState(623)),t=1),i-=1}this.writeState(0,We),this.index=qe}restoreCachedSeedArray(e){const t=Qe,n=He;if(null===t||null===n||t.length!==e.length)return!1;for(let n=0;n<t.length;n+=1)if(t[n]!==e[n])return!1;return this.state.set(n),!0}cacheSeedArray(e){const t=new Uint32Array(e.length);for(let n=0;n<e.length;n+=1)t[n]=Je(e[n]??0);Qe=t,He=this.state.slice()}twist(){let e=0;for(;e<227;e+=1){const t=this.readState(e)&We|this.readState(e+1)&Ke,n=1&~t?0:Xe;this.writeState(e,this.readState(e+Ye)^t>>>1^n)}for(;e<623;e+=1){const t=this.readState(e)&We|this.readState(e+1)&Ke,n=1&~t?0:Xe;this.writeState(e,this.readState(e+Ye-qe)^t>>>1^n)}const t=this.readState(623)&We|this.readState(0)&Ke,n=1&~t?0:Xe;this.writeState(623,this.readState(396)^t>>>1^n),this.index=0}}const et=/^[0-9a-f]{32}$/u;function tt(){const e=globalThis.crypto;return"function"==typeof e?.getRandomValues?e:null}function nt(e){let t="";for(let n=0;n<e.length;n+=1)t+=(e[n]??0).toString(16).padStart(8,"0");return t}function it(e){return new s(e,{code:"INVALID_REPLAY"})}function rt(e){if("object"!=typeof e||null===e)return!1;try{return!Array.isArray(e)}catch{return!1}}function st(e){if(!rt(e)||!function(e){const t=["algorithm","algorithmVersion","executionVersion","mathProfile","origin","planFingerprint","schemaVersion","seedMaterial"];try{return Object.keys(e).sort().join(",")===t.join(",")}catch{return!1}}(e))return!1;try{return 2===e.schemaVersion&&("mt19937"===e.algorithm||"xoshiro128ss"===e.algorithm)&&1===e.algorithmVersion&&1===e.executionVersion&&e.mathProfile===g&&("provided-number"===e.origin||"provided-string"===e.origin||"crypto"===e.origin)&&"string"==typeof e.seedMaterial&&et.test(e.seedMaterial)&&"string"==typeof e.planFingerprint&&et.test(e.planFingerprint)}catch{return!1}}function ot(e,t){if(!rt(e))throw it("Replay descriptor must be a non-null object");try{if(2!==e.schemaVersion||1!==e.algorithmVersion||1!==e.executionVersion||e.mathProfile!==g||"mt19937"!==e.algorithm&&"xoshiro128ss"!==e.algorithm)throw new s("The replay algorithm or version is not supported",{code:"UNSUPPORTED_REPLAY_VERSION"})}catch(e){if(e instanceof s)throw e;throw it("Replay descriptor could not be read")}if(!st(e))throw it("Replay descriptor contains malformed or unexpected fields");if(void 0!==t&&e.planFingerprint!==t)throw new s("Replay descriptor belongs to a different roll plan",{code:"REPLAY_PLAN_MISMATCH",details:{expectedPlanFingerprint:t,actualPlanFingerprint:e.planFingerprint}});return e}function at(e,t=Pe.maxSeedLength){const n=function(e,t=Pe.maxSeedLength){if(!Number.isSafeInteger(t)||t<1)throw new s("maxSeedLength must be a positive safe integer",{code:"INVALID_LIMIT",details:{maxSeedLength:t}});if("number"==typeof e){if(!Number.isFinite(e))throw new s("Numeric seeds must be finite",{code:"INVALID_SEED",details:{seed:String(e)}});return`number:${Object.is(e,-0)?"-0":e.toString(10)}`}if("string"!=typeof e)throw new s("Seeds must be finite numbers or strings",{code:"INVALID_SEED"});if(e.length>t)throw new s("Text seed exceeds the maximum length",{code:"INVALID_SEED",details:{seedLength:e.length,maxSeedLength:t}});return`string:${e}`}(e,t),i=function(e){let t=1779033703^e.length;for(let n=0;n<e.length;n+=1)t=Math.imul(t^e.charCodeAt(n),3432918353),t=t<<13|t>>>19;const n=[];for(let e=0;e<4;e+=1)t=Math.imul(t^t>>>16,2246822507),t=Math.imul(t^t>>>13,3266489909),t^=t>>>16,n.push(t>>>0);return Object.freeze(n)}(n);return Object.freeze({canonicalSeed:n,seedMaterial:nt(i),origin:"number"==typeof e?"provided-number":"provided-string",words:i})}function ut(e,t){const n=ot(e,t),i=function(e){const t=[];for(let n=0;n<4;n+=1)t.push(Number.parseInt(e.slice(8*n,8*(n+1)),16));return Object.freeze(t)}(n.seedMaterial);return Object.freeze({canonicalSeed:`replay:${n.seedMaterial}`,seedMaterial:n.seedMaterial,origin:n.origin,words:i})}function ct(e,t=tt(),n=Pe.maxSeedLength){return void 0===e?function(e=tt()){if(null===e)throw new s("A cryptographic random source is not available",{code:"RNG_UNAVAILABLE"});const t=new Uint32Array(4);try{e.getRandomValues(t)}catch{throw new s("The cryptographic random source failed",{code:"RNG_UNAVAILABLE"})}const n=Object.freeze(Array.from(t)),i=nt(n);return Object.freeze({canonicalSeed:`crypto:${i}`,seedMaterial:i,origin:"crypto",words:n})}(t):at(e,n)}const lt=4294967296;function dt(e,t){return e<<t|e>>>32-t}function pt(e){if(!Number.isSafeInteger(e))throw new s("xoshiro128** seed words must be safe integers",{code:"INVALID_SEED",details:{seed:Number.isFinite(e)?e:String(e)}});return e>>>0}class mt{state0;state1;state2;state3;budget;constructor(e,t=null){if(4!==e.length)throw new s("xoshiro128** requires exactly four seed words",{code:"INVALID_SEED",details:{wordCount:e.length}});this.budget=t,this.state0=0|pt(e[0]??0),this.state1=0|pt(e[1]??0),this.state2=0|pt(e[2]??0),this.state3=0|pt(e[3]??0),0===(this.state0|this.state1|this.state2|this.state3)&&(this.state3=-1640531527)}nextUint32(){this.budget?.consumeRandomCalls();const e=this.state0;let t=this.state1,n=this.state2,i=this.state3;const r=Math.imul(dt(Math.imul(t,5),7),9)>>>0,s=t<<9;return n^=e,i^=t,t^=n,this.state0=e^i,this.state1=t,this.state2=n^s,this.state3=dt(i,11),r}integer(e,t){if(!Number.isSafeInteger(e)||!Number.isSafeInteger(t)||e>t)throw new RangeError("Random integer bounds must be ordered safe integers");const n=t-e+1;if(!Number.isSafeInteger(n)||n<1||n>lt)throw new RangeError("Random integer range must contain at most 2^32 values");if(n===lt)return e+this.nextUint32();const i=Math.floor(lt/n)*n;let r=this.nextUint32();for(;r>=i;)r=this.nextUint32();return e+r%n}real(){return this.nextUint32()/lt}}class ht{limits;budget;random;journal;replay;constructor(e={}){if(this.limits=e.resolvedLimits??Ge(e.limits),this.budget=new le(this.limits),void 0!==e.seed&&void 0!==e.replay)throw new s("seed and replay are mutually exclusive",{code:"INVALID_REPLAY"});if(void 0!==e.replay&&void 0!==e.randomAlgorithm)throw new s("A replay descriptor determines its random algorithm",{code:"INVALID_REPLAY"});if(void 0!==e.collectEvents&&"boolean"!=typeof e.collectEvents)throw new s("collectEvents must be a boolean",{code:"ROLL_EXECUTION_LIMIT"});let t,n;if(void 0===e.replay){if(t=e.randomAlgorithm??"mt19937","mt19937"!==t&&"xoshiro128ss"!==t)throw new s("The requested random algorithm is not supported",{code:"INVALID_REPLAY"});n=ct(e.seed,e.cryptoSource,this.limits.maxSeedLength),this.replay=function(e,t={}){const n=t.algorithm??"mt19937",i=t.planFingerprint??"00000000000000000000000000000000";if("mt19937"!==n&&"xoshiro128ss"!==n||!et.test(e.seedMaterial)||!et.test(i))throw it("Replay seed material and plan fingerprint must be 128-bit hex strings");return Object.freeze({schemaVersion:2,algorithm:n,algorithmVersion:1,executionVersion:1,mathProfile:g,origin:e.origin,seedMaterial:e.seedMaterial,planFingerprint:i})}(n,{algorithm:t,...void 0===e.planFingerprint?{}:{planFingerprint:e.planFingerprint}})}else{const i=ot(e.replay,e.planFingerprint);t=i.algorithm,n=ut(i,e.planFingerprint),this.replay=i}this.random="mt19937"===t?new Ze(n.words,this.budget):new mt(n.words,this.budget),this.journal=new ze(this.budget,e.collectEvents??!0)}}function ft(e={}){return new ht(e)}function gt(e,t){return`roll-${t}:group:${e.id}`}function It(e,t){return e.plan.notation.slice(t.span.start,t.span.end)}function xt(e,t){e.states.includes(t)||e.states.push(t)}function vt(e){e.contribution=e.active&&e.included?e.value:0}function bt(e,t){return function(e,t,n){switch(e){case"=":return t===n;case"!=":case"<>":return t!==n;case"<":return t<n;case">":return t>n;case"<=":return t<=n;case">=":return t>=n}}(e.operator,t,e.value)}function Nt(e,t,n){return Et(e,t,n.context)}function Et(e,t,n){switch(e.diceKind){case"standard":return n.random.integer(t.minimum,t.maximum);case"percentile":return n.random.integer(1,100);case"fudge":if(2===e.variant)return n.random.integer(1,3)-2;{const e=n.random.integer(1,6);return 1===e?-1:6===e?1:0}}}function wt(e,t,n,i,r){r?n.context.budget.consumeGeneratedDice():n.context.budget.consumeInitialDice(),n.context.budget.consumeResultItems(),n.nextDieIndex+=1;const s=Nt(e,t,n),o={id:`roll-${n.rollIndex}-die-${n.nextDieIndex}`,sourceNodeId:e.id,parentDieId:i,rollIndex:n.rollIndex,groupId:gt(e,n.rollIndex),sides:t.sides,rawValue:s,value:s,contribution:s,included:!0,active:!0,states:[]};return n.dice.push(o),n.context.journal.record({type:"roll",subject:"die",dieId:o.id,parentDieId:i,rollIndex:n.rollIndex,sourceNodeId:e.id,value:s}),o}function Dt(e,t,n){for(const i of e)if(i.active&&i.value<t){const e=i.value;i.value=t,xt(i,"minimum"),vt(i),n.context.journal.record({type:"transform",subject:"die",dieId:i.id,parentDieId:i.parentDieId,rollIndex:n.rollIndex,sourceNodeId:i.sourceNodeId,from:e,to:i.value,reason:"minimum"})}}function At(e,t,n){for(const i of e)if(i.active&&i.value>t){const e=i.value;i.value=t,xt(i,"maximum"),vt(i),n.context.journal.record({type:"transform",subject:"die",dieId:i.id,parentDieId:i.parentDieId,rollIndex:n.rollIndex,sourceNodeId:i.sourceNodeId,from:e,to:i.value,reason:"maximum"})}}function Ot(e,t,n,i,r){const s=e.filter(e=>e.active),o=i.maximum;for(const a of s){let s=a,u=s.value;const c=[a];for(;;){if(!(null===t.compare?u===o:bt(t.compare,u)))break;r.context.budget.consumeModifierSteps(),xt(s,"exploded"),t.penetrate&&xt(s,"penetrated");const a=wt(n,i,r,s.id,!0);if(u=a.value,t.penetrate){const e=a.value;a.value-=1,vt(a),r.context.journal.record({type:"transform",subject:"die",dieId:a.id,parentDieId:a.parentDieId,rollIndex:r.rollIndex,sourceNodeId:n.id,from:e,to:a.value,reason:"penetrate"})}e.push(a),c.push(a),r.context.journal.record({type:"explode",subject:"die",dieId:s.id,parentDieId:s.parentDieId,rollIndex:r.rollIndex,sourceNodeId:n.id,childDieId:a.id,value:a.value,reason:t.compound?"compound":t.penetrate?"penetrate":"explode"}),s=a}if(t.compound&&c.length>1){const e=a.value;a.value=c.reduce((e,t)=>e+t.value,0),xt(a,"compound"),vt(a),r.context.journal.record({type:"transform",subject:"die",dieId:a.id,parentDieId:a.parentDieId,rollIndex:r.rollIndex,sourceNodeId:n.id,from:e,to:a.value,reason:"compound"});for(let e=1;e<c.length;e+=1){const t=c[e];void 0!==t&&(t.active=!1,t.included=!1,vt(t),r.context.journal.record({type:"exclude",subject:"die",dieId:t.id,parentDieId:t.parentDieId,rollIndex:r.rollIndex,sourceNodeId:n.id,reason:"compound-absorbed"}))}}}}function St(e,t,n,i,r){const s=i.minimum;for(const o of e)if(o.active)for(;;){if(!(null===t.compare?o.value===s:bt(t.compare,o.value)))break;r.context.budget.consumeModifierSteps();const e=o.value,a=Nt(n,i,r);if(o.value=a,xt(o,"rerolled"),vt(o),r.context.journal.record({type:"reroll",subject:"die",dieId:o.id,parentDieId:o.parentDieId,rollIndex:r.rollIndex,sourceNodeId:n.id,from:e,to:a,reason:t.once?"reroll-once":"reroll"}),t.once)break}}function yt(e,t,n,i,r){const s=e.filter(e=>e.active),o=new Set;for(let e=0;e<s.length;e+=1){const a=s[e];if(void 0!==a){for(;;){const e=o.has(a.value),s=null===t.compare||bt(t.compare,a.value);if(!e||!s)break;r.context.budget.consumeModifierSteps();const u=a.value,c=Nt(n,i,r);if(a.value=c,xt(a,"unique-rerolled"),vt(a),r.context.journal.record({type:"reroll",subject:"die",dieId:a.id,parentDieId:a.parentDieId,rollIndex:r.rollIndex,sourceNodeId:n.id,from:u,to:c,reason:t.once?"unique-once":"unique"}),t.once)break}o.add(a.value)}}}function Rt(e,t,n,i){const r=e.map((e,t)=>({index:t,value:e.value})).sort((e,t)=>e.value-t.value||e.index-t.index),s=("lowest"===n?r.slice(0,i):r.slice(Math.max(0,r.length-i))).map(e=>e.index);if("drop"===t)return s;const o=new Set(s);return r.filter(e=>!o.has(e.index)).map(e=>e.index)}function kt(e,t,n){const i=e.filter(e=>e.active),r=Rt(i,t.kind,t.selection,t.quantity);for(const e of r){const r=i[e];void 0!==r&&r.included&&(r.included=!1,xt(r,"dropped"),vt(r),n.context.journal.record({type:"exclude",subject:"die",dieId:r.id,parentDieId:r.parentDieId,rollIndex:n.rollIndex,sourceNodeId:r.sourceNodeId,reason:t.kind}))}}function _t(e,t,n){for(const i of e){if(!i.active)continue;let e;bt(t.success,i.value)?(e="success",xt(i,"target-success"),i.contribution=i.included?1:0):null!==t.failure&&bt(t.failure,i.value)?(e="failure",xt(i,"target-failure"),i.contribution=i.included?-1:0):(e="neutral",xt(i,"target-neutral"),i.contribution=0),n.context.journal.record({type:"classify",subject:"die",dieId:i.id,parentDieId:i.parentDieId,rollIndex:n.rollIndex,sourceNodeId:i.sourceNodeId,outcome:e})}}function Lt(e,t,n,i){const r="critical-success"===t.kind?n.maximum:n.minimum;for(const n of e)n.active&&(null===t.compare?n.value===r:bt(t.compare,n.value))&&(xt(n,t.kind),i.context.journal.record({type:"classify",subject:"die",dieId:n.id,parentDieId:n.parentDieId,rollIndex:i.rollIndex,sourceNodeId:n.sourceNodeId,outcome:t.kind}))}function Tt(e,t,n,i,r=[]){const s=gt(e,t.rollIndex),o="dice"===e.kind?"dice":"function"===e.kind?"function":"group"===e.kind?"group":"expression",a={id:s,sourceNodeId:e.id,rollIndex:t.rollIndex,kind:o,notation:It(t,e),span:e.span,value:n,contribution:n,included:!0,states:r.slice(),childIds:i};return t.context.budget.consumeResolvedGroups(),t.context.budget.consumeResultItems(),t.groups.push(a),t.groupById.set(s,a),s}function Mt(e,t){const n=t.program.diceSpecs.get(e.id);if(void 0===n)throw new s("Compiled dice specification is missing",{code:"UNSUPPORTED_NOTATION",input:t.plan.input,span:e.span,details:{nodeId:e.id}});const i=t.dice.length,r=[];for(let i=0;i<n.quantity;i+=1)r.push(wt(e,n,t,null,!1));const o=function(e,t,n,i,r){let s=e;for(const o of t)switch(o.kind){case"min":Dt(e,o.value,r);break;case"max":At(e,o.value,r);break;case"explode":Ot(e,o,n,i,r);break;case"reroll":St(e,o,n,i,r);break;case"unique":yt(e,o,n,i,r);break;case"keep":case"drop":kt(e,o,r);break;case"target":_t(e,o,r);break;case"critical-success":case"critical-failure":Lt(e,o,i,r);break;case"sort":s=e.slice().sort((e,t)=>"ascending"===o.direction?e.value-t.value:t.value-e.value)}return s}(r,n.modifiers,e,n,t),a=E(r.reduce((e,t)=>e+t.contribution,0)),u=Tt(e,t,a,o.map(e=>e.id));return{value:a,rendered:t.renderOutput?`[${o.map(e=>e.value).join(", ")}]`:"",groupId:u,diceRange:{start:i,count:t.dice.length-i}}}function Ct(e,t,n){const i=t.groupById.get(e);if(void 0!==i&&i.included){i.included=!1,i.contribution=0,i.states.push("dropped"),t.context.journal.record({type:"exclude",subject:"group",groupId:i.id,rollIndex:t.rollIndex,sourceNodeId:i.sourceNodeId,reason:n,value:i.value});for(const e of i.childIds)t.groupById.has(e)&&Ct(e,t,n)}}function jt(e,t,n){e.included=!1,null!==e.evaluation.groupId&&Ct(e.evaluation.groupId,t,n);const i=e.evaluation.diceRange.start+e.evaluation.diceRange.count;for(let r=e.evaluation.diceRange.start;r<i;r+=1){const e=t.dice[r];void 0!==e&&(e.included&&(e.included=!1,xt(e,"dropped"),vt(e),t.context.journal.record({type:"exclude",subject:"die",dieId:e.id,parentDieId:e.parentDieId,rollIndex:t.rollIndex,sourceNodeId:e.sourceNodeId,reason:n})))}}function zt(e,t){const n=t.dice.length,i=e.expressions.map(e=>{const n=Pt(e,t);return{evaluation:n,value:n.value,included:!0}}),r=xe(e.modifiers),o=function(e,t,n){let i=e;for(const r of t)switch(r.kind){case"keep":case"drop":{const t=Rt(e,r.kind,r.selection,r.quantity);for(const i of t){const t=e[i];void 0!==t&&t.included&&jt(t,n,r.kind)}break}case"min":case"max":case"target":case"critical-success":case"critical-failure":case"explode":case"reroll":case"unique":throw new s(`Modifier ${r.kind} is not supported on roll groups`,{code:"UNSUPPORTED_GROUP_MODIFIER",input:n.plan.input,span:r.span,details:{modifier:r.kind}});case"sort":i=e.slice().sort((e,t)=>"ascending"===r.direction?e.value-t.value:t.value-e.value)}return i}(i,r,t),a=E(i.reduce((e,t)=>e+(t.included?t.value:0),0)),u=i.flatMap(e=>null===e.evaluation.groupId?[]:[e.evaluation.groupId]),c=o.flatMap(e=>null===e.evaluation.groupId?[]:[e.evaluation.groupId]),l=r.find(e=>"sort"===e.kind),d=void 0===l?[]:["ascending"===l.direction?"sorted-ascending":"sorted-descending"],p=Tt(e,t,a,c,d);return void 0!==l&&t.context.journal.record({type:"transform",subject:"group",groupId:p,rollIndex:t.rollIndex,sourceNodeId:e.id,from:u,to:c,reason:"ascending"===l.direction?"sort-ascending":"sort-descending"}),{value:a,rendered:t.renderOutput?`{${o.map(e=>e.evaluation.rendered).join(", ")}}`:"",groupId:p,diceRange:{start:n,count:t.dice.length-n}}}function Pt(e,t){switch(e.kind){case"number":{const n=Tt(e,t,e.value,[]);return{value:e.value,rendered:t.renderOutput?e.raw:"",groupId:n,diceRange:{start:t.dice.length,count:0}}}case"unary":{const n=Pt(e.operand,t),i="-"===e.operator?-n.value:n.value,r=Tt(e,t,i,null===n.groupId?[]:[n.groupId]);return{value:i,rendered:t.renderOutput?`${e.operator}${n.rendered}`:"",groupId:r,diceRange:n.diceRange}}case"binary":{const n=Pt(e.left,t),i=Pt(e.right,t),r=v("**"===e.operator?"^":e.operator,n.value,i.value,t.plan.input),s=Tt(e,t,r,[n.groupId,i.groupId].filter(e=>null!==e));return{value:r,rendered:t.renderOutput?`${n.rendered}${e.operator}${i.rendered}`:"",groupId:s,diceRange:{start:n.diceRange.start,count:n.diceRange.count+i.diceRange.count}}}case"parenthesized":{const n=Pt(e.expression,t),i=Tt(e,t,n.value,null===n.groupId?[]:[n.groupId]);return{value:n.value,rendered:t.renderOutput?`(${n.rendered})`:"",groupId:i,diceRange:n.diceRange}}case"function":{if("unary"===e.functionKind){const n=Pt(e.arguments[0],t),i=b(e.name,n.value,t.plan.input),r=Tt(e,t,i,null===n.groupId?[]:[n.groupId]);return{value:i,rendered:t.renderOutput?`${e.name}(${n.rendered})`:"",groupId:r,diceRange:n.diceRange}}const n=Pt(e.arguments[0],t),i=Pt(e.arguments[1],t),r=N(e.name,n.value,i.value,t.plan.input),s=Tt(e,t,r,[n.groupId,i.groupId].filter(e=>null!==e));return{value:r,rendered:t.renderOutput?`${e.name}(${n.rendered},${i.rendered})`:"",groupId:s,diceRange:{start:n.diceRange.start,count:n.diceRange.count+i.diceRange.count}}}case"dice":return Mt(e,t);case"group":return zt(e,t)}}function Ut(e,t){const n=[];for(let i=0;i<e.dice.length;i+=1){const r=e.dice[i];void 0!==r&&(r.active&&r.included&&e.context.journal.record({type:"include",subject:"die",dieId:r.id,parentDieId:r.parentDieId,rollIndex:r.rollIndex,sourceNodeId:r.sourceNodeId,contribution:r.contribution}),t&&n.push({id:r.id,sourceNodeId:r.sourceNodeId,parentDieId:r.parentDieId,rollIndex:r.rollIndex,rollDieIndex:i+1,groupId:r.groupId,sides:r.sides,rawValue:r.rawValue,value:r.value,contribution:r.contribution,included:r.included&&r.active,states:r.states.slice()}))}return n}function Vt(e,t){const n=[];for(const i of e.groups)i.included&&e.context.journal.record({type:"include",subject:"group",groupId:i.id,rollIndex:i.rollIndex,sourceNodeId:i.sourceNodeId,value:i.value,contribution:i.contribution}),t&&n.push({id:i.id,sourceNodeId:i.sourceNodeId,rollIndex:i.rollIndex,kind:i.kind,notation:i.notation,span:i.span,value:i.value,contribution:i.contribution,included:i.included,states:i.states.slice(),childIds:i.childIds});return n}function Ft(e){let t=!1,n=0,i=0;for(const r of e){const e=r.states.includes("target-success"),s=r.states.includes("target-failure");(e||s||r.states.includes("target-neutral"))&&(t=!0),r.active&&r.included&&e?n+=1:r.active&&r.included&&s&&(i+=1)}return t?{successes:n,failures:i,netSuccesses:n-i}:null}function $t(e){let t=!1,n=0,i=0;for(const r of e)null!==r.pool&&(t=!0,n+=r.pool.successes,i+=r.pool.failures);return t?{successes:n,failures:i,netSuccesses:n-i}:null}function Gt(e,t,n){return void 0!==t.replay?ft({resolvedLimits:t.limits,replay:t.replay,planFingerprint:e.planFingerprint,collectEvents:n}):void 0!==t.seed?ft({resolvedLimits:t.limits,seed:t.seed,planFingerprint:e.planFingerprint,...void 0===t.randomAlgorithm?{}:{randomAlgorithm:t.randomAlgorithm},collectEvents:n}):ft({resolvedLimits:t.limits,planFingerprint:e.planFingerprint,...void 0===t.randomAlgorithm?{}:{randomAlgorithm:t.randomAlgorithm},collectEvents:n})}function qt(e){const t=e.budget.snapshot();return{rolls:t.rolls,initialDice:t.initialDice,generatedDice:t.generatedDice,randomCalls:t.randomCalls,modifierSteps:t.modifierSteps,events:t.events,resolvedGroups:t.resolvedGroups,resultItems:t.resultItems}}function Yt(e,t=1){e.budget.consumeEvents(t),e.budget.consumeResultItems(t)}function Xt(e,t,n,i){let r;switch(e.kind){case"number":r=e.value;break;case"unary":{const s=Xt(e.operand,t,n,i);r="-"===e.operator?-s:s;break}case"binary":r=v("**"===e.operator?"^":e.operator,Xt(e.left,t,n,i),Xt(e.right,t,n,i),i);break;case"parenthesized":r=Xt(e.expression,t,n,i);break;case"function":r="unary"===e.functionKind?b(e.name,Xt(e.arguments[0],t,n,i),i):N(e.name,Xt(e.arguments[0],t,n,i),Xt(e.arguments[1],t,n,i),i);break;case"dice":{const o=t.diceSpecs.get(e.id);if(void 0===o)throw new s("Compiled dice specification is missing",{code:"UNSUPPORTED_NOTATION",input:i,span:e.span,details:{nodeId:e.id}});let a=0;for(let t=0;t<o.quantity;t+=1)n.budget.consumeInitialDice(),n.budget.consumeResultItems(),a+=Et(e,o,n),Yt(n,2);r=E(a);break}case"group":{let s=0;for(const r of e.expressions)s+=Xt(r,t,n,i);r=E(s);break}}return function(e){e.budget.consumeResolvedGroups(),e.budget.consumeResultItems(),Yt(e)}(n),r}function Wt(e,t,n){const i="full"===n,r=je(e);if(!i&&function(e){for(const t of e.diceSpecs.values())if(t.modifiers.length>0)return!1;for(const t of e.postOrder)if("group"===t.kind&&t.modifiers.length>0)return!1;return!0}(r))return function(e,t,n){const i=Gt(e,n,!1);i.budget.consumeRolls(e.rollCount);const r=[];for(let n=1;n<=e.rollCount;n+=1)i.budget.consumeResultItems(),r.push({index:n,total:E(Xt(t.ast,t,i,e.input)),pool:null});return{type:"dice-roll-summary",schemaVersion:3,input:e.input,notation:e.notation,normalizedNotation:e.normalizedNotation,comment:e.comment,total:E(r.reduce((e,t)=>e+t.total,0)),replay:i.replay,stats:qt(i),rolls:r,pool:null}}(e,r,t);const s=Gt(e,t,i);s.budget.consumeRolls(e.rollCount);const o=r.ast,a=[],u=[],c=[],l=[],d=[];for(let t=1;t<=e.rollCount;t+=1){s.budget.consumeResultItems();const n=s.journal.length,p=a.length,m=u.length,h={context:s,plan:e,program:r,rollIndex:t,dice:[],groups:[],groupById:new Map,renderOutput:i,nextDieIndex:0},f=Pt(o,h),g=E(f.value),I=Ut(h,i),x=Vt(h,i),v=Ft(h.dice);if(i){a.push(...I),u.push(...x);const i=e.notation.length+2+f.rendered.length+3+String(g).length;s.budget.assertOutputLength(i),d.push(`${e.notation}: ${f.rendered} = ${g}`),c.push({index:t,total:g,pool:v,diceRange:{start:p,count:I.length},groupRange:{start:m,count:x.length},eventRange:{start:n,count:s.journal.length-n}})}else l.push({index:t,total:g,pool:v})}const p=s.journal.toArray(),m=i?c:l,h=E(m.reduce((e,t)=>e+t.total,0)),f={schemaVersion:3,input:e.input,notation:e.notation,normalizedNotation:e.normalizedNotation,comment:e.comment,total:h,replay:s.replay,stats:qt(s),pool:$t(m)};if(!i)return{...f,type:"dice-roll-summary",rolls:l};const g=function(e,t,n){if(1===e.length){const t=e[0]??"";return n.budget.assertOutputLength(t.length),t}const i=`Total: ${t}`;let r=i.length;for(let t=0;t<e.length;t+=1){const n=e[t]??"";r+=String(t+1).length+2+n.length+1}return n.budget.assertOutputLength(r),[...e.map((e,t)=>`${t+1}. ${e}`),i].join("\n")}(d,h,s);return{...f,type:"dice-roll",output:g,rolls:c,groups:u,dice:a,events:p}}function Kt(e,t){const n=Wt(e,t,"full");if("dice-roll"!==n.type)throw new TypeError("Full execution returned an invalid result kind");return n}function Bt(e,t){const n=Wt(e,t,"summary");if("dice-roll-summary"!==n.type)throw new TypeError("Summary execution returned an invalid result kind");return n}const Qt=Number.MAX_SAFE_INTEGER;function Ht(e,t,n){const i=t??n;if("number"!=typeof i||!Number.isSafeInteger(i)||i<0)throw new RangeError(`${e} must be a non-negative safe integer`);return i}function Jt(e){return"object"==typeof e&&null!==e}function Zt(e,t){return function(e,t){return t in e}(e,t)?e[t]:void 0}function en(e,t,n){try{if(!Jt(e)||Array.isArray(e))throw new s("Dice options must be a non-null object",{code:n});return Zt(e,t)}catch(e){if(o(e))throw e;throw new s(`Unable to read dice option ${t}`,{code:n,details:{option:t}})}}function tn(e){const t=en(e,"limits","INVALID_LIMIT"),n=en(e,"seed","INVALID_REPLAY"),i=en(e,"replay","INVALID_REPLAY"),r=en(e,"randomAlgorithm","INVALID_REPLAY");if(void 0!==n&&"string"!=typeof n&&"number"!=typeof n)throw new s("Seeds must be finite numbers or strings",{code:"INVALID_SEED"});if(void 0!==r&&"mt19937"!==r&&"xoshiro128ss"!==r)throw new s("The requested random algorithm is not supported",{code:"INVALID_REPLAY"});if(void 0!==i&&(void 0!==n||void 0!==r))throw new s("Replay cannot be combined with seed or randomAlgorithm",{code:"INVALID_REPLAY"});return{limits:t,randomAlgorithm:r,replay:i,seed:n}}function nn(e,t){return void 0===t?e:function(e,t={}){return Ve(t),$e({maxInputLength:Fe(e,t,"maxInputLength"),maxAstDepth:Fe(e,t,"maxAstDepth"),maxAstNodes:Fe(e,t,"maxAstNodes"),maxRolls:Fe(e,t,"maxRolls"),maxInitialDice:Fe(e,t,"maxInitialDice"),maxGeneratedDice:Fe(e,t,"maxGeneratedDice"),maxRandomCalls:Fe(e,t,"maxRandomCalls"),maxEvents:Fe(e,t,"maxEvents"),maxSides:Fe(e,t,"maxSides"),maxSeedLength:Fe(e,t,"maxSeedLength"),maxModifierSteps:Fe(e,t,"maxModifierSteps"),maxResolvedGroups:Fe(e,t,"maxResolvedGroups"),maxResultItems:Fe(e,t,"maxResultItems"),maxOutputLength:Fe(e,t,"maxOutputLength")})}(e,t)}function rn(e,t){return ot(e,t.planFingerprint)}class sn{limits;freezeResults;randomAlgorithm;inputCache;programCache;ownedPlans=new WeakSet;constructor(t){const n=function(e){const t=en(e,"limits","INVALID_LIMIT"),n=en(e,"cache","INVALID_LIMIT"),i=en(e,"freezeResults","INVALID_LIMIT"),r=en(e,"randomAlgorithm","INVALID_REPLAY");if(void 0!==i&&"development"!==i&&"always"!==i&&"never"!==i)throw new s("freezeResults uses an unsupported mode",{code:"INVALID_LIMIT"});if(void 0!==r&&"mt19937"!==r&&"xoshiro128ss"!==r)throw new s("The requested random algorithm is not supported",{code:"INVALID_REPLAY"});return{cache:n,freezeResults:i,limits:t,randomAlgorithm:r}}(t);this.limits=Ge(n.limits??{}),this.freezeResults=n.freezeResults??"never",this.randomAlgorithm=n.randomAlgorithm??"mt19937";const i=function(e){if(!1===e)return{maxInputEntries:0,maxProgramEntries:0,maxProgramNodes:0};let t,n,i,r;try{if(void 0!==e&&(!Jt(e)||Array.isArray(e)))throw new RangeError("cache must be false or a cache options object");t=void 0===e?{}:e}catch(e){if(e instanceof RangeError)throw e;throw new RangeError("cache options could not be read")}try{n=Zt(t,"maxInputEntries"),i=Zt(t,"maxProgramEntries"),r=Zt(t,"maxProgramNodes")}catch{throw new RangeError("cache options could not be read")}return{maxInputEntries:Ht("maxInputEntries",n,500),maxProgramEntries:Ht("maxProgramEntries",i,200),maxProgramNodes:Ht("maxProgramNodes",r,1e5)}}(n.cache);this.inputCache=new e(i.maxInputEntries,Qt),this.programCache=new e(i.maxProgramEntries,i.maxProgramNodes)}clearCache(){this.inputCache.clear(),this.programCache.clear()}getCacheStats(){const e=this.inputCache.stats(),t=this.programCache.stats();return{inputEntries:e.entries,programEntries:t.entries,programNodes:t.weight,hits:e.hits+t.hits,misses:e.misses+t.misses,evictions:e.evictions+t.evictions}}compile(e,t={}){if("string"!=typeof e)throw new s("Dice input must be a string",{code:"INVALID_NOTATION",details:{receivedType:typeof e}});const n=nn(this.limits,function(e){return en(e,"limits","INVALID_LIMIT")}(t));if(e.length>n.maxInputLength)throw new s("Dice input exceeds the configured length limit",{code:"INPUT_TOO_LONG",input:e,details:{actual:e.length,limit:n.maxInputLength}});const i=function(e,t){return`${function(e){return[e.maxInputLength,e.maxAstDepth,e.maxAstNodes,e.maxRolls,e.maxInitialDice,e.maxSides,e.maxModifierSteps].join(":")}(t)}\0${e}`}(e,n),r=this.inputCache.get(i);if(void 0!==r)return r;const o=Oe(e,n),a=o.normalized.notation;let u=this.programCache.get(a);void 0===u&&(u=Se(a,e,n),this.programCache.set(a,u,u.nodeCount));const c=Ce(o,n,u);return this.ownedPlans.add(c),this.inputCache.set(i,c),c}inspect(e,t={}){try{return{type:"dice-notation-inspection",input:(n=this.compile(e,t)).input,notation:n.notation,normalizedNotation:n.normalizedNotation,comment:n.comment,isValid:!0,plan:n,groups:n.groups,cost:n.cost,error:null}}catch(t){return function(e,t){const n="string"==typeof e?e:"",i=o(t)?t:new s("Invalid dice notation",{code:"INVALID_NOTATION",input:n,details:{cause:t instanceof Error?t.message:"Unknown compiler error"}}),r="INPUT_TOO_LONG"===i.code?{notation:"",normalizedNotation:"",comment:""}:ue(n);return{type:"dice-notation-inspection",input:n,notation:r.notation,normalizedNotation:r.normalizedNotation,comment:r.comment,isValid:!1,plan:null,groups:[],cost:null,error:i}}(e,t)}var n}normalize(e){return ae(e)}roll(e,t={}){const n=tn(t),i=nn(this.limits,n.limits),r=this.resolvePlan(e,i),s=void 0!==n.replay?Kt(r,{limits:i,replay:rn(n.replay,r)}):void 0===n.seed?Kt(r,{limits:i,randomAlgorithm:n.randomAlgorithm??this.randomAlgorithm}):Kt(r,{limits:i,seed:n.seed,randomAlgorithm:n.randomAlgorithm??this.randomAlgorithm});return f(this.freezeResults)?function(e){return e.rolls.forEach(p),e.dice.forEach(u),e.groups.forEach(l),e.events.forEach(c),Object.freeze(e.rolls),Object.freeze(e.dice),Object.freeze(e.groups),Object.freeze(e.events),Object.freeze(e.replay),Object.freeze(e.stats),d(e.pool),Object.freeze(e)}(s):s}rollSummary(e,t={}){const n=tn(t),i=nn(this.limits,n.limits),r=this.resolvePlan(e,i),s=void 0!==n.replay?Bt(r,{limits:i,replay:rn(n.replay,r)}):void 0===n.seed?Bt(r,{limits:i,randomAlgorithm:n.randomAlgorithm??this.randomAlgorithm}):Bt(r,{limits:i,seed:n.seed,randomAlgorithm:n.randomAlgorithm??this.randomAlgorithm});return f(this.freezeResults)?function(e){return e.rolls.forEach(m),Object.freeze(e.rolls),Object.freeze(e.replay),Object.freeze(e.stats),d(e.pool),Object.freeze(e)}(s):s}verify(e,t={}){return this.inspect(e,t).isValid}resolvePlan(e,t){if("string"==typeof e)return this.compile(e,{limits:t});if(function(e){return pe.has(e)}(e))return this.ownedPlans.has(e)&&t===this.limits||function(e,t){if(new le(t).assertInputLength(e.input),e.rollCount>t.maxRolls)throw new s("Roll count exceeds the execution limit",{code:"TOO_MANY_ROLLS",input:e.input,details:{rollCount:e.rollCount,limit:t.maxRolls}});ye(e.input,e.notation,e.rollCount,je(e),t)}(e,t),e;const n=function(e){try{if(!Jt(e)||"roll-plan"!==Zt(e,"type")||3!==Zt(e,"schemaVersion")||1!==Zt(e,"compilerVersion"))throw new s("Roll plan is invalid or uses an unsupported schema",{code:"UNSUPPORTED_NOTATION"});const t=Zt(e,"input"),n=Zt(e,"planFingerprint");if("string"!=typeof t||"string"!=typeof n||32!==n.length||!/^[0-9a-f]{32}$/u.test(n))throw new s("Roll plan envelope is malformed",{code:"UNSUPPORTED_NOTATION"});return{input:t,planFingerprint:n}}catch(e){if(o(e))throw e;throw new s("Roll plan could not be read safely",{code:"UNSUPPORTED_NOTATION",details:{cause:e instanceof Error?e.message:"External plan access failed"}})}}(e),i=this.compile(n.input,{limits:t});if(n.planFingerprint!==i.planFingerprint)throw new s("Roll plan does not match its source input",{code:"UNSUPPORTED_NOTATION",input:n.input,details:{expectedFingerprint:i.planFingerprint,receivedFingerprint:n.planFingerprint}});return i}}function on(e={}){return new sn(e)}const an=on();function un(e,t={}){return an.compile(e,t)}function cn(e,t={}){return an.inspect(e,t)}function ln(e,t={}){return an.roll(e,t)}function dn(e,t={}){return an.rollSummary(e,t)}function pn(e,t={}){return an.verify(e,t)}export{Pe as DEFAULT_DICE_LIMITS,s as DiceRollError,un as compileRpgDice,on as createDiceEngine,cn as inspectRpgDiceNotation,o as isDiceRollError,a as isDiceRollErrorData,ae as normalizeRpgDiceNotation,ln as rollRpgDice,dn as rollRpgDiceSummary,pn as verifyRpgDiceNotation};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface LruCacheStats {
|
|
2
|
+
readonly entries: number;
|
|
3
|
+
readonly weight: number;
|
|
4
|
+
readonly hits: number;
|
|
5
|
+
readonly misses: number;
|
|
6
|
+
readonly evictions: number;
|
|
7
|
+
}
|
|
8
|
+
/** Small deterministic LRU used by the engine's input and compiled-program caches. */
|
|
9
|
+
export declare class WeightedLruCache<Key, Value> {
|
|
10
|
+
private readonly maxEntries;
|
|
11
|
+
private readonly maxWeight;
|
|
12
|
+
private readonly entries;
|
|
13
|
+
private currentWeight;
|
|
14
|
+
private hitCount;
|
|
15
|
+
private missCount;
|
|
16
|
+
private evictionCount;
|
|
17
|
+
constructor(maxEntries: number, maxWeight: number);
|
|
18
|
+
get(key: Key): Value | undefined;
|
|
19
|
+
set(key: Key, value: Value, weight?: number): void;
|
|
20
|
+
clear(): void;
|
|
21
|
+
stats(): LruCacheStats;
|
|
22
|
+
private evictOverflow;
|
|
23
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface LruCacheStats {
|
|
2
|
+
readonly entries: number;
|
|
3
|
+
readonly weight: number;
|
|
4
|
+
readonly hits: number;
|
|
5
|
+
readonly misses: number;
|
|
6
|
+
readonly evictions: number;
|
|
7
|
+
}
|
|
8
|
+
/** Small deterministic LRU used by the engine's input and compiled-program caches. */
|
|
9
|
+
export declare class WeightedLruCache<Key, Value> {
|
|
10
|
+
private readonly maxEntries;
|
|
11
|
+
private readonly maxWeight;
|
|
12
|
+
private readonly entries;
|
|
13
|
+
private currentWeight;
|
|
14
|
+
private hitCount;
|
|
15
|
+
private missCount;
|
|
16
|
+
private evictionCount;
|
|
17
|
+
constructor(maxEntries: number, maxWeight: number);
|
|
18
|
+
get(key: Key): Value | undefined;
|
|
19
|
+
set(key: Key, value: Value, weight?: number): void;
|
|
20
|
+
clear(): void;
|
|
21
|
+
stats(): LruCacheStats;
|
|
22
|
+
private evictOverflow;
|
|
23
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type NormalizedDiceInput } from './normalization.cjs';
|
|
2
|
+
import type { DiceLimits } from './runtime/limits.cjs';
|
|
3
|
+
import { type ExpressionNode, type ModifierNode } from './syntax/index.cjs';
|
|
4
|
+
import type { DiceNotationInspection, DiceSides, RollPlan } from './types.cjs';
|
|
5
|
+
export declare const DICE_COMPILER_VERSION: 1;
|
|
6
|
+
export interface CompiledDiceSpec {
|
|
7
|
+
readonly nodeId: string;
|
|
8
|
+
readonly quantity: number;
|
|
9
|
+
readonly sides: DiceSides;
|
|
10
|
+
readonly minimum: number;
|
|
11
|
+
readonly maximum: number;
|
|
12
|
+
readonly possibleFaces: number;
|
|
13
|
+
readonly modifiers: readonly ModifierNode[];
|
|
14
|
+
}
|
|
15
|
+
export interface CompiledDiceProgram {
|
|
16
|
+
readonly compilerVersion: 1;
|
|
17
|
+
readonly notation: string;
|
|
18
|
+
readonly programFingerprint: string;
|
|
19
|
+
readonly ast: ExpressionNode;
|
|
20
|
+
readonly postOrder: readonly ExpressionNode[];
|
|
21
|
+
readonly nodeCount: number;
|
|
22
|
+
readonly maxDepth: number;
|
|
23
|
+
readonly staticDice: number;
|
|
24
|
+
readonly maximumSides: number;
|
|
25
|
+
readonly diceSpecs: ReadonlyMap<string, CompiledDiceSpec>;
|
|
26
|
+
readonly constants: ReadonlyMap<string, number>;
|
|
27
|
+
}
|
|
28
|
+
export interface PreparedDicePlanInput {
|
|
29
|
+
readonly normalized: NormalizedDiceInput;
|
|
30
|
+
}
|
|
31
|
+
/** Returns the V3 modifier pipeline (last duplicate wins) without per-roll sorting. */
|
|
32
|
+
export declare function orderCompiledModifiers(modifiers: readonly ModifierNode[]): readonly ModifierNode[];
|
|
33
|
+
/** Stable 128-bit compiler fingerprint encoded as 32 lowercase hex characters. */
|
|
34
|
+
export declare function fingerprintDicePlan(value: string): string;
|
|
35
|
+
/** Normalizes and validates the input envelope before a program-cache lookup. */
|
|
36
|
+
export declare function prepareDicePlanInput(input: string, limits: DiceLimits): PreparedDicePlanInput;
|
|
37
|
+
/** Compiles one normalized formula into a cacheable, input-comment-independent program. */
|
|
38
|
+
export declare function compileDiceProgram(notation: string, sourceInput: string, limits: DiceLimits): CompiledDiceProgram;
|
|
39
|
+
/** Builds a public immutable plan around a known compiled program. */
|
|
40
|
+
export declare function compilePreparedDicePlan(prepared: PreparedDicePlanInput, limits: DiceLimits, program?: CompiledDiceProgram): RollPlan;
|
|
41
|
+
/** Compiles normalized dice notation exactly once into a validated, immutable V3 plan. */
|
|
42
|
+
export declare function compileDicePlan(input: string, limits: DiceLimits): RollPlan;
|
|
43
|
+
export declare function getPlanProgram(plan: RollPlan): CompiledDiceProgram;
|
|
44
|
+
export declare function hasPlanProgram(plan: RollPlan): boolean;
|
|
45
|
+
/** Revalidates a known immutable plan against lower per-call caps without recompiling it. */
|
|
46
|
+
export declare function validateKnownPlan(plan: RollPlan, limits: DiceLimits): void;
|
|
47
|
+
/** Kept while the executor transitions from the AST to the compiled IR. */
|
|
48
|
+
export declare function getPlanAst(plan: RollPlan): ExpressionNode;
|
|
49
|
+
/** Inspects notation without throwing for ordinary validation failures. */
|
|
50
|
+
export declare function inspectDicePlan(input: string, limits: DiceLimits): DiceNotationInspection;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { type NormalizedDiceInput } from './normalization.js';
|
|
2
|
+
import type { DiceLimits } from './runtime/limits.js';
|
|
3
|
+
import { type ExpressionNode, type ModifierNode } from './syntax/index.js';
|
|
4
|
+
import type { DiceNotationInspection, DiceSides, RollPlan } from './types.js';
|
|
5
|
+
export declare const DICE_COMPILER_VERSION: 1;
|
|
6
|
+
export interface CompiledDiceSpec {
|
|
7
|
+
readonly nodeId: string;
|
|
8
|
+
readonly quantity: number;
|
|
9
|
+
readonly sides: DiceSides;
|
|
10
|
+
readonly minimum: number;
|
|
11
|
+
readonly maximum: number;
|
|
12
|
+
readonly possibleFaces: number;
|
|
13
|
+
readonly modifiers: readonly ModifierNode[];
|
|
14
|
+
}
|
|
15
|
+
export interface CompiledDiceProgram {
|
|
16
|
+
readonly compilerVersion: 1;
|
|
17
|
+
readonly notation: string;
|
|
18
|
+
readonly programFingerprint: string;
|
|
19
|
+
readonly ast: ExpressionNode;
|
|
20
|
+
readonly postOrder: readonly ExpressionNode[];
|
|
21
|
+
readonly nodeCount: number;
|
|
22
|
+
readonly maxDepth: number;
|
|
23
|
+
readonly staticDice: number;
|
|
24
|
+
readonly maximumSides: number;
|
|
25
|
+
readonly diceSpecs: ReadonlyMap<string, CompiledDiceSpec>;
|
|
26
|
+
readonly constants: ReadonlyMap<string, number>;
|
|
27
|
+
}
|
|
28
|
+
export interface PreparedDicePlanInput {
|
|
29
|
+
readonly normalized: NormalizedDiceInput;
|
|
30
|
+
}
|
|
31
|
+
/** Returns the V3 modifier pipeline (last duplicate wins) without per-roll sorting. */
|
|
32
|
+
export declare function orderCompiledModifiers(modifiers: readonly ModifierNode[]): readonly ModifierNode[];
|
|
33
|
+
/** Stable 128-bit compiler fingerprint encoded as 32 lowercase hex characters. */
|
|
34
|
+
export declare function fingerprintDicePlan(value: string): string;
|
|
35
|
+
/** Normalizes and validates the input envelope before a program-cache lookup. */
|
|
36
|
+
export declare function prepareDicePlanInput(input: string, limits: DiceLimits): PreparedDicePlanInput;
|
|
37
|
+
/** Compiles one normalized formula into a cacheable, input-comment-independent program. */
|
|
38
|
+
export declare function compileDiceProgram(notation: string, sourceInput: string, limits: DiceLimits): CompiledDiceProgram;
|
|
39
|
+
/** Builds a public immutable plan around a known compiled program. */
|
|
40
|
+
export declare function compilePreparedDicePlan(prepared: PreparedDicePlanInput, limits: DiceLimits, program?: CompiledDiceProgram): RollPlan;
|
|
41
|
+
/** Compiles normalized dice notation exactly once into a validated, immutable V3 plan. */
|
|
42
|
+
export declare function compileDicePlan(input: string, limits: DiceLimits): RollPlan;
|
|
43
|
+
export declare function getPlanProgram(plan: RollPlan): CompiledDiceProgram;
|
|
44
|
+
export declare function hasPlanProgram(plan: RollPlan): boolean;
|
|
45
|
+
/** Revalidates a known immutable plan against lower per-call caps without recompiling it. */
|
|
46
|
+
export declare function validateKnownPlan(plan: RollPlan, limits: DiceLimits): void;
|
|
47
|
+
/** Kept while the executor transitions from the AST to the compiled IR. */
|
|
48
|
+
export declare function getPlanAst(plan: RollPlan): ExpressionNode;
|
|
49
|
+
/** Inspects notation without throwing for ordinary validation failures. */
|
|
50
|
+
export declare function inspectDicePlan(input: string, limits: DiceLimits): DiceNotationInspection;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CompileOptions, DiceEngine, DiceEngineOptions, DiceNotationInspection, DiceRollResult, DiceRollSummary, RollOptions, RollPlan } from './types.cjs';
|
|
2
|
+
export declare function createDiceEngine(options?: DiceEngineOptions): DiceEngine;
|
|
3
|
+
export declare function compileRpgDice(input: string, options?: CompileOptions): RollPlan;
|
|
4
|
+
export declare function inspectRpgDiceNotation(input: string, options?: CompileOptions): DiceNotationInspection;
|
|
5
|
+
export declare function rollRpgDice(input: string | RollPlan, options?: RollOptions): DiceRollResult;
|
|
6
|
+
export declare function rollRpgDiceSummary(input: string | RollPlan, options?: RollOptions): DiceRollSummary;
|
|
7
|
+
export declare function verifyRpgDiceNotation(input: string, options?: CompileOptions): boolean;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CompileOptions, DiceEngine, DiceEngineOptions, DiceNotationInspection, DiceRollResult, DiceRollSummary, RollOptions, RollPlan } from './types.js';
|
|
2
|
+
export declare function createDiceEngine(options?: DiceEngineOptions): DiceEngine;
|
|
3
|
+
export declare function compileRpgDice(input: string, options?: CompileOptions): RollPlan;
|
|
4
|
+
export declare function inspectRpgDiceNotation(input: string, options?: CompileOptions): DiceNotationInspection;
|
|
5
|
+
export declare function rollRpgDice(input: string | RollPlan, options?: RollOptions): DiceRollResult;
|
|
6
|
+
export declare function rollRpgDiceSummary(input: string | RollPlan, options?: RollOptions): DiceRollSummary;
|
|
7
|
+
export declare function verifyRpgDiceNotation(input: string, options?: CompileOptions): boolean;
|