@mcptoolshop/roll 1.0.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.
Files changed (75) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/LICENSE +21 -0
  3. package/README.es.md +204 -0
  4. package/README.fr.md +204 -0
  5. package/README.hi.md +204 -0
  6. package/README.it.md +204 -0
  7. package/README.ja.md +204 -0
  8. package/README.md +204 -0
  9. package/README.pt-BR.md +204 -0
  10. package/README.zh.md +204 -0
  11. package/dist/analyze/distribution.d.ts +6 -0
  12. package/dist/analyze/distribution.d.ts.map +1 -0
  13. package/dist/analyze/distribution.js +252 -0
  14. package/dist/analyze/distribution.js.map +1 -0
  15. package/dist/analyze/montecarlo.d.ts +5 -0
  16. package/dist/analyze/montecarlo.d.ts.map +1 -0
  17. package/dist/analyze/montecarlo.js +19 -0
  18. package/dist/analyze/montecarlo.js.map +1 -0
  19. package/dist/analyze/stats.d.ts +16 -0
  20. package/dist/analyze/stats.d.ts.map +1 -0
  21. package/dist/analyze/stats.js +66 -0
  22. package/dist/analyze/stats.js.map +1 -0
  23. package/dist/bin.d.ts +3 -0
  24. package/dist/bin.d.ts.map +1 -0
  25. package/dist/bin.js +267 -0
  26. package/dist/bin.js.map +1 -0
  27. package/dist/display/box.d.ts +5 -0
  28. package/dist/display/box.d.ts.map +1 -0
  29. package/dist/display/box.js +26 -0
  30. package/dist/display/box.js.map +1 -0
  31. package/dist/display/color.d.ts +12 -0
  32. package/dist/display/color.d.ts.map +1 -0
  33. package/dist/display/color.js +19 -0
  34. package/dist/display/color.js.map +1 -0
  35. package/dist/display/format.d.ts +13 -0
  36. package/dist/display/format.d.ts.map +1 -0
  37. package/dist/display/format.js +134 -0
  38. package/dist/display/format.js.map +1 -0
  39. package/dist/display/histogram.d.ts +7 -0
  40. package/dist/display/histogram.d.ts.map +1 -0
  41. package/dist/display/histogram.js +48 -0
  42. package/dist/display/histogram.js.map +1 -0
  43. package/dist/engine/random.d.ts +6 -0
  44. package/dist/engine/random.d.ts.map +1 -0
  45. package/dist/engine/random.js +17 -0
  46. package/dist/engine/random.js.map +1 -0
  47. package/dist/engine/roller.d.ts +19 -0
  48. package/dist/engine/roller.d.ts.map +1 -0
  49. package/dist/engine/roller.js +168 -0
  50. package/dist/engine/roller.js.map +1 -0
  51. package/dist/index.d.ts +27 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +37 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/loot/table.d.ts +27 -0
  56. package/dist/loot/table.d.ts.map +1 -0
  57. package/dist/loot/table.js +92 -0
  58. package/dist/loot/table.js.map +1 -0
  59. package/dist/parser/ast.d.ts +27 -0
  60. package/dist/parser/ast.d.ts.map +1 -0
  61. package/dist/parser/ast.js +2 -0
  62. package/dist/parser/ast.js.map +1 -0
  63. package/dist/parser/lexer.d.ts +7 -0
  64. package/dist/parser/lexer.d.ts.map +1 -0
  65. package/dist/parser/lexer.js +126 -0
  66. package/dist/parser/lexer.js.map +1 -0
  67. package/dist/parser/parser.d.ts +7 -0
  68. package/dist/parser/parser.d.ts.map +1 -0
  69. package/dist/parser/parser.js +188 -0
  70. package/dist/parser/parser.js.map +1 -0
  71. package/dist/parser/tokens.d.ts +25 -0
  72. package/dist/parser/tokens.d.ts.map +1 -0
  73. package/dist/parser/tokens.js +21 -0
  74. package/dist/parser/tokens.js.map +1 -0
  75. package/package.json +55 -0
@@ -0,0 +1,92 @@
1
+ import { parse } from "../parser/parser.js";
2
+ import { evaluate } from "../engine/roller.js";
3
+ import { cryptoRng } from "../engine/random.js";
4
+ /** Roll on a loot table, resolving nested tables and dice expressions. */
5
+ export function rollLootTable(tables, tableName, rng = cryptoRng, depth = 0) {
6
+ if (depth > 10) {
7
+ throw new Error("Loot table recursion depth exceeded (circular reference?)");
8
+ }
9
+ const table = tableName
10
+ ? tables.find((t) => t.table === tableName)
11
+ : tables[0];
12
+ if (!table) {
13
+ throw new Error(`Loot table not found: ${tableName ?? "(default)"}`);
14
+ }
15
+ // Calculate total weight
16
+ const totalWeight = table.items.reduce((sum, item) => sum + item.weight, 0);
17
+ if (totalWeight <= 0) {
18
+ throw new Error(`Loot table "${table.table}" has no valid items`);
19
+ }
20
+ // Weighted random selection
21
+ const roll = rng(1, totalWeight);
22
+ let cumulative = 0;
23
+ let selected;
24
+ for (const item of table.items) {
25
+ cumulative += item.weight;
26
+ if (roll <= cumulative) {
27
+ selected = item;
28
+ break;
29
+ }
30
+ }
31
+ if (!selected) {
32
+ selected = table.items[table.items.length - 1];
33
+ }
34
+ // If nested table reference, recurse
35
+ if (selected.table) {
36
+ return rollLootTable(tables, selected.table, rng, depth + 1);
37
+ }
38
+ // Resolve quantity
39
+ let quantity = 1;
40
+ if (selected.quantity) {
41
+ const ast = parse(selected.quantity);
42
+ quantity = evaluate(ast, rng).total;
43
+ }
44
+ // Resolve roll value
45
+ let rollValue;
46
+ let rollExpression;
47
+ if (selected.roll) {
48
+ const ast = parse(selected.roll);
49
+ rollValue = evaluate(ast, rng).total;
50
+ rollExpression = selected.roll;
51
+ }
52
+ return [{
53
+ item: selected.name,
54
+ quantity,
55
+ rollValue,
56
+ rollExpression,
57
+ fromTable: table.table,
58
+ }];
59
+ }
60
+ /** Validate a loot table collection. Returns errors or empty array. */
61
+ export function validateLootTables(tables) {
62
+ const errors = [];
63
+ const tableNames = new Set(tables.map((t) => t.table));
64
+ for (const table of tables) {
65
+ if (!table.table)
66
+ errors.push("Table missing name");
67
+ if (!table.items || table.items.length === 0) {
68
+ errors.push(`Table "${table.table}" has no items`);
69
+ }
70
+ for (const item of table.items) {
71
+ if (!item.name && !item.table) {
72
+ errors.push(`Item in "${table.table}" has no name or table reference`);
73
+ }
74
+ if (item.weight <= 0) {
75
+ errors.push(`Item "${item.name}" in "${table.table}" has invalid weight`);
76
+ }
77
+ if (item.table && !tableNames.has(item.table)) {
78
+ errors.push(`Table reference "${item.table}" not found (in "${table.table}")`);
79
+ }
80
+ if (item.roll) {
81
+ try {
82
+ parse(item.roll);
83
+ }
84
+ catch {
85
+ errors.push(`Invalid dice expression "${item.roll}" in "${table.table}"`);
86
+ }
87
+ }
88
+ }
89
+ }
90
+ return errors;
91
+ }
92
+ //# sourceMappingURL=table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table.js","sourceRoot":"","sources":["../../src/loot/table.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ export type ASTNode = NumberNode | DiceNode | BinaryOpNode | UnaryMinusNode;
2
+ export interface NumberNode {
3
+ type: "number";
4
+ value: number;
5
+ }
6
+ export interface DiceModifier {
7
+ kind: "kh" | "kl" | "dh" | "dl" | "explode";
8
+ value?: number;
9
+ }
10
+ export type DiceSides = number | "%" | "F";
11
+ export interface DiceNode {
12
+ type: "dice";
13
+ count: number;
14
+ sides: DiceSides;
15
+ modifiers: DiceModifier[];
16
+ }
17
+ export interface BinaryOpNode {
18
+ type: "binary";
19
+ op: "+" | "-" | "*" | "/";
20
+ left: ASTNode;
21
+ right: ASTNode;
22
+ }
23
+ export interface UnaryMinusNode {
24
+ type: "unary_minus";
25
+ operand: ASTNode;
26
+ }
27
+ //# sourceMappingURL=ast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../src/parser/ast.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG,UAAU,GAAG,QAAQ,GAAG,YAAY,GAAG,cAAc,CAAC;AAE5E,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC;AAE3C,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,CAAC;IACjB,SAAS,EAAE,YAAY,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,QAAQ,CAAC;IACf,EAAE,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;IAC1B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;CAClB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast.js","sourceRoot":"","sources":["../../src/parser/ast.ts"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ import { Token } from "./tokens.js";
2
+ export declare class LexerError extends Error {
3
+ position: number;
4
+ constructor(message: string, position: number);
5
+ }
6
+ export declare function tokenize(input: string): Token[];
7
+ //# sourceMappingURL=lexer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lexer.d.ts","sourceRoot":"","sources":["../../src/parser/lexer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAa,MAAM,aAAa,CAAC;AAE/C,qBAAa,UAAW,SAAQ,KAAK;IACC,QAAQ,EAAE,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAS,QAAQ,EAAE,MAAM;CAIrD;AASD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,EAAE,CAoH/C"}
@@ -0,0 +1,126 @@
1
+ import { TokenType } from "./tokens.js";
2
+ export class LexerError extends Error {
3
+ position;
4
+ constructor(message, position) {
5
+ super(message);
6
+ this.position = position;
7
+ this.name = "LexerError";
8
+ }
9
+ }
10
+ const TWO_CHAR_KEYWORDS = {
11
+ kh: TokenType.KH,
12
+ kl: TokenType.KL,
13
+ dh: TokenType.DH,
14
+ dl: TokenType.DL,
15
+ };
16
+ export function tokenize(input) {
17
+ const tokens = [];
18
+ let i = 0;
19
+ while (i < input.length) {
20
+ // Skip whitespace
21
+ if (input[i] === " " || input[i] === "\t") {
22
+ i++;
23
+ continue;
24
+ }
25
+ const pos = i;
26
+ const ch = input[i];
27
+ // Numbers
28
+ if (ch >= "0" && ch <= "9") {
29
+ let num = "";
30
+ while (i < input.length && input[i] >= "0" && input[i] <= "9") {
31
+ num += input[i];
32
+ i++;
33
+ }
34
+ tokens.push({ type: TokenType.NUMBER, value: num, position: pos });
35
+ continue;
36
+ }
37
+ // Two-char keywords (kh, kl, dh, dl) — but not 'd' alone
38
+ const twoChar = input.slice(i, i + 2).toLowerCase();
39
+ if (TWO_CHAR_KEYWORDS[twoChar]) {
40
+ // Make sure 'dh'/'dl' aren't confused with 'd' followed by a modifier
41
+ // Only match dh/dl if the previous token is a dice-related context
42
+ if (twoChar === "dh" || twoChar === "dl") {
43
+ // dh/dl are drop-highest/drop-lowest modifiers, only valid after dice
44
+ const lastToken = tokens[tokens.length - 1];
45
+ if (lastToken &&
46
+ (lastToken.type === TokenType.NUMBER ||
47
+ lastToken.type === TokenType.PERCENT ||
48
+ lastToken.type === TokenType.F ||
49
+ lastToken.type === TokenType.KH ||
50
+ lastToken.type === TokenType.KL ||
51
+ lastToken.type === TokenType.DH ||
52
+ lastToken.type === TokenType.DL ||
53
+ lastToken.type === TokenType.BANG)) {
54
+ tokens.push({
55
+ type: TWO_CHAR_KEYWORDS[twoChar],
56
+ value: twoChar,
57
+ position: pos,
58
+ });
59
+ i += 2;
60
+ continue;
61
+ }
62
+ }
63
+ else {
64
+ tokens.push({
65
+ type: TWO_CHAR_KEYWORDS[twoChar],
66
+ value: twoChar,
67
+ position: pos,
68
+ });
69
+ i += 2;
70
+ continue;
71
+ }
72
+ }
73
+ // Single characters
74
+ switch (ch.toLowerCase()) {
75
+ case "d":
76
+ tokens.push({ type: TokenType.D, value: ch, position: pos });
77
+ i++;
78
+ break;
79
+ case "f":
80
+ tokens.push({ type: TokenType.F, value: ch, position: pos });
81
+ i++;
82
+ break;
83
+ case "%":
84
+ tokens.push({ type: TokenType.PERCENT, value: ch, position: pos });
85
+ i++;
86
+ break;
87
+ case "+":
88
+ tokens.push({ type: TokenType.PLUS, value: ch, position: pos });
89
+ i++;
90
+ break;
91
+ case "-":
92
+ tokens.push({ type: TokenType.MINUS, value: ch, position: pos });
93
+ i++;
94
+ break;
95
+ case "*":
96
+ tokens.push({ type: TokenType.STAR, value: ch, position: pos });
97
+ i++;
98
+ break;
99
+ case "/":
100
+ tokens.push({ type: TokenType.SLASH, value: ch, position: pos });
101
+ i++;
102
+ break;
103
+ case "(":
104
+ tokens.push({ type: TokenType.LPAREN, value: ch, position: pos });
105
+ i++;
106
+ break;
107
+ case ")":
108
+ tokens.push({ type: TokenType.RPAREN, value: ch, position: pos });
109
+ i++;
110
+ break;
111
+ case "!":
112
+ tokens.push({ type: TokenType.BANG, value: ch, position: pos });
113
+ i++;
114
+ break;
115
+ case ">":
116
+ tokens.push({ type: TokenType.GT, value: ch, position: pos });
117
+ i++;
118
+ break;
119
+ default:
120
+ throw new LexerError(`Unexpected character: '${ch}'`, pos);
121
+ }
122
+ }
123
+ tokens.push({ type: TokenType.EOF, value: "", position: i });
124
+ return tokens;
125
+ }
126
+ //# sourceMappingURL=lexer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lexer.js","sourceRoot":"","sources":["../../src/parser/lexer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { ASTNode } from "./ast.js";
2
+ export declare class ParseError extends Error {
3
+ position: number;
4
+ constructor(message: string, position: number);
5
+ }
6
+ export declare function parse(input: string): ASTNode;
7
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/parser/parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAA2B,MAAM,UAAU,CAAC;AAI5D,qBAAa,UAAW,SAAQ,KAAK;IACC,QAAQ,EAAE,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAS,QAAQ,EAAE,MAAM;CAIrD;AAsMD,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAe5C"}
@@ -0,0 +1,188 @@
1
+ import { TokenType } from "./tokens.js";
2
+ import { tokenize } from "./lexer.js";
3
+ export class ParseError extends Error {
4
+ position;
5
+ constructor(message, position) {
6
+ super(message);
7
+ this.position = position;
8
+ this.name = "ParseError";
9
+ }
10
+ }
11
+ class Parser {
12
+ tokens;
13
+ pos = 0;
14
+ constructor(tokens) {
15
+ this.tokens = tokens;
16
+ }
17
+ peek() {
18
+ return this.tokens[this.pos];
19
+ }
20
+ advance() {
21
+ const token = this.tokens[this.pos];
22
+ this.pos++;
23
+ return token;
24
+ }
25
+ expect(type) {
26
+ const token = this.peek();
27
+ if (token.type !== type) {
28
+ throw new ParseError(`Expected ${type} but got ${token.type} ('${token.value}')`, token.position);
29
+ }
30
+ return this.advance();
31
+ }
32
+ match(...types) {
33
+ if (types.includes(this.peek().type)) {
34
+ return this.advance();
35
+ }
36
+ return null;
37
+ }
38
+ // expression → term (('+' | '-') term)*
39
+ parseExpression() {
40
+ let left = this.parseTerm();
41
+ while (this.peek().type === TokenType.PLUS || this.peek().type === TokenType.MINUS) {
42
+ const op = this.advance();
43
+ const right = this.parseTerm();
44
+ left = {
45
+ type: "binary",
46
+ op: op.type === TokenType.PLUS ? "+" : "-",
47
+ left,
48
+ right,
49
+ };
50
+ }
51
+ return left;
52
+ }
53
+ // term → factor (('*' | '/') factor)*
54
+ parseTerm() {
55
+ let left = this.parseFactor();
56
+ while (this.peek().type === TokenType.STAR || this.peek().type === TokenType.SLASH) {
57
+ const op = this.advance();
58
+ const right = this.parseFactor();
59
+ left = {
60
+ type: "binary",
61
+ op: op.type === TokenType.STAR ? "*" : "/",
62
+ left,
63
+ right,
64
+ };
65
+ }
66
+ return left;
67
+ }
68
+ // factor → '-' factor | '(' expression ')' | dice | number
69
+ parseFactor() {
70
+ // Unary minus
71
+ if (this.peek().type === TokenType.MINUS) {
72
+ this.advance();
73
+ const operand = this.parseFactor();
74
+ return { type: "unary_minus", operand };
75
+ }
76
+ // Parenthesized expression
77
+ if (this.peek().type === TokenType.LPAREN) {
78
+ this.advance();
79
+ const expr = this.parseExpression();
80
+ this.expect(TokenType.RPAREN);
81
+ return expr;
82
+ }
83
+ // Dice or number: starts with NUMBER or D
84
+ if (this.peek().type === TokenType.NUMBER) {
85
+ const numToken = this.advance();
86
+ const numValue = parseInt(numToken.value, 10);
87
+ // Check if followed by 'd' → dice expression
88
+ if (this.peek().type === TokenType.D) {
89
+ return this.parseDice(numValue);
90
+ }
91
+ // Just a number
92
+ return { type: "number", value: numValue };
93
+ }
94
+ // Bare 'd' (implicit 1d)
95
+ if (this.peek().type === TokenType.D) {
96
+ return this.parseDice(1);
97
+ }
98
+ throw new ParseError(`Unexpected token: ${this.peek().type} ('${this.peek().value}')`, this.peek().position);
99
+ }
100
+ // dice → 'd' M [modifier]*
101
+ // Called with count already parsed
102
+ parseDice(count) {
103
+ this.expect(TokenType.D);
104
+ // Parse sides: number, %, or F
105
+ let sides;
106
+ if (this.peek().type === TokenType.PERCENT) {
107
+ this.advance();
108
+ sides = "%";
109
+ }
110
+ else if (this.peek().type === TokenType.F) {
111
+ this.advance();
112
+ sides = "F";
113
+ }
114
+ else if (this.peek().type === TokenType.NUMBER) {
115
+ const token = this.advance();
116
+ sides = parseInt(token.value, 10);
117
+ if (sides < 1) {
118
+ throw new ParseError("Die must have at least 1 side", token.position);
119
+ }
120
+ }
121
+ else {
122
+ throw new ParseError(`Expected die size after 'd', got ${this.peek().type}`, this.peek().position);
123
+ }
124
+ // Parse modifiers
125
+ const modifiers = [];
126
+ let parsing = true;
127
+ while (parsing) {
128
+ switch (this.peek().type) {
129
+ case TokenType.KH: {
130
+ this.advance();
131
+ const n = this.parseOptionalNumber(1);
132
+ modifiers.push({ kind: "kh", value: n });
133
+ break;
134
+ }
135
+ case TokenType.KL: {
136
+ this.advance();
137
+ const n = this.parseOptionalNumber(1);
138
+ modifiers.push({ kind: "kl", value: n });
139
+ break;
140
+ }
141
+ case TokenType.DH: {
142
+ this.advance();
143
+ const n = this.parseOptionalNumber(1);
144
+ modifiers.push({ kind: "dh", value: n });
145
+ break;
146
+ }
147
+ case TokenType.DL: {
148
+ this.advance();
149
+ const n = this.parseOptionalNumber(1);
150
+ modifiers.push({ kind: "dl", value: n });
151
+ break;
152
+ }
153
+ case TokenType.BANG: {
154
+ this.advance();
155
+ let threshold;
156
+ if (this.peek().type === TokenType.GT) {
157
+ this.advance();
158
+ const numToken = this.expect(TokenType.NUMBER);
159
+ threshold = parseInt(numToken.value, 10);
160
+ }
161
+ modifiers.push({ kind: "explode", value: threshold });
162
+ break;
163
+ }
164
+ default:
165
+ parsing = false;
166
+ }
167
+ }
168
+ return { type: "dice", count, sides, modifiers };
169
+ }
170
+ parseOptionalNumber(defaultValue) {
171
+ if (this.peek().type === TokenType.NUMBER) {
172
+ return parseInt(this.advance().value, 10);
173
+ }
174
+ return defaultValue;
175
+ }
176
+ }
177
+ export function parse(input) {
178
+ const tokens = tokenize(input);
179
+ const parser = new Parser(tokens);
180
+ const ast = parser.parseExpression();
181
+ // Ensure we consumed everything
182
+ const remaining = tokens[parser["pos"]];
183
+ if (remaining && remaining.type !== TokenType.EOF) {
184
+ throw new ParseError(`Unexpected token after expression: ${remaining.type} ('${remaining.value}')`, remaining.position);
185
+ }
186
+ return ast;
187
+ }
188
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/parser/parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ export declare enum TokenType {
2
+ NUMBER = "NUMBER",
3
+ D = "D",
4
+ PLUS = "PLUS",
5
+ MINUS = "MINUS",
6
+ STAR = "STAR",
7
+ SLASH = "SLASH",
8
+ LPAREN = "LPAREN",
9
+ RPAREN = "RPAREN",
10
+ KH = "KH",
11
+ KL = "KL",
12
+ DH = "DH",
13
+ DL = "DL",
14
+ BANG = "BANG",
15
+ GT = "GT",
16
+ PERCENT = "PERCENT",
17
+ F = "F",
18
+ EOF = "EOF"
19
+ }
20
+ export interface Token {
21
+ type: TokenType;
22
+ value: string;
23
+ position: number;
24
+ }
25
+ //# sourceMappingURL=tokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/parser/tokens.ts"],"names":[],"mappings":"AAAA,oBAAY,SAAS;IACnB,MAAM,WAAW;IACjB,CAAC,MAAM;IACP,IAAI,SAAS;IACb,KAAK,UAAU;IACf,IAAI,SAAS;IACb,KAAK,UAAU;IACf,MAAM,WAAW;IACjB,MAAM,WAAW;IACjB,EAAE,OAAO;IACT,EAAE,OAAO;IACT,EAAE,OAAO;IACT,EAAE,OAAO;IACT,IAAI,SAAS;IACb,EAAE,OAAO;IACT,OAAO,YAAY;IACnB,CAAC,MAAM;IACP,GAAG,QAAQ;CACZ;AAED,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB"}
@@ -0,0 +1,21 @@
1
+ export var TokenType;
2
+ (function (TokenType) {
3
+ TokenType["NUMBER"] = "NUMBER";
4
+ TokenType["D"] = "D";
5
+ TokenType["PLUS"] = "PLUS";
6
+ TokenType["MINUS"] = "MINUS";
7
+ TokenType["STAR"] = "STAR";
8
+ TokenType["SLASH"] = "SLASH";
9
+ TokenType["LPAREN"] = "LPAREN";
10
+ TokenType["RPAREN"] = "RPAREN";
11
+ TokenType["KH"] = "KH";
12
+ TokenType["KL"] = "KL";
13
+ TokenType["DH"] = "DH";
14
+ TokenType["DL"] = "DL";
15
+ TokenType["BANG"] = "BANG";
16
+ TokenType["GT"] = "GT";
17
+ TokenType["PERCENT"] = "PERCENT";
18
+ TokenType["F"] = "F";
19
+ TokenType["EOF"] = "EOF";
20
+ })(TokenType || (TokenType = {}));
21
+ //# sourceMappingURL=tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/parser/tokens.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,SAkBX;AAlBD,WAAY,SAAS;IACnB,8BAAiB,CAAA;IACjB,oBAAO,CAAA;IACP,0BAAa,CAAA;IACb,4BAAe,CAAA;IACf,0BAAa,CAAA;IACb,4BAAe,CAAA;IACf,8BAAiB,CAAA;IACjB,8BAAiB,CAAA;IACjB,sBAAS,CAAA;IACT,sBAAS,CAAA;IACT,sBAAS,CAAA;IACT,sBAAS,CAAA;IACT,0BAAa,CAAA;IACb,sBAAS,CAAA;IACT,gCAAmB,CAAA;IACnB,oBAAO,CAAA;IACP,wBAAW,CAAA;AACb,CAAC,EAlBW,SAAS,KAAT,SAAS,QAkBpB"}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@mcptoolshop/roll",
3
+ "version": "1.0.0",
4
+ "description": "RPG dice engine — expression parser, probability analyzer, loot tables, beautiful terminal output",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "roll": "./dist/bin.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "README.md",
20
+ "LICENSE",
21
+ "CHANGELOG.md"
22
+ ],
23
+ "scripts": {
24
+ "build": "tsc",
25
+ "test": "vitest run",
26
+ "clean": "rm -rf dist",
27
+ "verify": "npm run build && npm test",
28
+ "prepublishOnly": "npm run clean && npm run verify"
29
+ },
30
+ "engines": {
31
+ "node": ">=22"
32
+ },
33
+ "keywords": [
34
+ "dice",
35
+ "rpg",
36
+ "roller",
37
+ "probability",
38
+ "dnd",
39
+ "tabletop",
40
+ "loot-table",
41
+ "game-design",
42
+ "cli"
43
+ ],
44
+ "author": "mcp-tool-shop",
45
+ "license": "MIT",
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "git+https://github.com/mcp-tool-shop-org/roll.git"
49
+ },
50
+ "devDependencies": {
51
+ "@types/node": "^25.6.0",
52
+ "typescript": "^5.7.0",
53
+ "vitest": "^3.0.0"
54
+ }
55
+ }