roll-parser 2.3.2 → 3.0.0-alpha.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/README.md +47 -178
- package/dist/cli/args.d.ts +35 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/format.d.ts +20 -0
- package/dist/cli/format.d.ts.map +1 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli.js +1775 -0
- package/dist/errors.d.ts +39 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/evaluator/evaluator.d.ts +65 -0
- package/dist/evaluator/evaluator.d.ts.map +1 -0
- package/dist/evaluator/index.d.ts +8 -0
- package/dist/evaluator/index.d.ts.map +1 -0
- package/dist/evaluator/modifiers/compare.d.ts +15 -0
- package/dist/evaluator/modifiers/compare.d.ts.map +1 -0
- package/dist/evaluator/modifiers/explode.d.ts +44 -0
- package/dist/evaluator/modifiers/explode.d.ts.map +1 -0
- package/dist/evaluator/modifiers/keep-drop.d.ts +44 -0
- package/dist/evaluator/modifiers/keep-drop.d.ts.map +1 -0
- package/dist/evaluator/modifiers/reroll.d.ts +33 -0
- package/dist/evaluator/modifiers/reroll.d.ts.map +1 -0
- package/dist/evaluator/modifiers/success-count.d.ts +28 -0
- package/dist/evaluator/modifiers/success-count.d.ts.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1723 -0
- package/dist/index.mjs +1724 -0
- package/dist/lexer/lexer.d.ts +75 -0
- package/dist/lexer/lexer.d.ts.map +1 -0
- package/dist/lexer/tokens.d.ts +87 -0
- package/dist/lexer/tokens.d.ts.map +1 -0
- package/dist/parser/ast.d.ts +183 -0
- package/dist/parser/ast.d.ts.map +1 -0
- package/dist/parser/parser.d.ts +102 -0
- package/dist/parser/parser.d.ts.map +1 -0
- package/dist/rng/index.d.ts +8 -0
- package/dist/rng/index.d.ts.map +1 -0
- package/dist/rng/mock.d.ts +36 -0
- package/dist/rng/mock.d.ts.map +1 -0
- package/dist/rng/seeded.d.ts +33 -0
- package/dist/rng/seeded.d.ts.map +1 -0
- package/dist/rng/types.d.ts +24 -0
- package/dist/rng/types.d.ts.map +1 -0
- package/dist/roll.d.ts +47 -0
- package/dist/roll.d.ts.map +1 -0
- package/dist/testing.d.ts +11 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +38 -0
- package/dist/testing.mjs +39 -0
- package/dist/types.d.ts +105 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +62 -43
- package/src/cli/args.ts +72 -0
- package/src/cli/format.ts +45 -0
- package/src/cli/index.ts +75 -0
- package/src/errors.ts +78 -0
- package/src/evaluator/evaluator.ts +837 -0
- package/src/evaluator/index.ts +14 -0
- package/src/evaluator/modifiers/compare.ts +29 -0
- package/src/evaluator/modifiers/explode.ts +215 -0
- package/src/evaluator/modifiers/keep-drop.ts +151 -0
- package/src/evaluator/modifiers/reroll.ts +172 -0
- package/src/evaluator/modifiers/success-count.ts +59 -0
- package/src/index.ts +72 -0
- package/src/lexer/lexer.ts +281 -0
- package/src/lexer/tokens.ts +147 -0
- package/src/parser/ast.ts +261 -0
- package/src/parser/parser.ts +716 -0
- package/src/rng/index.ts +8 -0
- package/src/rng/mock.ts +65 -0
- package/src/rng/seeded.ts +127 -0
- package/src/rng/types.ts +25 -0
- package/src/roll.ts +66 -0
- package/src/testing.ts +16 -0
- package/src/types.ts +112 -0
- package/bin/help.txt +0 -19
- package/bin/roll-parser.js +0 -23
- package/dist/roll-parser.js +0 -697
- package/dist/roll-parser.min.js +0 -1
- package/index.js +0 -24
- package/src/complex/parse.js +0 -37
- package/src/complex/parseAndRoll.js +0 -21
- package/src/complex/parseAndRollClassic.js +0 -20
- package/src/complex/parseAndRollSimple.js +0 -19
- package/src/complex/parseAndRollWod.js +0 -20
- package/src/complex/parseClassicRoll.js +0 -22
- package/src/complex/parseSimpleRoll.js +0 -21
- package/src/complex/parseWodRoll.js +0 -21
- package/src/converter.js +0 -45
- package/src/grammar.js +0 -14
- package/src/mapper.js +0 -50
- package/src/normalizer.js +0 -51
- package/src/object/Result.js +0 -23
- package/src/object/Roll.js +0 -26
- package/src/object/Type.js +0 -5
- package/src/object/WodRoll.js +0 -29
- package/src/parser.js +0 -43
- package/src/random.js +0 -22
- package/src/roller.js +0 -106
- package/src/stringifier.js +0 -33
package/src/rng/mock.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock RNG for deterministic testing.
|
|
3
|
+
*
|
|
4
|
+
* @module rng/mock
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { RNG } from './types';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Error thrown when MockRNG exhausts its predefined values.
|
|
11
|
+
*
|
|
12
|
+
* This is intentional behavior to catch incorrect roll counts in tests.
|
|
13
|
+
* If you see this error, your test is consuming more random values than expected.
|
|
14
|
+
*/
|
|
15
|
+
export class MockRNGExhaustedError extends Error {
|
|
16
|
+
readonly consumed: number;
|
|
17
|
+
|
|
18
|
+
constructor(consumed: number) {
|
|
19
|
+
super(`MockRNG exhausted: consumed ${consumed} values, no more available`);
|
|
20
|
+
this.name = 'MockRNGExhaustedError';
|
|
21
|
+
this.consumed = consumed;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Creates a mock RNG that returns predefined values in sequence.
|
|
27
|
+
*
|
|
28
|
+
* IMPORTANT: Throws MockRNGExhaustedError when all values are consumed.
|
|
29
|
+
* This behavior catches incorrect roll counts in tests - it never wraps around.
|
|
30
|
+
*
|
|
31
|
+
* @param values - Array of values to return (dice results for nextInt, floats for next)
|
|
32
|
+
* @returns RNG instance returning predefined values
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* const rng = createMockRng([4, 2, 6]);
|
|
37
|
+
* rng.nextInt(1, 6); // Returns 4
|
|
38
|
+
* rng.nextInt(1, 6); // Returns 2
|
|
39
|
+
* rng.nextInt(1, 6); // Returns 6
|
|
40
|
+
* rng.nextInt(1, 6); // Throws MockRNGExhaustedError
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export function createMockRng(values: number[]): RNG {
|
|
44
|
+
let index = 0;
|
|
45
|
+
|
|
46
|
+
const getNext = (): number => {
|
|
47
|
+
const value = values[index];
|
|
48
|
+
if (value === undefined) {
|
|
49
|
+
throw new MockRNGExhaustedError(index);
|
|
50
|
+
}
|
|
51
|
+
index++;
|
|
52
|
+
return value;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
next: getNext,
|
|
57
|
+
nextInt: (min: number, max: number): number => {
|
|
58
|
+
const value = getNext();
|
|
59
|
+
if (value < min || value > max) {
|
|
60
|
+
throw new RangeError(`MockRNG value ${value} is out of bounds [${min}, ${max}]`);
|
|
61
|
+
}
|
|
62
|
+
return value;
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seedable RNG using xorshift128 algorithm.
|
|
3
|
+
*
|
|
4
|
+
* @module rng/seeded
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { RNG } from './types';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Seedable pseudo-random number generator using xorshift128.
|
|
11
|
+
*
|
|
12
|
+
* Produces reproducible sequences from identical seeds.
|
|
13
|
+
* Period: 2^128 - 1
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* // Same seed = same sequence
|
|
18
|
+
* const rng1 = new SeededRNG('test-seed');
|
|
19
|
+
* const rng2 = new SeededRNG('test-seed');
|
|
20
|
+
* rng1.nextInt(1, 6) === rng2.nextInt(1, 6); // true
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export class SeededRNG implements RNG {
|
|
24
|
+
private s0: number;
|
|
25
|
+
private s1: number;
|
|
26
|
+
private s2: number;
|
|
27
|
+
private s3: number;
|
|
28
|
+
|
|
29
|
+
constructor(seed?: string | number) {
|
|
30
|
+
// Initialize state to zero, will be set by initState
|
|
31
|
+
this.s0 = 0;
|
|
32
|
+
this.s1 = 0;
|
|
33
|
+
this.s2 = 0;
|
|
34
|
+
this.s3 = 0;
|
|
35
|
+
|
|
36
|
+
this.initState(seed);
|
|
37
|
+
|
|
38
|
+
// Warm-up: discard first 20 values for better initial distribution
|
|
39
|
+
for (let i = 0; i < 20; i++) {
|
|
40
|
+
this.nextUint32();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private initState(seed?: string | number): void {
|
|
45
|
+
const numSeed =
|
|
46
|
+
seed == null
|
|
47
|
+
? (Date.now() ^ (Math.random() * 0xffffffff)) >>> 0
|
|
48
|
+
: typeof seed === 'string'
|
|
49
|
+
? this.hashString(seed)
|
|
50
|
+
: seed >>> 0;
|
|
51
|
+
|
|
52
|
+
// Split seed into 4 state values using splitmix32
|
|
53
|
+
let s = numSeed;
|
|
54
|
+
const state: number[] = [];
|
|
55
|
+
|
|
56
|
+
for (let i = 0; i < 4; i++) {
|
|
57
|
+
s = (s + 0x9e3779b9) >>> 0;
|
|
58
|
+
let z = s;
|
|
59
|
+
z = Math.imul(z ^ (z >>> 16), 0x85ebca6b) >>> 0;
|
|
60
|
+
z = Math.imul(z ^ (z >>> 13), 0xc2b2ae35) >>> 0;
|
|
61
|
+
state.push((z ^ (z >>> 16)) >>> 0);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
this.s0 = state[0] ?? 0;
|
|
65
|
+
this.s1 = state[1] ?? 0;
|
|
66
|
+
this.s2 = state[2] ?? 0;
|
|
67
|
+
this.s3 = state[3] ?? 0;
|
|
68
|
+
|
|
69
|
+
// Ensure non-zero state (xorshift requires at least one non-zero)
|
|
70
|
+
if (this.s0 === 0 && this.s1 === 0 && this.s2 === 0 && this.s3 === 0) {
|
|
71
|
+
this.s0 = 1;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private hashString(str: string): number {
|
|
76
|
+
// djb2 hash algorithm
|
|
77
|
+
let hash = 5381;
|
|
78
|
+
for (let i = 0; i < str.length; i++) {
|
|
79
|
+
hash = ((hash << 5) + hash + str.charCodeAt(i)) >>> 0;
|
|
80
|
+
}
|
|
81
|
+
return hash;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private nextUint32(): number {
|
|
85
|
+
// xorshift128 algorithm
|
|
86
|
+
let t = this.s3;
|
|
87
|
+
const s = this.s0;
|
|
88
|
+
|
|
89
|
+
this.s3 = this.s2;
|
|
90
|
+
this.s2 = this.s1;
|
|
91
|
+
this.s1 = s;
|
|
92
|
+
|
|
93
|
+
t ^= t << 11;
|
|
94
|
+
t ^= t >>> 8;
|
|
95
|
+
this.s0 = (t ^ s ^ (s >>> 19)) >>> 0;
|
|
96
|
+
|
|
97
|
+
return this.s0;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
next(): number {
|
|
101
|
+
// Convert uint32 to [0, 1) float
|
|
102
|
+
return this.nextUint32() / 0x100000000;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
nextInt(min: number, max: number): number {
|
|
106
|
+
// Handle inverted bounds
|
|
107
|
+
const lo = min > max ? max : min;
|
|
108
|
+
const hi = min > max ? min : max;
|
|
109
|
+
|
|
110
|
+
const range = hi - lo + 1;
|
|
111
|
+
|
|
112
|
+
// Single value case
|
|
113
|
+
if (range <= 1) {
|
|
114
|
+
return lo;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Rejection sampling for unbiased distribution
|
|
118
|
+
// Avoids modulo bias by rejecting values that would cause uneven distribution
|
|
119
|
+
const threshold = (0x100000000 - range) % range;
|
|
120
|
+
let value: number;
|
|
121
|
+
do {
|
|
122
|
+
value = this.nextUint32();
|
|
123
|
+
} while (value < threshold);
|
|
124
|
+
|
|
125
|
+
return lo + (value % range);
|
|
126
|
+
}
|
|
127
|
+
}
|
package/src/rng/types.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Random Number Generator interface.
|
|
3
|
+
*
|
|
4
|
+
* All dice rolling MUST use this interface - never use Math.random() directly.
|
|
5
|
+
*
|
|
6
|
+
* @module rng/types
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Random Number Generator interface for dice rolling.
|
|
11
|
+
*/
|
|
12
|
+
export type RNG = {
|
|
13
|
+
/**
|
|
14
|
+
* Returns a random floating-point number in the range [0, 1).
|
|
15
|
+
*/
|
|
16
|
+
next(): number;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Returns a random integer in the inclusive range [min, max].
|
|
20
|
+
*
|
|
21
|
+
* @param min - Minimum value (inclusive)
|
|
22
|
+
* @param max - Maximum value (inclusive)
|
|
23
|
+
*/
|
|
24
|
+
nextInt(min: number, max: number): number;
|
|
25
|
+
};
|
package/src/roll.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main public API for rolling dice expressions.
|
|
3
|
+
*
|
|
4
|
+
* @module roll
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { RNG } from './rng/types';
|
|
8
|
+
import type { EvaluateOptions, RollResult } from './types';
|
|
9
|
+
import { evaluate } from './evaluator/evaluator';
|
|
10
|
+
import { lex } from './lexer/lexer';
|
|
11
|
+
import { Parser } from './parser/parser';
|
|
12
|
+
import { SeededRNG } from './rng/seeded';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Options for the roll function.
|
|
16
|
+
*/
|
|
17
|
+
export type RollOptions = {
|
|
18
|
+
/** Custom RNG instance (takes precedence over seed) */
|
|
19
|
+
rng?: RNG;
|
|
20
|
+
/** Seed for deterministic rolls (ignored if rng provided) */
|
|
21
|
+
seed?: string | number;
|
|
22
|
+
/** Maximum total dice allowed per evaluation (default: 10,000) */
|
|
23
|
+
maxDice?: number;
|
|
24
|
+
/** Maximum explosion iterations allowed per die (default: 1,000) */
|
|
25
|
+
maxExplodeIterations?: number;
|
|
26
|
+
/** Maximum reroll iterations allowed per die (default: 1,000) */
|
|
27
|
+
maxRerollIterations?: number;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Parses and evaluates a dice notation string.
|
|
32
|
+
*
|
|
33
|
+
* @param notation - Dice notation (e.g., "2d6+3", "4d6kh3")
|
|
34
|
+
* @param options - Optional configuration (RNG or seed)
|
|
35
|
+
* @returns Complete roll result with total and metadata
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* // Random roll
|
|
40
|
+
* const result = roll('2d6+3');
|
|
41
|
+
* console.log(result.total); // 5-15
|
|
42
|
+
*
|
|
43
|
+
* // Seeded for reproducibility
|
|
44
|
+
* const r1 = roll('4d6', { seed: 'test' });
|
|
45
|
+
* const r2 = roll('4d6', { seed: 'test' });
|
|
46
|
+
* r1.total === r2.total; // true
|
|
47
|
+
*
|
|
48
|
+
* // Custom RNG for testing
|
|
49
|
+
* const result = roll('1d20', { rng: createMockRng([15]) });
|
|
50
|
+
* result.total; // 15
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export function roll(notation: string, options: RollOptions = {}): RollResult {
|
|
54
|
+
const rng = options.rng ?? new SeededRNG(options.seed);
|
|
55
|
+
const tokens = lex(notation);
|
|
56
|
+
const ast = new Parser(tokens).parse();
|
|
57
|
+
const evalOptions: EvaluateOptions = { notation };
|
|
58
|
+
if (options.maxDice != null) evalOptions.maxDice = options.maxDice;
|
|
59
|
+
if (options.maxExplodeIterations != null) {
|
|
60
|
+
evalOptions.maxExplodeIterations = options.maxExplodeIterations;
|
|
61
|
+
}
|
|
62
|
+
if (options.maxRerollIterations != null) {
|
|
63
|
+
evalOptions.maxRerollIterations = options.maxRerollIterations;
|
|
64
|
+
}
|
|
65
|
+
return evaluate(ast, rng, evalOptions);
|
|
66
|
+
}
|
package/src/testing.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test utilities for roll-parser consumers.
|
|
3
|
+
*
|
|
4
|
+
* Import from `roll-parser/testing` for deterministic dice testing.
|
|
5
|
+
*
|
|
6
|
+
* @module testing
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Direct value exports force the bundler to inline the code
|
|
10
|
+
import {
|
|
11
|
+
MockRNGExhaustedError as _MockRNGExhaustedError,
|
|
12
|
+
createMockRng as _createMockRng,
|
|
13
|
+
} from './rng/mock';
|
|
14
|
+
|
|
15
|
+
export const createMockRng = _createMockRng;
|
|
16
|
+
export const MockRNGExhaustedError = _MockRNGExhaustedError;
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared type definitions for roll results and comparison primitives.
|
|
3
|
+
*
|
|
4
|
+
* @module types
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { ASTNode } from './parser/ast';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Comparison operator for compare points.
|
|
11
|
+
*/
|
|
12
|
+
export type CompareOp = '>' | '>=' | '<' | '<=' | '=';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A comparison threshold used by exploding dice, reroll, and success counting.
|
|
16
|
+
*
|
|
17
|
+
* The value is an ASTNode to support computed thresholds (e.g., `>=ceil(5)`),
|
|
18
|
+
* matching the pattern used by DiceNode.count and DiceNode.sides.
|
|
19
|
+
*/
|
|
20
|
+
export type ComparePoint = {
|
|
21
|
+
operator: CompareOp;
|
|
22
|
+
value: ASTNode;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Modifier flags applied to individual die results.
|
|
27
|
+
*/
|
|
28
|
+
export type DieModifier = 'dropped' | 'kept' | 'exploded' | 'rerolled' | 'success' | 'failure';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* PF2e Degree of Success. Produced by the `vs` operator when comparing a
|
|
32
|
+
* roll against a Difficulty Class. Ordering is significant — natural 20
|
|
33
|
+
* upgrades one step and natural 1 downgrades one step.
|
|
34
|
+
*/
|
|
35
|
+
export enum DegreeOfSuccess {
|
|
36
|
+
CriticalFailure = 0,
|
|
37
|
+
Failure = 1,
|
|
38
|
+
Success = 2,
|
|
39
|
+
CriticalSuccess = 3,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Individual die roll result with metadata.
|
|
44
|
+
*/
|
|
45
|
+
export type DieResult = {
|
|
46
|
+
/**
|
|
47
|
+
* Number of sides on the die. Normal dice use `sides >= 1`. Fate/Fudge
|
|
48
|
+
* dice use `sides = 0` as a sentinel — they have no configurable sides
|
|
49
|
+
* and always produce results in {-1, 0, +1}.
|
|
50
|
+
*/
|
|
51
|
+
sides: number;
|
|
52
|
+
/** The rolled value */
|
|
53
|
+
result: number;
|
|
54
|
+
/** Modifiers applied to this die */
|
|
55
|
+
modifiers: DieModifier[];
|
|
56
|
+
/** True if rolled the maximum value (always false for Fate dice) */
|
|
57
|
+
critical: boolean;
|
|
58
|
+
/** True if rolled 1 (always false for Fate dice) */
|
|
59
|
+
fumble: boolean;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Complete roll result with all metadata.
|
|
64
|
+
*/
|
|
65
|
+
export type RollResult = {
|
|
66
|
+
/** Final computed total */
|
|
67
|
+
total: number;
|
|
68
|
+
/** Original input notation */
|
|
69
|
+
notation: string;
|
|
70
|
+
/** Normalized expression */
|
|
71
|
+
expression: string;
|
|
72
|
+
/** Rendered result with individual rolls shown */
|
|
73
|
+
rendered: string;
|
|
74
|
+
/** All individual die results */
|
|
75
|
+
rolls: DieResult[];
|
|
76
|
+
/**
|
|
77
|
+
* Number of dice tagged as success across the whole expression. Present
|
|
78
|
+
* only when a success-counting modifier was used. Independent of `total` —
|
|
79
|
+
* arithmetic on top of a success count (e.g. `5d6>=5 * 2`) affects `total`
|
|
80
|
+
* but not `successes`.
|
|
81
|
+
*/
|
|
82
|
+
successes?: number;
|
|
83
|
+
/**
|
|
84
|
+
* Number of dice tagged as failure across the whole expression. Present
|
|
85
|
+
* only when a success-counting modifier with a fail threshold was used.
|
|
86
|
+
*/
|
|
87
|
+
failures?: number;
|
|
88
|
+
/**
|
|
89
|
+
* PF2e Degree of Success. Present only when the expression used the `vs`
|
|
90
|
+
* operator at the top level (e.g. `1d20+10 vs 25`).
|
|
91
|
+
*/
|
|
92
|
+
degree?: DegreeOfSuccess;
|
|
93
|
+
/**
|
|
94
|
+
* Natural d20 value used for PF2e upgrade/downgrade — present only when
|
|
95
|
+
* exactly one kept d20 was rolled on the roll side of a `vs` expression.
|
|
96
|
+
*/
|
|
97
|
+
natural?: number;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Options for the evaluate function.
|
|
102
|
+
*/
|
|
103
|
+
export type EvaluateOptions = {
|
|
104
|
+
/** Original notation string (for result metadata) */
|
|
105
|
+
notation?: string;
|
|
106
|
+
/** Maximum total dice allowed per evaluation (default: 10,000) */
|
|
107
|
+
maxDice?: number;
|
|
108
|
+
/** Maximum explosion iterations allowed per die (default: 1,000) */
|
|
109
|
+
maxExplodeIterations?: number;
|
|
110
|
+
/** Maximum reroll iterations allowed per die (default: 1,000) */
|
|
111
|
+
maxRerollIterations?: number;
|
|
112
|
+
};
|
package/bin/help.txt
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
Usage:
|
|
2
|
-
roll-parser [options] [<rolls>]
|
|
3
|
-
|
|
4
|
-
Options:
|
|
5
|
-
--help # Print the module options and usage
|
|
6
|
-
|
|
7
|
-
Arguments:
|
|
8
|
-
rolls # Whitespace separated list of roll (classic or WoD) notations.
|
|
9
|
-
If omitted, classic d20 roll will be used by default.
|
|
10
|
-
Use quotes on arguments if WoD notation is passed, to prevent problems
|
|
11
|
-
with special characters like '>'.
|
|
12
|
-
Classic: 2d20+1
|
|
13
|
-
World of Darkness: 6d10!>6f1
|
|
14
|
-
|
|
15
|
-
Examples:
|
|
16
|
-
roll-parser 2d20+1
|
|
17
|
-
roll-parser 4d10 5d6-1 d100
|
|
18
|
-
roll-parser '6d10!>6f1'
|
|
19
|
-
roll-parser --help
|
package/bin/roll-parser.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
process.title = 'roll-parser';
|
|
4
|
-
|
|
5
|
-
/* eslint-disable max-len, no-console, no-var, vars-on-top, prefer-spread, global-require, import/no-dynamic-require, wrap-iife, no-void */
|
|
6
|
-
|
|
7
|
-
const argv = require( 'minimist' )( process.argv.slice( 2 ));
|
|
8
|
-
const path = require( 'path' );
|
|
9
|
-
const fs = require( 'fs' );
|
|
10
|
-
|
|
11
|
-
const rollParser = require( '../index' );
|
|
12
|
-
|
|
13
|
-
const format = roll => `${ rollParser.parseAndRoll( roll ) || 'Invalid roll notation.' }`;
|
|
14
|
-
|
|
15
|
-
void function cmd() {
|
|
16
|
-
// --help
|
|
17
|
-
if ( argv.help ) {
|
|
18
|
-
fs.createReadStream( path.resolve( __dirname, './help.txt' )).pipe( process.stdout );
|
|
19
|
-
} else {
|
|
20
|
-
const rolls = argv._.length > 0 ? argv._ : [ 'd20' ];
|
|
21
|
-
rolls.forEach( roll => console.log( format( roll )));
|
|
22
|
-
}
|
|
23
|
-
}();
|