roll-parser 3.0.0 → 3.2.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/CHANGELOG.md +61 -1
- package/MIGRATION.md +293 -4
- package/README.md +246 -55
- package/dist/cli/format.d.ts.map +1 -1
- package/dist/cli/format.js +8 -7
- package/dist/cli/format.js.map +1 -1
- package/dist/evaluator/die.d.ts +2 -1
- package/dist/evaluator/die.d.ts.map +1 -1
- package/dist/evaluator/die.js.map +1 -1
- package/dist/evaluator/env.d.ts +57 -0
- package/dist/evaluator/env.d.ts.map +1 -1
- package/dist/evaluator/env.js.map +1 -1
- package/dist/evaluator/evaluator.d.ts.map +1 -1
- package/dist/evaluator/evaluator.js +104 -56
- package/dist/evaluator/evaluator.js.map +1 -1
- package/dist/evaluator/modifiers/crit-threshold.d.ts +43 -5
- package/dist/evaluator/modifiers/crit-threshold.d.ts.map +1 -1
- package/dist/evaluator/modifiers/crit-threshold.js +24 -11
- package/dist/evaluator/modifiers/crit-threshold.js.map +1 -1
- package/dist/evaluator/modifiers/die-bound.d.ts +5 -2
- package/dist/evaluator/modifiers/die-bound.d.ts.map +1 -1
- package/dist/evaluator/modifiers/die-bound.js +6 -3
- package/dist/evaluator/modifiers/die-bound.js.map +1 -1
- package/dist/evaluator/modifiers/explode.d.ts.map +1 -1
- package/dist/evaluator/modifiers/explode.js +13 -5
- package/dist/evaluator/modifiers/explode.js.map +1 -1
- package/dist/evaluator/modifiers/flags.d.ts +17 -0
- package/dist/evaluator/modifiers/flags.d.ts.map +1 -1
- package/dist/evaluator/modifiers/flags.js +4 -4
- package/dist/evaluator/modifiers/flags.js.map +1 -1
- package/dist/evaluator/modifiers/keep-drop.d.ts +5 -5
- package/dist/evaluator/modifiers/keep-drop.d.ts.map +1 -1
- package/dist/evaluator/modifiers/keep-drop.js +7 -7
- package/dist/evaluator/modifiers/keep-drop.js.map +1 -1
- package/dist/evaluator/modifiers/reroll.d.ts.map +1 -1
- package/dist/evaluator/modifiers/reroll.js +16 -10
- package/dist/evaluator/modifiers/reroll.js.map +1 -1
- package/dist/evaluator/modifiers/sort.d.ts +1 -1
- package/dist/evaluator/modifiers/sort.d.ts.map +1 -1
- package/dist/evaluator/modifiers/sort.js +3 -3
- package/dist/evaluator/modifiers/sort.js.map +1 -1
- package/dist/evaluator/modifiers/success-count.d.ts +6 -2
- package/dist/evaluator/modifiers/success-count.d.ts.map +1 -1
- package/dist/evaluator/modifiers/success-count.js +9 -5
- package/dist/evaluator/modifiers/success-count.js.map +1 -1
- package/dist/notation.d.ts +13 -0
- package/dist/notation.d.ts.map +1 -0
- package/dist/notation.js +8 -0
- package/dist/notation.js.map +1 -0
- package/dist/parser/ast.d.ts +12 -7
- package/dist/parser/ast.d.ts.map +1 -1
- package/dist/parser/ast.js.map +1 -1
- package/dist/parser/guards.d.ts +38 -0
- package/dist/parser/guards.d.ts.map +1 -1
- package/dist/parser/guards.js +51 -0
- package/dist/parser/guards.js.map +1 -1
- package/dist/parser/parser.d.ts.map +1 -1
- package/dist/parser/parser.js +26 -2
- package/dist/parser/parser.js.map +1 -1
- package/dist/render.d.ts +95 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +232 -0
- package/dist/render.js.map +1 -0
- package/dist/types.d.ts +64 -12
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +14 -4
- package/src/cli/format.ts +15 -23
- package/src/evaluator/die.ts +2 -1
- package/src/evaluator/env.ts +58 -0
- package/src/evaluator/evaluator.ts +192 -70
- package/src/evaluator/modifiers/crit-threshold.ts +81 -15
- package/src/evaluator/modifiers/die-bound.ts +13 -4
- package/src/evaluator/modifiers/explode.ts +21 -6
- package/src/evaluator/modifiers/flags.ts +21 -4
- package/src/evaluator/modifiers/keep-drop.ts +10 -8
- package/src/evaluator/modifiers/reroll.ts +20 -11
- package/src/evaluator/modifiers/sort.ts +9 -3
- package/src/evaluator/modifiers/success-count.ts +27 -5
- package/src/notation.ts +24 -0
- package/src/parser/ast.ts +12 -7
- package/src/parser/guards.ts +92 -1
- package/src/parser/parser.ts +56 -1
- package/src/render.ts +394 -0
- package/src/types.ts +64 -12
- package/src/version.ts +1 -1
package/dist/render.js
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { joinModifierCode } from './notation.js';
|
|
2
|
+
import { DegreeOfSuccess } from './types.js';
|
|
3
|
+
export const MARKDOWN_MARKS = {
|
|
4
|
+
dropped: (_die, text) => `~~${text}~~`,
|
|
5
|
+
success: (_die, text) => `**${text}**`,
|
|
6
|
+
failure: (_die, text) => `__${text}__`,
|
|
7
|
+
droppedGroup: (inner) => `~~${inner}~~`,
|
|
8
|
+
};
|
|
9
|
+
const KEEP_DROP_CODES = {
|
|
10
|
+
keep: { highest: 'kh', lowest: 'kl' },
|
|
11
|
+
drop: { highest: 'dh', lowest: 'dl' },
|
|
12
|
+
};
|
|
13
|
+
const EXPLODE_MARKERS = {
|
|
14
|
+
standard: '!',
|
|
15
|
+
compound: '!!',
|
|
16
|
+
penetrating: '!p',
|
|
17
|
+
};
|
|
18
|
+
const DEGREE_LABELS = {
|
|
19
|
+
[DegreeOfSuccess.CriticalFailure]: 'Critical Failure',
|
|
20
|
+
[DegreeOfSuccess.Failure]: 'Failure',
|
|
21
|
+
[DegreeOfSuccess.Success]: 'Success',
|
|
22
|
+
[DegreeOfSuccess.CriticalSuccess]: 'Critical Success',
|
|
23
|
+
};
|
|
24
|
+
const BARE_VARIABLE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
25
|
+
function comparePointCode(point) {
|
|
26
|
+
return `${point.operator}${point.value}`;
|
|
27
|
+
}
|
|
28
|
+
function critCode(prefix, threshold) {
|
|
29
|
+
return threshold === 'default' ? prefix : `${prefix}${comparePointCode(threshold)}`;
|
|
30
|
+
}
|
|
31
|
+
function keepDropCode(spec) {
|
|
32
|
+
return `${KEEP_DROP_CODES[spec.kind][spec.selector]}${spec.count}`;
|
|
33
|
+
}
|
|
34
|
+
function failCode(point) {
|
|
35
|
+
return point.operator === '=' ? `f${point.value}` : `f${comparePointCode(point)}`;
|
|
36
|
+
}
|
|
37
|
+
function expr(part) {
|
|
38
|
+
switch (part.type) {
|
|
39
|
+
case 'literal':
|
|
40
|
+
case 'variable':
|
|
41
|
+
return String(part.value);
|
|
42
|
+
case 'dice':
|
|
43
|
+
return `${part.count}d${part.sides}`;
|
|
44
|
+
case 'fateDice':
|
|
45
|
+
return `${part.count}dF`;
|
|
46
|
+
case 'grouped':
|
|
47
|
+
return `(${expr(part.inner)})`;
|
|
48
|
+
case 'binaryOp':
|
|
49
|
+
return `${expr(part.left)} ${part.operator} ${expr(part.right)}`;
|
|
50
|
+
case 'unaryOp':
|
|
51
|
+
return `-${expr(part.operand)}`;
|
|
52
|
+
case 'group':
|
|
53
|
+
return `{${part.parts.map(expr).join(', ')}}`;
|
|
54
|
+
case 'functionCall':
|
|
55
|
+
return `${part.name}(${part.args.map(expr).join(', ')})`;
|
|
56
|
+
case 'keepDrop':
|
|
57
|
+
return joinModifierCode(expr(part.target), part.specs.map(keepDropCode).join(''));
|
|
58
|
+
case 'explode':
|
|
59
|
+
return `${expr(part.target)}${explodeCode(part)}`;
|
|
60
|
+
case 'reroll':
|
|
61
|
+
return joinModifierCode(expr(part.target), rerollCode(part));
|
|
62
|
+
case 'dieBound':
|
|
63
|
+
return joinModifierCode(expr(part.target), dieBoundCode(part));
|
|
64
|
+
case 'sort':
|
|
65
|
+
return joinModifierCode(expr(part.target), part.order === 'ascending' ? 's' : 'sd');
|
|
66
|
+
case 'critThreshold':
|
|
67
|
+
return joinModifierCode(expr(part.target), critThresholdCode(part));
|
|
68
|
+
case 'successCount':
|
|
69
|
+
return `${expr(part.target)}${successCountCode(part)}`;
|
|
70
|
+
case 'versus':
|
|
71
|
+
return `${expr(part.roll)} vs ${expr(part.dc)}`;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function explodeCode(part) {
|
|
75
|
+
const marker = EXPLODE_MARKERS[part.variant];
|
|
76
|
+
return part.threshold == null ? marker : `${marker}${comparePointCode(part.threshold)}`;
|
|
77
|
+
}
|
|
78
|
+
function rerollCode(part) {
|
|
79
|
+
return `${part.once ? 'ro' : 'r'}${comparePointCode(part.condition)}`;
|
|
80
|
+
}
|
|
81
|
+
function dieBoundCode(part) {
|
|
82
|
+
return part.value < 0 ? `${part.bound}(${part.value})` : `${part.bound}${part.value}`;
|
|
83
|
+
}
|
|
84
|
+
function critThresholdCode(part) {
|
|
85
|
+
return [
|
|
86
|
+
...part.successThresholds.map((threshold) => critCode('cs', threshold)),
|
|
87
|
+
...part.failThresholds.map((threshold) => critCode('cf', threshold)),
|
|
88
|
+
].reduce(joinModifierCode, '');
|
|
89
|
+
}
|
|
90
|
+
function successCountCode(part) {
|
|
91
|
+
const fail = part.failThreshold == null ? '' : failCode(part.failThreshold);
|
|
92
|
+
return `${comparePointCode(part.threshold)}${fail}`;
|
|
93
|
+
}
|
|
94
|
+
function collectDice(part, out) {
|
|
95
|
+
switch (part.type) {
|
|
96
|
+
case 'dice':
|
|
97
|
+
case 'fateDice':
|
|
98
|
+
case 'sort':
|
|
99
|
+
case 'explode':
|
|
100
|
+
case 'reroll':
|
|
101
|
+
case 'successCount':
|
|
102
|
+
for (const die of part.rolls)
|
|
103
|
+
out.push(die);
|
|
104
|
+
return;
|
|
105
|
+
case 'grouped':
|
|
106
|
+
collectDice(part.inner, out);
|
|
107
|
+
return;
|
|
108
|
+
case 'unaryOp':
|
|
109
|
+
collectDice(part.operand, out);
|
|
110
|
+
return;
|
|
111
|
+
case 'binaryOp':
|
|
112
|
+
collectDice(part.left, out);
|
|
113
|
+
collectDice(part.right, out);
|
|
114
|
+
return;
|
|
115
|
+
case 'keepDrop':
|
|
116
|
+
case 'dieBound':
|
|
117
|
+
case 'critThreshold':
|
|
118
|
+
collectDice(part.target, out);
|
|
119
|
+
return;
|
|
120
|
+
case 'group':
|
|
121
|
+
for (const sub of part.parts)
|
|
122
|
+
collectDice(sub, out);
|
|
123
|
+
return;
|
|
124
|
+
case 'functionCall':
|
|
125
|
+
for (const arg of part.args)
|
|
126
|
+
collectDice(arg, out);
|
|
127
|
+
return;
|
|
128
|
+
case 'versus':
|
|
129
|
+
collectDice(part.roll, out);
|
|
130
|
+
collectDice(part.dc, out);
|
|
131
|
+
return;
|
|
132
|
+
case 'literal':
|
|
133
|
+
case 'variable':
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function poolOf(part) {
|
|
138
|
+
const dice = [];
|
|
139
|
+
collectDice(part, dice);
|
|
140
|
+
return dice;
|
|
141
|
+
}
|
|
142
|
+
function markDie(die, marks, plain) {
|
|
143
|
+
let text = String(die.result);
|
|
144
|
+
if (die.critical)
|
|
145
|
+
text = marks.critical?.(die, text) ?? text;
|
|
146
|
+
if (die.fumble)
|
|
147
|
+
text = marks.fumble?.(die, text) ?? text;
|
|
148
|
+
if (plain)
|
|
149
|
+
return text;
|
|
150
|
+
const { modifiers } = die;
|
|
151
|
+
if (modifiers.includes('dropped'))
|
|
152
|
+
return marks.dropped?.(die, text) ?? text;
|
|
153
|
+
if (modifiers.includes('success'))
|
|
154
|
+
return marks.success?.(die, text) ?? text;
|
|
155
|
+
if (modifiers.includes('failure'))
|
|
156
|
+
return marks.failure?.(die, text) ?? text;
|
|
157
|
+
return text;
|
|
158
|
+
}
|
|
159
|
+
function renderPool(dice, marks, plain) {
|
|
160
|
+
const shown = [];
|
|
161
|
+
for (const die of dice) {
|
|
162
|
+
if (die.modifiers.includes('meta'))
|
|
163
|
+
continue;
|
|
164
|
+
shown.push(markDie(die, marks, plain));
|
|
165
|
+
}
|
|
166
|
+
return `[${shown.join(', ')}]`;
|
|
167
|
+
}
|
|
168
|
+
function renderModifier(target, code, dice, marks, plain) {
|
|
169
|
+
const pool = dice.length === 0 ? '' : renderPool(dice, marks, plain);
|
|
170
|
+
return `${joinModifierCode(expr(target), code)}${pool}`;
|
|
171
|
+
}
|
|
172
|
+
function renderPart(part, marks, plain) {
|
|
173
|
+
switch (part.type) {
|
|
174
|
+
case 'literal':
|
|
175
|
+
return String(part.value);
|
|
176
|
+
case 'variable': {
|
|
177
|
+
const display = BARE_VARIABLE.test(part.name) ? `@${part.name}` : `@{${part.name}}`;
|
|
178
|
+
return `${display}[${part.value}]`;
|
|
179
|
+
}
|
|
180
|
+
case 'dice':
|
|
181
|
+
case 'fateDice':
|
|
182
|
+
return `${expr(part)}${renderPool(part.rolls, marks, plain)}`;
|
|
183
|
+
case 'grouped':
|
|
184
|
+
return `(${renderPart(part.inner, marks, plain)})`;
|
|
185
|
+
case 'binaryOp':
|
|
186
|
+
return `${renderPart(part.left, marks, plain)} ${part.operator} ${renderPart(part.right, marks, plain)}`;
|
|
187
|
+
case 'unaryOp':
|
|
188
|
+
return `-${renderPart(part.operand, marks, plain)}`;
|
|
189
|
+
case 'functionCall': {
|
|
190
|
+
const args = part.args.map((arg) => renderPart(arg, marks, plain)).join(', ');
|
|
191
|
+
return `${part.name}(${args})`;
|
|
192
|
+
}
|
|
193
|
+
case 'versus':
|
|
194
|
+
return `${renderPart(part.roll, marks, plain)} vs ${renderPart(part.dc, marks, plain)}`;
|
|
195
|
+
case 'group':
|
|
196
|
+
return renderGroup(part, marks, plain);
|
|
197
|
+
case 'keepDrop':
|
|
198
|
+
return part.target.type === 'group' && part.target.keptIndices != null
|
|
199
|
+
? renderPart(part.target, marks, plain)
|
|
200
|
+
: `${expr(part.target)}${renderPool(poolOf(part.target), marks, plain)}`;
|
|
201
|
+
case 'explode':
|
|
202
|
+
return renderModifier(part.target, explodeCode(part), part.rolls, marks, plain);
|
|
203
|
+
case 'reroll':
|
|
204
|
+
return renderModifier(part.target, rerollCode(part), part.rolls, marks, plain);
|
|
205
|
+
case 'successCount':
|
|
206
|
+
return part.target.type === 'group' && part.target.parts.length >= 2
|
|
207
|
+
? `${renderPart(part.target, marks, plain)}${successCountCode(part)}`
|
|
208
|
+
: renderModifier(part.target, successCountCode(part), part.rolls, marks, plain);
|
|
209
|
+
case 'dieBound':
|
|
210
|
+
return `${expr(part)}${renderPool(poolOf(part.target), marks, plain)}`;
|
|
211
|
+
case 'sort':
|
|
212
|
+
return `${expr(part)}${renderPool(part.rolls, marks, plain)}`;
|
|
213
|
+
case 'critThreshold':
|
|
214
|
+
return `${expr(part)}${renderPool(poolOf(part.target), marks, plain)}`;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
function renderGroup(part, marks, plain) {
|
|
218
|
+
const { keptIndices } = part;
|
|
219
|
+
const subRolls = part.parts.map((sub, index) => {
|
|
220
|
+
if (keptIndices == null || keptIndices.includes(index)) {
|
|
221
|
+
return renderPart(sub, marks, plain);
|
|
222
|
+
}
|
|
223
|
+
const inner = renderPart(sub, marks, true);
|
|
224
|
+
return marks.droppedGroup?.(inner) ?? inner;
|
|
225
|
+
});
|
|
226
|
+
return `{${subRolls.join(', ')}}`;
|
|
227
|
+
}
|
|
228
|
+
export function renderBreakdown(result, marks = MARKDOWN_MARKS) {
|
|
229
|
+
const trailing = result.degree == null ? String(result.total) : DEGREE_LABELS[result.degree];
|
|
230
|
+
return `${renderPart(result.parts, marks, false)} = ${trailing}`;
|
|
231
|
+
}
|
|
232
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -37,9 +37,12 @@ export type ResolvedComparePoint = {
|
|
|
37
37
|
readonly value: number;
|
|
38
38
|
};
|
|
39
39
|
/**
|
|
40
|
-
* A resolved crit threshold — `'default'` means the per-die default rule
|
|
41
|
-
*
|
|
42
|
-
*
|
|
40
|
+
* A resolved crit threshold — `'default'` means the per-die default rule,
|
|
41
|
+
* which is what bare `cs` / `cf` produce. It reads the natural face
|
|
42
|
+
* (`initialResult ?? result`): critical when it equals `sides`, fumble when
|
|
43
|
+
* it equals 1, both only for `sides > 1`. An explicit ComparePoint instead
|
|
44
|
+
* reads the die's current `result`, so a preceding modifier that rewrote it
|
|
45
|
+
* is visible to the comparison.
|
|
43
46
|
*
|
|
44
47
|
* @category Results
|
|
45
48
|
*/
|
|
@@ -64,10 +67,14 @@ export type ResolvedCritThreshold = ResolvedComparePoint | 'default';
|
|
|
64
67
|
*
|
|
65
68
|
* `'meta'` is the one tag with no counterpart in the notation. Dice counts,
|
|
66
69
|
* sides, modifier counts and computed thresholds may themselves be dice
|
|
67
|
-
* (`(1d4)d6`, `4d6kh(1d2)`, `1d6!>(1d2+3)`). Those inner dice
|
|
68
|
-
*
|
|
69
|
-
* `RollResult.rolls` tagged `'meta'` so an audit log can still
|
|
70
|
-
* meta-expression rolled.
|
|
70
|
+
* (`(1d4)d6`, `4d6kh(1d2)`, `1d6!>(1d2+3)`). Those inner dice belong to no
|
|
71
|
+
* pool: they never appear on a `dice` or `fateDice` part, and they are
|
|
72
|
+
* appended to `RollResult.rolls` tagged `'meta'` so an audit log can still
|
|
73
|
+
* show what the meta-expression rolled.
|
|
74
|
+
*
|
|
75
|
+
* The four whole-pool views — `sort`, `explode`, `reroll`, and `successCount`
|
|
76
|
+
* `rolls` — are snapshots of an evaluation context rather than of a pool, so
|
|
77
|
+
* they do carry meta dice. Filter them out when summing or displaying a pool.
|
|
71
78
|
*
|
|
72
79
|
* `'dc'` marks the DC side of a `vs` comparison. Unlike `'meta'` these dice do
|
|
73
80
|
* render — `1d20[3] vs 2d10[5, 6]` shows both sides — but they are not part of
|
|
@@ -140,17 +147,28 @@ export type DieResult = {
|
|
|
140
147
|
/** The rolled value */
|
|
141
148
|
result: number;
|
|
142
149
|
/**
|
|
143
|
-
* Raw first roll before any mutation
|
|
144
|
-
* Only populated when `result` has
|
|
150
|
+
* Raw first roll before any mutation — compound-explode accumulation, the
|
|
151
|
+
* `!p` decrement, or a `minN`/`maxN` clamp. Only populated when `result` has
|
|
152
|
+
* been overwritten with a computed value.
|
|
145
153
|
* Consumers that need the original face (nat-20 / nat-1 detection) should
|
|
146
154
|
* read `initialResult ?? result`.
|
|
147
155
|
*/
|
|
148
156
|
initialResult?: number;
|
|
149
157
|
/** Modifiers applied to this die */
|
|
150
158
|
modifiers: DieModifier[];
|
|
151
|
-
/**
|
|
159
|
+
/**
|
|
160
|
+
* True if the die met its critical criteria — by default, rolling the
|
|
161
|
+
* maximum face on a die with more than one side. That default never fires
|
|
162
|
+
* on `d1` or on Fate dice (`sides = 0` has no maximum face), but an
|
|
163
|
+
* explicit `cs` threshold does: `4dFcs>0` flags every `+1`.
|
|
164
|
+
*/
|
|
152
165
|
critical: boolean;
|
|
153
|
-
/**
|
|
166
|
+
/**
|
|
167
|
+
* True if the die met its fumble criteria — by default, rolling a 1 on a
|
|
168
|
+
* die with more than one side. As with {@link DieResult.critical}, the
|
|
169
|
+
* default never fires on `d1` or Fate dice, while an explicit `cf`
|
|
170
|
+
* threshold does: `4dFcf=-1` flags every `-1`.
|
|
171
|
+
*/
|
|
154
172
|
fumble: boolean;
|
|
155
173
|
};
|
|
156
174
|
/**
|
|
@@ -196,7 +214,10 @@ export type RollPartBase = {
|
|
|
196
214
|
* - `literal.total === value` and `variable.total === value`.
|
|
197
215
|
* - Each part's `rolls[]` shares `DieResult` references with
|
|
198
216
|
* `RollResult.rolls[]`; both reflect post-evaluation state (explode
|
|
199
|
-
* accumulation, reroll flags, keep/drop flags). No deep
|
|
217
|
+
* accumulation, reroll flags, keep/drop flags, success/failure tags). No deep
|
|
218
|
+
* clone. A part's own numbers record what that part computed, so an inner
|
|
219
|
+
* `successCount` re-scored by an outer one (`{4d6>=5}<=2f5`) keeps its
|
|
220
|
+
* tally while the dice it shares show the outer count's tags.
|
|
200
221
|
*
|
|
201
222
|
* Meta-expression sub-trees (`4d6kh(1d2)`, `(1+1)d6` counts/sides, computed
|
|
202
223
|
* thresholds) are not surfaced as nested parts — their resolved numbers
|
|
@@ -296,11 +317,29 @@ export type RollPart = (RollPartBase & {
|
|
|
296
317
|
type: 'explode';
|
|
297
318
|
variant: 'standard' | 'compound' | 'penetrating';
|
|
298
319
|
threshold?: ResolvedComparePoint;
|
|
320
|
+
/**
|
|
321
|
+
* The expanded pool. Standard and penetrating explosions append dice
|
|
322
|
+
* that exist nowhere under `target`, so this is the only view of the
|
|
323
|
+
* pool the modifier actually produced. Compound explosions accumulate
|
|
324
|
+
* in place, making it the same dice as `target` carries.
|
|
325
|
+
*
|
|
326
|
+
* Like `RollResult.rolls` — and unlike the pool under `target` — this
|
|
327
|
+
* keeps `'meta'` dice. Filter them out before counting or displaying.
|
|
328
|
+
*/
|
|
329
|
+
rolls: DieResult[];
|
|
299
330
|
target: RollPart;
|
|
300
331
|
}) | (RollPartBase & {
|
|
301
332
|
type: 'reroll';
|
|
302
333
|
once: boolean;
|
|
303
334
|
condition: ResolvedComparePoint;
|
|
335
|
+
/**
|
|
336
|
+
* The post-reroll pool: discarded intermediates (`'rerolled'` +
|
|
337
|
+
* `'dropped'`) alongside their replacements. Both are appended rather
|
|
338
|
+
* than substituted, so neither appears under `target`.
|
|
339
|
+
*
|
|
340
|
+
* Keeps `'meta'` dice, as `RollResult.rolls` does.
|
|
341
|
+
*/
|
|
342
|
+
rolls: DieResult[];
|
|
304
343
|
target: RollPart;
|
|
305
344
|
}) | (RollPartBase & {
|
|
306
345
|
type: 'dieBound';
|
|
@@ -311,6 +350,11 @@ export type RollPart = (RollPartBase & {
|
|
|
311
350
|
type: 'successCount';
|
|
312
351
|
threshold: ResolvedComparePoint;
|
|
313
352
|
failThreshold?: ResolvedComparePoint;
|
|
353
|
+
/**
|
|
354
|
+
* The tallied pool, sharing `DieResult` references with `target`.
|
|
355
|
+
* Keeps `'meta'` dice, as `RollResult.rolls` does.
|
|
356
|
+
*/
|
|
357
|
+
rolls: DieResult[];
|
|
314
358
|
target: RollPart;
|
|
315
359
|
successes: number;
|
|
316
360
|
failures: number;
|
|
@@ -414,6 +458,14 @@ export type RollResult = Readonly<{
|
|
|
414
458
|
* arithmetic on top of a success count (e.g. `{5d6>=5}+2`) affects `total`
|
|
415
459
|
* but not `successes`. Success counts are terminal, so the group braces are
|
|
416
460
|
* required: `5d6>=5 * 2` is an `INVALID_SUCCESS_COUNT_TARGET` parse error.
|
|
461
|
+
*
|
|
462
|
+
* Braces also let a second count re-count the same pool (`{4d6>=5}<=2f5`).
|
|
463
|
+
* The outermost count owns the outcome: it re-scores the pool against its own
|
|
464
|
+
* thresholds, so no die is ever both a success and a failure, and dice it
|
|
465
|
+
* does not count come out untagged rather than keeping the inner count's
|
|
466
|
+
* tags. The DC side of a `vs` is never tallied here; it keeps whatever tags
|
|
467
|
+
* an inner count gave it, unless the outer count scores subtotals rather
|
|
468
|
+
* than dice, which leaves every die untagged.
|
|
417
469
|
*/
|
|
418
470
|
successes?: number;
|
|
419
471
|
/**
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/C;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG,GAAG,GAAG,IAAI,GAAG,GAAG,GAAG,IAAI,GAAG,GAAG,CAAC;AAEtD;;;;;;;;;GASG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAiIA,MAAM,CAAN,IAAY,eAKX;AALD,WAAY,eAAe;IACzB,2EAAmB,CAAA;IACnB,2DAAW,CAAA;IACX,2DAAW,CAAA;IACX,2EAAmB,CAAA;AACrB,CAAC,EALW,eAAe,KAAf,eAAe,QAK1B"}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const version = "3.
|
|
1
|
+
export declare const version = "3.2.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const version = '3.
|
|
1
|
+
export const version = '3.2.0';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "roll-parser",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "High-performance dice notation parser for tabletop RPGs. TypeScript-first, runs on Node, Bun, and browsers with zero dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
"types": "./dist/index.d.ts",
|
|
13
13
|
"default": "./dist/index.js"
|
|
14
14
|
},
|
|
15
|
+
"./render": {
|
|
16
|
+
"types": "./dist/render.d.ts",
|
|
17
|
+
"default": "./dist/render.js"
|
|
18
|
+
},
|
|
15
19
|
"./testing": {
|
|
16
20
|
"types": "./dist/testing.d.ts",
|
|
17
21
|
"default": "./dist/testing.js"
|
|
@@ -63,7 +67,7 @@
|
|
|
63
67
|
"workspaces": ["scripts/browser-smoke", "scripts/docs"],
|
|
64
68
|
"scripts": {
|
|
65
69
|
"prepare": "git rev-parse --git-dir > /dev/null 2>&1 && git config core.hooksPath .githooks || exit 0",
|
|
66
|
-
"typecheck": "tsc --noEmit && bun run build && tsc --noEmit -p site/tsconfig.json && tsc --noEmit -p scripts/tsconfig.json && tsc --noEmit -p bench/tsconfig.json",
|
|
70
|
+
"typecheck": "tsc --noEmit && bun run build && tsc --noEmit -p site/tsconfig.json && tsc --noEmit -p site/tsconfig.test.json && tsc --noEmit -p scripts/tsconfig.json && tsc --noEmit -p bench/tsconfig.json",
|
|
67
71
|
"check": "bun typecheck && biome check .",
|
|
68
72
|
"check:fix": "bun typecheck && biome check --write .",
|
|
69
73
|
"check:version": "bun scripts/check-version.ts",
|
|
@@ -98,7 +102,7 @@
|
|
|
98
102
|
{
|
|
99
103
|
"name": "index.js (full library)",
|
|
100
104
|
"path": "dist/index.js",
|
|
101
|
-
"limit": "12.
|
|
105
|
+
"limit": "12.85 kB"
|
|
102
106
|
},
|
|
103
107
|
{
|
|
104
108
|
"name": "index.js — { parse }",
|
|
@@ -110,7 +114,13 @@
|
|
|
110
114
|
"name": "index.js — { roll }",
|
|
111
115
|
"path": "dist/index.js",
|
|
112
116
|
"import": "{ roll }",
|
|
113
|
-
"limit": "12 kB"
|
|
117
|
+
"limit": "12.5 kB"
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"name": "render.js — { renderBreakdown }",
|
|
121
|
+
"path": "dist/render.js",
|
|
122
|
+
"import": "{ renderBreakdown }",
|
|
123
|
+
"limit": "2 kB"
|
|
114
124
|
},
|
|
115
125
|
{
|
|
116
126
|
"name": "testing.js — { createMockRng }",
|
package/src/cli/format.ts
CHANGED
|
@@ -6,8 +6,22 @@
|
|
|
6
6
|
* @module cli/format
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { type DieMarks, renderBreakdown } from '../render.js';
|
|
9
10
|
import type { RollResult } from '../types.js';
|
|
10
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Terminal stand-ins for the markdown markers `RollResult.rendered` uses:
|
|
14
|
+
* dropped dice become `(value)`, successes `[value]`, failures `{value}`, so
|
|
15
|
+
* the per-die classification stays visible with no markup dependency. A
|
|
16
|
+
* dropped group sub-roll takes the same parentheses as a dropped die.
|
|
17
|
+
*/
|
|
18
|
+
const TERMINAL_MARKS: DieMarks = {
|
|
19
|
+
dropped: (_die, text) => `(${text})`,
|
|
20
|
+
success: (_die, text) => `[${text}]`,
|
|
21
|
+
failure: (_die, text) => `{${text}}`,
|
|
22
|
+
droppedGroup: (inner) => `(${inner})`,
|
|
23
|
+
};
|
|
24
|
+
|
|
11
25
|
/**
|
|
12
26
|
* Output mode selectors for {@link formatResult}.
|
|
13
27
|
*/
|
|
@@ -42,27 +56,5 @@ export function formatResult(result: RollResult, options: FormatOptions = {}): s
|
|
|
42
56
|
return String(result.total);
|
|
43
57
|
}
|
|
44
58
|
|
|
45
|
-
return
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Converts markdown-style dice markers to terminal-friendly forms.
|
|
50
|
-
*
|
|
51
|
-
* The evaluator uses markdown syntax in the rendered field:
|
|
52
|
-
* `~~value~~` — dropped dice or dropped group sub-rolls
|
|
53
|
-
* `**value**` — dice counted as success
|
|
54
|
-
* `__value__` — dice counted as failure
|
|
55
|
-
*
|
|
56
|
-
* For plain terminals these become `(value)`, `[value]`, and `{value}` so
|
|
57
|
-
* the per-die classification stays visible without any markup dependency.
|
|
58
|
-
* Dropped spans can wrap a whole sub-roll (e.g. `~~1d8[2]~~` from
|
|
59
|
-
* `{1d8, 1d10}kh1`), so the strikethrough pattern accepts any tilde-free
|
|
60
|
-
* content, not just a single number. The evaluator never nests `~~`
|
|
61
|
-
* (see `stripInnerMarkers`), so the tilde-free span match is safe.
|
|
62
|
-
*/
|
|
63
|
-
function formatRendered(rendered: string): string {
|
|
64
|
-
return rendered
|
|
65
|
-
.replace(/\*\*(-?\d+)\*\*/g, '[$1]')
|
|
66
|
-
.replace(/__(-?\d+)__/g, '{$1}')
|
|
67
|
-
.replace(/~~([^~]+)~~/g, '($1)');
|
|
59
|
+
return renderBreakdown(result, TERMINAL_MARKS);
|
|
68
60
|
}
|
package/src/evaluator/die.ts
CHANGED
|
@@ -37,7 +37,8 @@ export function createDieResult(
|
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
39
|
* Creates a Fate/Fudge die result. Uses `sides = 0` as a sentinel — Fate dice
|
|
40
|
-
* have no max-face concept, so `critical` and `fumble`
|
|
40
|
+
* have no max-face concept, so `critical` and `fumble` start `false` and the
|
|
41
|
+
* default rule never sets them. An explicit `cs`/`cf` threshold still can.
|
|
41
42
|
*/
|
|
42
43
|
export function createFateDieResult(result: number, modifiers: DieModifier[]): DieResult {
|
|
43
44
|
return {
|
package/src/evaluator/env.ts
CHANGED
|
@@ -10,6 +10,17 @@
|
|
|
10
10
|
|
|
11
11
|
import { EvaluatorError } from '../errors.js';
|
|
12
12
|
import type { ASTNode } from '../parser/ast.js';
|
|
13
|
+
import type { DieResult, ResolvedCritThreshold } from '../types.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A resolved `cs`/`cf` pair, recorded per die so that dice minted later by
|
|
17
|
+
* explode or reroll can be judged by the rule the user declared instead of
|
|
18
|
+
* the built-in default.
|
|
19
|
+
*/
|
|
20
|
+
export type CritRule = {
|
|
21
|
+
readonly success: readonly ResolvedCritThreshold[];
|
|
22
|
+
readonly fail: readonly ResolvedCritThreshold[];
|
|
23
|
+
};
|
|
13
24
|
|
|
14
25
|
/**
|
|
15
26
|
* Per-evaluation shared environment (created once, shared across all branches).
|
|
@@ -26,8 +37,20 @@ export type EvalEnv = {
|
|
|
26
37
|
* Set to `true` by `evalSuccessCount`. Propagates through the shared env
|
|
27
38
|
* so `evaluate()` can include `successes`/`failures` fields even when no
|
|
28
39
|
* die was tagged (impossible threshold).
|
|
40
|
+
*
|
|
41
|
+
* ! Set *after* the target is evaluated, not before. `evalSuccessCount` reads
|
|
42
|
+
* ! the pre-set value to learn whether an inner count already tagged its pool
|
|
43
|
+
* ! — moving the assignment back to the top makes it read its own write.
|
|
29
44
|
*/
|
|
30
45
|
hasSuccessCount: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* What a multi-sub-roll group count (`{2d6, 2d6}>=10`) scored. Its units are
|
|
48
|
+
* subtotals, which exist only as throwaway synthetic dice, so these verdicts
|
|
49
|
+
* reach the top-level tally here rather than as tags on a die. Every path
|
|
50
|
+
* that releases `TALLY_FLAGS` releases these too.
|
|
51
|
+
*/
|
|
52
|
+
subtotalSuccesses: number;
|
|
53
|
+
subtotalFailures: number;
|
|
31
54
|
/**
|
|
32
55
|
* `true` while the evaluator is inside a `VersusNode`'s roll or DC
|
|
33
56
|
* sub-evaluation. `evalVersus` rejects nesting via this flag — catches
|
|
@@ -35,6 +58,41 @@ export type EvalEnv = {
|
|
|
35
58
|
* left-chain check.
|
|
36
59
|
*/
|
|
37
60
|
insideVersus: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* `true` once a `vs` has tagged its DC dice `'dc'`. Lets every pool
|
|
63
|
+
* operation skip its per-die `isVersusDc` check outright — the tag exists in
|
|
64
|
+
* a small minority of notation, and the call inside the loop cost 11-38% on
|
|
65
|
+
* keep/drop, success, and sort notation that can never carry one.
|
|
66
|
+
*
|
|
67
|
+
* ! Monotonic: set by `evalVersus`, never cleared. `insideVersus` is not a
|
|
68
|
+
* ! model for it — that flag resets in a `finally`, and it is false exactly
|
|
69
|
+
* ! when the tagged DC dice become visible to the enclosing pool.
|
|
70
|
+
*/
|
|
71
|
+
hasVersusDc: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Crit rule per die, keyed on the `DieResult` object itself. Populated by
|
|
74
|
+
* `applyCritThresholds`; read by explode and reroll so a die they mint
|
|
75
|
+
* inherits the rule of the die it descended from.
|
|
76
|
+
*
|
|
77
|
+
* Out of band rather than a `DieResult` field because `DieResult` is public
|
|
78
|
+
* and serialized. `undefined` until the first `cs`/`cf` node — declared here
|
|
79
|
+
* so the shape stays stable for notation that has none.
|
|
80
|
+
*/
|
|
81
|
+
critRules: WeakMap<DieResult, CritRule> | undefined;
|
|
82
|
+
/**
|
|
83
|
+
* Dice minted as explosion continuations by `!` / `!p`, keyed on the
|
|
84
|
+
* `DieResult` object itself. Read by `extractNatural`, which counts them out
|
|
85
|
+
* of the versus primaries — the `'exploded'` tag cannot say it alone, since
|
|
86
|
+
* a compound explode stamps it on the original die it accumulated into.
|
|
87
|
+
*
|
|
88
|
+
* Out of band for the same reason as {@link EvalEnv.critRules}: `DieResult`
|
|
89
|
+
* is public and serialized.
|
|
90
|
+
*
|
|
91
|
+
* ! Only populated while {@link EvalEnv.insideVersus} — nothing outside a
|
|
92
|
+
* ! `vs` reads it, and the `add` per appended die is not free. Any new
|
|
93
|
+
* ! reader must be on a versus path too.
|
|
94
|
+
*/
|
|
95
|
+
explosionDice: WeakSet<DieResult> | undefined;
|
|
38
96
|
/**
|
|
39
97
|
* User-supplied variable map for `@name` / `@{name}` references. Always
|
|
40
98
|
* defined — `evaluate()` defaults to an empty object so lookups can be
|