redscript-mc 1.2.30 → 2.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 (269) hide show
  1. package/.claude/commands/build-test.md +10 -0
  2. package/.claude/commands/deploy-demo.md +12 -0
  3. package/.claude/commands/stage-status.md +13 -0
  4. package/.claude/settings.json +12 -0
  5. package/.github/workflows/ci.yml +1 -0
  6. package/CLAUDE.md +231 -0
  7. package/demo.gif +0 -0
  8. package/dist/cli.js +2 -554
  9. package/dist/compile.js +2 -266
  10. package/dist/index.js +2 -159
  11. package/dist/lowering/index.js +5 -3
  12. package/dist/src/__tests__/cli.test.d.ts +1 -0
  13. package/dist/src/__tests__/cli.test.js +104 -0
  14. package/dist/src/__tests__/codegen.test.d.ts +1 -0
  15. package/dist/src/__tests__/codegen.test.js +152 -0
  16. package/dist/src/__tests__/compile-all.test.d.ts +10 -0
  17. package/dist/src/__tests__/compile-all.test.js +108 -0
  18. package/dist/src/__tests__/dce.test.d.ts +1 -0
  19. package/dist/src/__tests__/dce.test.js +102 -0
  20. package/dist/src/__tests__/diagnostics.test.d.ts +4 -0
  21. package/dist/src/__tests__/diagnostics.test.js +177 -0
  22. package/dist/src/__tests__/e2e.test.d.ts +6 -0
  23. package/dist/src/__tests__/e2e.test.js +1789 -0
  24. package/dist/src/__tests__/entity-types.test.d.ts +1 -0
  25. package/dist/src/__tests__/entity-types.test.js +203 -0
  26. package/dist/src/__tests__/formatter.test.d.ts +1 -0
  27. package/dist/src/__tests__/formatter.test.js +40 -0
  28. package/dist/src/__tests__/lexer.test.d.ts +1 -0
  29. package/dist/src/__tests__/lexer.test.js +343 -0
  30. package/dist/src/__tests__/lowering.test.d.ts +1 -0
  31. package/dist/src/__tests__/lowering.test.js +1015 -0
  32. package/dist/src/__tests__/macro.test.d.ts +8 -0
  33. package/dist/src/__tests__/macro.test.js +306 -0
  34. package/dist/src/__tests__/mc-integration.test.d.ts +12 -0
  35. package/dist/src/__tests__/mc-integration.test.js +817 -0
  36. package/dist/src/__tests__/mc-syntax.test.d.ts +1 -0
  37. package/dist/src/__tests__/mc-syntax.test.js +124 -0
  38. package/dist/src/__tests__/nbt.test.d.ts +1 -0
  39. package/dist/src/__tests__/nbt.test.js +82 -0
  40. package/dist/src/__tests__/optimizer-advanced.test.d.ts +1 -0
  41. package/dist/src/__tests__/optimizer-advanced.test.js +124 -0
  42. package/dist/src/__tests__/optimizer.test.d.ts +1 -0
  43. package/dist/src/__tests__/optimizer.test.js +149 -0
  44. package/dist/src/__tests__/parser.test.d.ts +1 -0
  45. package/dist/src/__tests__/parser.test.js +807 -0
  46. package/dist/src/__tests__/repl.test.d.ts +1 -0
  47. package/dist/src/__tests__/repl.test.js +27 -0
  48. package/dist/src/__tests__/runtime.test.d.ts +1 -0
  49. package/dist/src/__tests__/runtime.test.js +289 -0
  50. package/dist/src/__tests__/stdlib-advanced.test.d.ts +4 -0
  51. package/dist/src/__tests__/stdlib-advanced.test.js +374 -0
  52. package/dist/src/__tests__/stdlib-bigint.test.d.ts +7 -0
  53. package/dist/src/__tests__/stdlib-bigint.test.js +426 -0
  54. package/dist/src/__tests__/stdlib-math.test.d.ts +7 -0
  55. package/dist/src/__tests__/stdlib-math.test.js +351 -0
  56. package/dist/src/__tests__/stdlib-vec.test.d.ts +4 -0
  57. package/dist/src/__tests__/stdlib-vec.test.js +263 -0
  58. package/dist/src/__tests__/structure-optimizer.test.d.ts +1 -0
  59. package/dist/src/__tests__/structure-optimizer.test.js +33 -0
  60. package/dist/src/__tests__/typechecker.test.d.ts +1 -0
  61. package/dist/src/__tests__/typechecker.test.js +552 -0
  62. package/dist/src/__tests__/var-allocator.test.d.ts +1 -0
  63. package/dist/src/__tests__/var-allocator.test.js +69 -0
  64. package/dist/src/ast/types.d.ts +515 -0
  65. package/dist/src/ast/types.js +9 -0
  66. package/dist/src/builtins/metadata.d.ts +36 -0
  67. package/dist/src/builtins/metadata.js +1014 -0
  68. package/dist/src/cli.d.ts +11 -0
  69. package/dist/src/cli.js +443 -0
  70. package/dist/src/codegen/cmdblock/index.d.ts +26 -0
  71. package/dist/src/codegen/cmdblock/index.js +45 -0
  72. package/dist/src/codegen/mcfunction/index.d.ts +40 -0
  73. package/dist/src/codegen/mcfunction/index.js +606 -0
  74. package/dist/src/codegen/structure/index.d.ts +24 -0
  75. package/dist/src/codegen/structure/index.js +279 -0
  76. package/dist/src/codegen/var-allocator.d.ts +45 -0
  77. package/dist/src/codegen/var-allocator.js +104 -0
  78. package/dist/src/compile.d.ts +37 -0
  79. package/dist/src/compile.js +165 -0
  80. package/dist/src/diagnostics/index.d.ts +44 -0
  81. package/dist/src/diagnostics/index.js +140 -0
  82. package/dist/src/events/types.d.ts +35 -0
  83. package/dist/src/events/types.js +59 -0
  84. package/dist/src/formatter/index.d.ts +1 -0
  85. package/dist/src/formatter/index.js +26 -0
  86. package/dist/src/index.d.ts +22 -0
  87. package/dist/src/index.js +45 -0
  88. package/dist/src/ir/builder.d.ts +33 -0
  89. package/dist/src/ir/builder.js +99 -0
  90. package/dist/src/ir/types.d.ts +132 -0
  91. package/dist/src/ir/types.js +15 -0
  92. package/dist/src/lexer/index.d.ts +37 -0
  93. package/dist/src/lexer/index.js +569 -0
  94. package/dist/src/lowering/index.d.ts +188 -0
  95. package/dist/src/lowering/index.js +3405 -0
  96. package/dist/src/mc-test/client.d.ts +128 -0
  97. package/dist/src/mc-test/client.js +174 -0
  98. package/dist/src/mc-test/runner.d.ts +28 -0
  99. package/dist/src/mc-test/runner.js +151 -0
  100. package/dist/src/mc-test/setup.d.ts +11 -0
  101. package/dist/src/mc-test/setup.js +98 -0
  102. package/dist/src/mc-validator/index.d.ts +17 -0
  103. package/dist/src/mc-validator/index.js +322 -0
  104. package/dist/src/nbt/index.d.ts +86 -0
  105. package/dist/src/nbt/index.js +250 -0
  106. package/dist/src/optimizer/commands.d.ts +38 -0
  107. package/dist/src/optimizer/commands.js +451 -0
  108. package/dist/src/optimizer/dce.d.ts +34 -0
  109. package/dist/src/optimizer/dce.js +639 -0
  110. package/dist/src/optimizer/passes.d.ts +34 -0
  111. package/dist/src/optimizer/passes.js +243 -0
  112. package/dist/src/optimizer/structure.d.ts +9 -0
  113. package/dist/src/optimizer/structure.js +356 -0
  114. package/dist/src/parser/index.d.ts +93 -0
  115. package/dist/src/parser/index.js +1687 -0
  116. package/dist/src/repl.d.ts +16 -0
  117. package/dist/src/repl.js +165 -0
  118. package/dist/src/runtime/index.d.ts +107 -0
  119. package/dist/src/runtime/index.js +1409 -0
  120. package/dist/src/typechecker/index.d.ts +61 -0
  121. package/dist/src/typechecker/index.js +1034 -0
  122. package/dist/src/types/entity-hierarchy.d.ts +29 -0
  123. package/dist/src/types/entity-hierarchy.js +107 -0
  124. package/dist/src2/__tests__/e2e/basic.test.d.ts +8 -0
  125. package/dist/src2/__tests__/e2e/basic.test.js +140 -0
  126. package/dist/src2/__tests__/e2e/macros.test.d.ts +9 -0
  127. package/dist/src2/__tests__/e2e/macros.test.js +182 -0
  128. package/dist/src2/__tests__/e2e/migrate.test.d.ts +13 -0
  129. package/dist/src2/__tests__/e2e/migrate.test.js +2739 -0
  130. package/dist/src2/__tests__/hir/desugar.test.d.ts +1 -0
  131. package/dist/src2/__tests__/hir/desugar.test.js +234 -0
  132. package/dist/src2/__tests__/lir/lower.test.d.ts +1 -0
  133. package/dist/src2/__tests__/lir/lower.test.js +559 -0
  134. package/dist/src2/__tests__/lir/types.test.d.ts +1 -0
  135. package/dist/src2/__tests__/lir/types.test.js +185 -0
  136. package/dist/src2/__tests__/lir/verify.test.d.ts +1 -0
  137. package/dist/src2/__tests__/lir/verify.test.js +221 -0
  138. package/dist/src2/__tests__/mir/arithmetic.test.d.ts +1 -0
  139. package/dist/src2/__tests__/mir/arithmetic.test.js +130 -0
  140. package/dist/src2/__tests__/mir/control-flow.test.d.ts +1 -0
  141. package/dist/src2/__tests__/mir/control-flow.test.js +205 -0
  142. package/dist/src2/__tests__/mir/verify.test.d.ts +1 -0
  143. package/dist/src2/__tests__/mir/verify.test.js +223 -0
  144. package/dist/src2/__tests__/optimizer/block_merge.test.d.ts +1 -0
  145. package/dist/src2/__tests__/optimizer/block_merge.test.js +78 -0
  146. package/dist/src2/__tests__/optimizer/branch_simplify.test.d.ts +1 -0
  147. package/dist/src2/__tests__/optimizer/branch_simplify.test.js +58 -0
  148. package/dist/src2/__tests__/optimizer/constant_fold.test.d.ts +1 -0
  149. package/dist/src2/__tests__/optimizer/constant_fold.test.js +131 -0
  150. package/dist/src2/__tests__/optimizer/copy_prop.test.d.ts +1 -0
  151. package/dist/src2/__tests__/optimizer/copy_prop.test.js +91 -0
  152. package/dist/src2/__tests__/optimizer/dce.test.d.ts +1 -0
  153. package/dist/src2/__tests__/optimizer/dce.test.js +76 -0
  154. package/dist/src2/__tests__/optimizer/pipeline.test.d.ts +1 -0
  155. package/dist/src2/__tests__/optimizer/pipeline.test.js +102 -0
  156. package/dist/src2/emit/compile.d.ts +19 -0
  157. package/dist/src2/emit/compile.js +80 -0
  158. package/dist/src2/emit/index.d.ts +17 -0
  159. package/dist/src2/emit/index.js +172 -0
  160. package/dist/src2/hir/lower.d.ts +15 -0
  161. package/dist/src2/hir/lower.js +378 -0
  162. package/dist/src2/hir/types.d.ts +373 -0
  163. package/dist/src2/hir/types.js +16 -0
  164. package/dist/src2/lir/lower.d.ts +15 -0
  165. package/dist/src2/lir/lower.js +453 -0
  166. package/dist/src2/lir/types.d.ts +136 -0
  167. package/dist/src2/lir/types.js +11 -0
  168. package/dist/src2/lir/verify.d.ts +14 -0
  169. package/dist/src2/lir/verify.js +113 -0
  170. package/dist/src2/mir/lower.d.ts +9 -0
  171. package/dist/src2/mir/lower.js +1030 -0
  172. package/dist/src2/mir/macro.d.ts +22 -0
  173. package/dist/src2/mir/macro.js +168 -0
  174. package/dist/src2/mir/types.d.ts +183 -0
  175. package/dist/src2/mir/types.js +11 -0
  176. package/dist/src2/mir/verify.d.ts +16 -0
  177. package/dist/src2/mir/verify.js +216 -0
  178. package/dist/src2/optimizer/block_merge.d.ts +12 -0
  179. package/dist/src2/optimizer/block_merge.js +84 -0
  180. package/dist/src2/optimizer/branch_simplify.d.ts +9 -0
  181. package/dist/src2/optimizer/branch_simplify.js +28 -0
  182. package/dist/src2/optimizer/constant_fold.d.ts +10 -0
  183. package/dist/src2/optimizer/constant_fold.js +85 -0
  184. package/dist/src2/optimizer/copy_prop.d.ts +9 -0
  185. package/dist/src2/optimizer/copy_prop.js +113 -0
  186. package/dist/src2/optimizer/dce.d.ts +8 -0
  187. package/dist/src2/optimizer/dce.js +155 -0
  188. package/dist/src2/optimizer/pipeline.d.ts +10 -0
  189. package/dist/src2/optimizer/pipeline.js +42 -0
  190. package/dist/tsconfig.tsbuildinfo +1 -0
  191. package/docs/compiler-pipeline-redesign.md +2243 -0
  192. package/docs/optimization-ideas.md +1076 -0
  193. package/editors/vscode/package-lock.json +3 -3
  194. package/editors/vscode/package.json +1 -1
  195. package/jest.config.js +1 -1
  196. package/package.json +6 -5
  197. package/scripts/postbuild.js +15 -0
  198. package/src/__tests__/cli.test.ts +8 -220
  199. package/src/__tests__/dce.test.ts +11 -56
  200. package/src/__tests__/diagnostics.test.ts +59 -38
  201. package/src/__tests__/mc-integration.test.ts +1 -2
  202. package/src/ast/types.ts +6 -1
  203. package/src/cli.ts +29 -156
  204. package/src/compile.ts +6 -162
  205. package/src/index.ts +14 -178
  206. package/src/mc-test/runner.ts +4 -3
  207. package/src/parser/index.ts +1 -1
  208. package/src/repl.ts +1 -1
  209. package/src/runtime/index.ts +1 -1
  210. package/src2/__tests__/e2e/basic.test.ts +154 -0
  211. package/src2/__tests__/e2e/macros.test.ts +199 -0
  212. package/src2/__tests__/e2e/migrate.test.ts +3008 -0
  213. package/src2/__tests__/hir/desugar.test.ts +263 -0
  214. package/src2/__tests__/lir/lower.test.ts +619 -0
  215. package/src2/__tests__/lir/types.test.ts +207 -0
  216. package/src2/__tests__/lir/verify.test.ts +249 -0
  217. package/src2/__tests__/mir/arithmetic.test.ts +156 -0
  218. package/src2/__tests__/mir/control-flow.test.ts +242 -0
  219. package/src2/__tests__/mir/verify.test.ts +254 -0
  220. package/src2/__tests__/optimizer/block_merge.test.ts +84 -0
  221. package/src2/__tests__/optimizer/branch_simplify.test.ts +64 -0
  222. package/src2/__tests__/optimizer/constant_fold.test.ts +145 -0
  223. package/src2/__tests__/optimizer/copy_prop.test.ts +99 -0
  224. package/src2/__tests__/optimizer/dce.test.ts +83 -0
  225. package/src2/__tests__/optimizer/pipeline.test.ts +116 -0
  226. package/src2/emit/compile.ts +99 -0
  227. package/src2/emit/index.ts +222 -0
  228. package/src2/hir/lower.ts +428 -0
  229. package/src2/hir/types.ts +216 -0
  230. package/src2/lir/lower.ts +556 -0
  231. package/src2/lir/types.ts +109 -0
  232. package/src2/lir/verify.ts +129 -0
  233. package/src2/mir/lower.ts +1160 -0
  234. package/src2/mir/macro.ts +167 -0
  235. package/src2/mir/types.ts +106 -0
  236. package/src2/mir/verify.ts +218 -0
  237. package/src2/optimizer/block_merge.ts +93 -0
  238. package/src2/optimizer/branch_simplify.ts +27 -0
  239. package/src2/optimizer/constant_fold.ts +88 -0
  240. package/src2/optimizer/copy_prop.ts +106 -0
  241. package/src2/optimizer/dce.ts +133 -0
  242. package/src2/optimizer/pipeline.ts +44 -0
  243. package/tsconfig.json +2 -2
  244. package/src/__tests__/codegen.test.ts +0 -161
  245. package/src/__tests__/e2e.test.ts +0 -2039
  246. package/src/__tests__/entity-types.test.ts +0 -236
  247. package/src/__tests__/lowering.test.ts +0 -1185
  248. package/src/__tests__/macro.test.ts +0 -343
  249. package/src/__tests__/nbt.test.ts +0 -58
  250. package/src/__tests__/optimizer-advanced.test.ts +0 -144
  251. package/src/__tests__/optimizer.test.ts +0 -162
  252. package/src/__tests__/runtime.test.ts +0 -305
  253. package/src/__tests__/stdlib-advanced.test.ts +0 -379
  254. package/src/__tests__/stdlib-bigint.test.ts +0 -427
  255. package/src/__tests__/stdlib-math.test.ts +0 -374
  256. package/src/__tests__/stdlib-vec.test.ts +0 -259
  257. package/src/__tests__/structure-optimizer.test.ts +0 -38
  258. package/src/__tests__/var-allocator.test.ts +0 -75
  259. package/src/codegen/cmdblock/index.ts +0 -63
  260. package/src/codegen/mcfunction/index.ts +0 -662
  261. package/src/codegen/structure/index.ts +0 -346
  262. package/src/codegen/var-allocator.ts +0 -104
  263. package/src/ir/builder.ts +0 -116
  264. package/src/ir/types.ts +0 -134
  265. package/src/lowering/index.ts +0 -3876
  266. package/src/optimizer/commands.ts +0 -534
  267. package/src/optimizer/dce.ts +0 -679
  268. package/src/optimizer/passes.ts +0 -250
  269. package/src/optimizer/structure.ts +0 -450
@@ -0,0 +1,128 @@
1
+ /**
2
+ * RedScript MC Test Client
3
+ *
4
+ * Connects to a Paper server running TestHarnessPlugin and provides
5
+ * a fluent API for integration testing compiled datapacks.
6
+ *
7
+ * Usage:
8
+ * const mc = new MCTestClient('localhost', 25561)
9
+ * await mc.command('/function arena:start')
10
+ * await mc.ticks(100)
11
+ * const score = await mc.scoreboard('Alice', 'kills')
12
+ * expect(score).toBe(3)
13
+ */
14
+ export interface ScoreResult {
15
+ player: string;
16
+ obj: string;
17
+ value: number;
18
+ }
19
+ export interface BlockResult {
20
+ x: number;
21
+ y: number;
22
+ z: number;
23
+ world: string;
24
+ type: string;
25
+ blockData: string;
26
+ }
27
+ export interface EntityResult {
28
+ uuid: string;
29
+ name: string;
30
+ type: string;
31
+ x: number;
32
+ y: number;
33
+ z: number;
34
+ world: string;
35
+ tags: string[];
36
+ }
37
+ export interface ChatMessage {
38
+ tick: number;
39
+ type: string;
40
+ sender?: string;
41
+ message: string;
42
+ }
43
+ export interface GameEvent {
44
+ tick: number;
45
+ type: string;
46
+ player?: string;
47
+ advancement?: string;
48
+ cause?: string;
49
+ }
50
+ export interface ServerStatus {
51
+ online: boolean;
52
+ tps_1m: number;
53
+ tps_5m: number;
54
+ tps_15m: number;
55
+ players: number;
56
+ playerNames: string[];
57
+ worlds: string[];
58
+ version: string;
59
+ }
60
+ export declare class MCTestClient {
61
+ private baseUrl;
62
+ constructor(host?: string, port?: number);
63
+ private get;
64
+ private post;
65
+ /** Check if server is reachable */
66
+ isOnline(): Promise<boolean>;
67
+ /** Get server status */
68
+ status(): Promise<ServerStatus>;
69
+ /** Run a command on the server (as console sender) */
70
+ command(cmd: string): Promise<{
71
+ ok: boolean;
72
+ cmd: string;
73
+ }>;
74
+ /** Wait for N server ticks (50ms each) */
75
+ ticks(count: number): Promise<void>;
76
+ /** Wait for 1 second = 20 ticks */
77
+ seconds(s: number): Promise<void>;
78
+ /** Get a scoreboard value */
79
+ scoreboard(player: string, obj: string): Promise<number>;
80
+ /** Get all scoreboard values for a selector */
81
+ scoreboardAll(selector: string, obj: string): Promise<ScoreResult[]>;
82
+ /** Get block at position */
83
+ block(x: number, y: number, z: number, world?: string): Promise<BlockResult>;
84
+ /** Get entities matching selector */
85
+ entities(selector?: string): Promise<EntityResult[]>;
86
+ /** Get chat log since a tick */
87
+ chat(since?: number): Promise<ChatMessage[]>;
88
+ /** Get last N chat messages */
89
+ chatLast(n: number): Promise<ChatMessage[]>;
90
+ /** Get events since a tick, optionally filtered by type */
91
+ events(since?: number, type?: string): Promise<GameEvent[]>;
92
+ /** Clear chat and event logs */
93
+ reset(): Promise<void>;
94
+ /**
95
+ * Full test reset: clear logs + fill test area with air + kill entities + reset scoreboards.
96
+ * Call this at the start of each integration test.
97
+ */
98
+ fullReset(options?: {
99
+ x1?: number;
100
+ y1?: number;
101
+ z1?: number;
102
+ x2?: number;
103
+ y2?: number;
104
+ z2?: number;
105
+ clearArea?: boolean;
106
+ killEntities?: boolean;
107
+ resetScoreboards?: boolean;
108
+ }): Promise<void>;
109
+ /** Reload datapacks */
110
+ reload(): Promise<void>;
111
+ /**
112
+ * Assert a scoreboard value equals expected.
113
+ * Throws with a descriptive error if it doesn't match.
114
+ */
115
+ assertScore(player: string, obj: string, expected: number, msg?: string): Promise<void>;
116
+ /**
117
+ * Assert a block type at position.
118
+ */
119
+ assertBlock(x: number, y: number, z: number, expectedType: string, world?: string): Promise<void>;
120
+ /**
121
+ * Assert chat log contains a message matching substring.
122
+ */
123
+ assertChatContains(substring: string, since?: number): Promise<void>;
124
+ /**
125
+ * Wait until a scoreboard value equals expected, up to timeout ms.
126
+ */
127
+ waitForScore(player: string, obj: string, expected: number, timeoutMs?: number, pollMs?: number): Promise<void>;
128
+ }
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ /**
3
+ * RedScript MC Test Client
4
+ *
5
+ * Connects to a Paper server running TestHarnessPlugin and provides
6
+ * a fluent API for integration testing compiled datapacks.
7
+ *
8
+ * Usage:
9
+ * const mc = new MCTestClient('localhost', 25561)
10
+ * await mc.command('/function arena:start')
11
+ * await mc.ticks(100)
12
+ * const score = await mc.scoreboard('Alice', 'kills')
13
+ * expect(score).toBe(3)
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.MCTestClient = void 0;
17
+ class MCTestClient {
18
+ constructor(host = 'localhost', port = 25561) {
19
+ this.baseUrl = `http://${host}:${port}`;
20
+ }
21
+ async get(path, params = {}) {
22
+ const qs = Object.entries(params)
23
+ .map(([k, v]) => `${k}=${encodeURIComponent(String(v))}`)
24
+ .join('&');
25
+ const url = `${this.baseUrl}${path}${qs ? '?' + qs : ''}`;
26
+ const res = await fetch(url);
27
+ if (!res.ok) {
28
+ const body = await res.text();
29
+ throw new Error(`GET ${path} failed ${res.status}: ${body}`);
30
+ }
31
+ return res.json();
32
+ }
33
+ async post(path, body = {}) {
34
+ const res = await fetch(`${this.baseUrl}${path}`, {
35
+ method: 'POST',
36
+ headers: { 'Content-Type': 'application/json' },
37
+ body: JSON.stringify(body)
38
+ });
39
+ if (!res.ok) {
40
+ const text = await res.text();
41
+ throw new Error(`POST ${path} failed ${res.status}: ${text}`);
42
+ }
43
+ return res.json();
44
+ }
45
+ /** Check if server is reachable */
46
+ async isOnline() {
47
+ try {
48
+ const status = await this.get('/status');
49
+ return status.online;
50
+ }
51
+ catch {
52
+ return false;
53
+ }
54
+ }
55
+ /** Get server status */
56
+ async status() {
57
+ return this.get('/status');
58
+ }
59
+ /** Run a command on the server (as console sender) */
60
+ async command(cmd) {
61
+ return this.post('/command', { cmd });
62
+ }
63
+ /** Wait for N server ticks (50ms each) */
64
+ async ticks(count) {
65
+ await this.post('/tick', { count });
66
+ }
67
+ /** Wait for 1 second = 20 ticks */
68
+ async seconds(s) {
69
+ await this.ticks(s * 20);
70
+ }
71
+ /** Get a scoreboard value */
72
+ async scoreboard(player, obj) {
73
+ const result = await this.get('/scoreboard', { player, obj });
74
+ return result.value;
75
+ }
76
+ /** Get all scoreboard values for a selector */
77
+ async scoreboardAll(selector, obj) {
78
+ return this.get('/scoreboard', { player: selector, obj });
79
+ }
80
+ /** Get block at position */
81
+ async block(x, y, z, world = 'world') {
82
+ return this.get('/block', { x, y, z, world });
83
+ }
84
+ /** Get entities matching selector */
85
+ async entities(selector = '@e') {
86
+ return this.get('/entity', { sel: selector });
87
+ }
88
+ /** Get chat log since a tick */
89
+ async chat(since = 0) {
90
+ return this.get('/chat', { since });
91
+ }
92
+ /** Get last N chat messages */
93
+ async chatLast(n) {
94
+ return this.get('/chat', { last: n });
95
+ }
96
+ /** Get events since a tick, optionally filtered by type */
97
+ async events(since = 0, type) {
98
+ const params = { since };
99
+ if (type)
100
+ params.type = type;
101
+ return this.get('/events', params);
102
+ }
103
+ /** Clear chat and event logs */
104
+ async reset() {
105
+ await this.post('/reset');
106
+ }
107
+ /**
108
+ * Full test reset: clear logs + fill test area with air + kill entities + reset scoreboards.
109
+ * Call this at the start of each integration test.
110
+ */
111
+ async fullReset(options) {
112
+ await this.post('/reset', {
113
+ clearArea: options?.clearArea ?? true,
114
+ killEntities: options?.killEntities ?? true,
115
+ resetScoreboards: options?.resetScoreboards ?? true,
116
+ x1: options?.x1 ?? -50, y1: options?.y1 ?? 0, z1: options?.z1 ?? -50,
117
+ x2: options?.x2 ?? 50, y2: options?.y2 ?? 100, z2: options?.z2 ?? 50,
118
+ });
119
+ }
120
+ /** Reload datapacks */
121
+ async reload() {
122
+ await this.post('/reload');
123
+ await this.ticks(40); // wait 2s for reload
124
+ }
125
+ /**
126
+ * Assert a scoreboard value equals expected.
127
+ * Throws with a descriptive error if it doesn't match.
128
+ */
129
+ async assertScore(player, obj, expected, msg) {
130
+ const actual = await this.scoreboard(player, obj);
131
+ if (actual !== expected) {
132
+ throw new Error(msg ?? `assertScore failed: ${player}/${obj} expected ${expected}, got ${actual}`);
133
+ }
134
+ }
135
+ /**
136
+ * Assert a block type at position.
137
+ */
138
+ async assertBlock(x, y, z, expectedType, world = 'world') {
139
+ const block = await this.block(x, y, z, world);
140
+ if (block.type !== expectedType) {
141
+ throw new Error(`assertBlock failed: (${x},${y},${z}) expected ${expectedType}, got ${block.type}`);
142
+ }
143
+ }
144
+ /**
145
+ * Assert chat log contains a message matching substring.
146
+ */
147
+ async assertChatContains(substring, since = 0) {
148
+ const msgs = await this.chat(since);
149
+ const found = msgs.some(m => m.message.includes(substring));
150
+ if (!found) {
151
+ const recent = msgs.map(m => m.message).slice(-5).join(', ');
152
+ throw new Error(`assertChatContains: "${substring}" not found in chat. Recent: [${recent}]`);
153
+ }
154
+ }
155
+ /**
156
+ * Wait until a scoreboard value equals expected, up to timeout ms.
157
+ */
158
+ async waitForScore(player, obj, expected, timeoutMs = 5000, pollMs = 100) {
159
+ const start = Date.now();
160
+ while (Date.now() - start < timeoutMs) {
161
+ try {
162
+ const val = await this.scoreboard(player, obj);
163
+ if (val === expected)
164
+ return;
165
+ }
166
+ catch { /* ignore transient errors */ }
167
+ await new Promise(r => setTimeout(r, pollMs));
168
+ }
169
+ const final = await this.scoreboard(player, obj);
170
+ throw new Error(`waitForScore: ${player}/${obj} never reached ${expected} (last: ${final})`);
171
+ }
172
+ }
173
+ exports.MCTestClient = MCTestClient;
174
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1,28 @@
1
+ /**
2
+ * RedScript MC Integration Test Runner
3
+ *
4
+ * Compiles a .mcrs file, installs it to a running Paper server,
5
+ * runs test scenarios, and reports results.
6
+ *
7
+ * Usage:
8
+ * npx ts-node src/mc-test/runner.ts src/examples/counter.mcrs
9
+ *
10
+ * Requires:
11
+ * - Paper server running with TestHarnessPlugin
12
+ * - MC_SERVER_DIR env var pointing to server directory
13
+ * - MC_HOST and MC_PORT env vars (default: localhost:25561)
14
+ */
15
+ import { MCTestClient } from './client';
16
+ export interface TestCase {
17
+ name: string;
18
+ run: (mc: MCTestClient) => Promise<void>;
19
+ }
20
+ export interface TestResult {
21
+ name: string;
22
+ passed: boolean;
23
+ error?: string;
24
+ durationMs: number;
25
+ }
26
+ export declare function runMCTests(sourceFile: string, tests: TestCase[], options?: {
27
+ skipInstall?: boolean;
28
+ }): Promise<TestResult[]>;
@@ -0,0 +1,151 @@
1
+ "use strict";
2
+ /**
3
+ * RedScript MC Integration Test Runner
4
+ *
5
+ * Compiles a .mcrs file, installs it to a running Paper server,
6
+ * runs test scenarios, and reports results.
7
+ *
8
+ * Usage:
9
+ * npx ts-node src/mc-test/runner.ts src/examples/counter.mcrs
10
+ *
11
+ * Requires:
12
+ * - Paper server running with TestHarnessPlugin
13
+ * - MC_SERVER_DIR env var pointing to server directory
14
+ * - MC_HOST and MC_PORT env vars (default: localhost:25561)
15
+ */
16
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ var desc = Object.getOwnPropertyDescriptor(m, k);
19
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
20
+ desc = { enumerable: true, get: function() { return m[k]; } };
21
+ }
22
+ Object.defineProperty(o, k2, desc);
23
+ }) : (function(o, m, k, k2) {
24
+ if (k2 === undefined) k2 = k;
25
+ o[k2] = m[k];
26
+ }));
27
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
28
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
29
+ }) : function(o, v) {
30
+ o["default"] = v;
31
+ });
32
+ var __importStar = (this && this.__importStar) || (function () {
33
+ var ownKeys = function(o) {
34
+ ownKeys = Object.getOwnPropertyNames || function (o) {
35
+ var ar = [];
36
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
37
+ return ar;
38
+ };
39
+ return ownKeys(o);
40
+ };
41
+ return function (mod) {
42
+ if (mod && mod.__esModule) return mod;
43
+ var result = {};
44
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
45
+ __setModuleDefault(result, mod);
46
+ return result;
47
+ };
48
+ })();
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.runMCTests = runMCTests;
51
+ const fs = __importStar(require("fs"));
52
+ const path = __importStar(require("path"));
53
+ const client_1 = require("./client");
54
+ const compile_1 = require("../compile");
55
+ const MC_HOST = process.env.MC_HOST ?? 'localhost';
56
+ const MC_PORT = parseInt(process.env.MC_PORT ?? '25561');
57
+ const MC_SERVER_DIR = process.env.MC_SERVER_DIR ?? path.join(process.env.HOME, 'mc-test-server');
58
+ async function runMCTests(sourceFile, tests, options = {}) {
59
+ const mc = new client_1.MCTestClient(MC_HOST, MC_PORT);
60
+ // Check server is online
61
+ console.log(`Connecting to MC server at ${MC_HOST}:${MC_PORT}...`);
62
+ const online = await mc.isOnline();
63
+ if (!online) {
64
+ throw new Error(`MC server not reachable at ${MC_HOST}:${MC_PORT}. Start Paper server first.`);
65
+ }
66
+ console.log('✓ Server online');
67
+ if (!options.skipInstall) {
68
+ // Compile and install datapack
69
+ const outDir = path.join(MC_SERVER_DIR, 'world', 'datapacks', 'redscript-test');
70
+ console.log(`Compiling ${sourceFile}...`);
71
+ const ns = path.basename(sourceFile, '.mcrs');
72
+ const result = (0, compile_1.compile)(fs.readFileSync(sourceFile, 'utf-8'), { namespace: ns, filePath: sourceFile });
73
+ if (!result.files) {
74
+ throw new Error('Compilation failed');
75
+ }
76
+ // Write files
77
+ fs.mkdirSync(outDir, { recursive: true });
78
+ for (const file of result.files) {
79
+ const filePath = path.join(outDir, file.path);
80
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
81
+ fs.writeFileSync(filePath, file.content);
82
+ }
83
+ console.log(`✓ Datapack installed to ${outDir}`);
84
+ // Reload datapacks
85
+ await mc.command('/reload');
86
+ await mc.ticks(40); // wait 2s for reload
87
+ console.log('✓ Datapacks reloaded');
88
+ }
89
+ // Run tests
90
+ const results = [];
91
+ for (const test of tests) {
92
+ await mc.reset(); // clear logs before each test
93
+ const start = Date.now();
94
+ try {
95
+ await test.run(mc);
96
+ results.push({ name: test.name, passed: true, durationMs: Date.now() - start });
97
+ console.log(` ✓ ${test.name} (${Date.now() - start}ms)`);
98
+ }
99
+ catch (err) {
100
+ results.push({
101
+ name: test.name,
102
+ passed: false,
103
+ error: err.message,
104
+ durationMs: Date.now() - start
105
+ });
106
+ console.log(` ✗ ${test.name}: ${err.message}`);
107
+ }
108
+ }
109
+ // Summary
110
+ const passed = results.filter(r => r.passed).length;
111
+ const failed = results.length - passed;
112
+ console.log(`\nResults: ${passed}/${results.length} passed${failed > 0 ? ` (${failed} FAILED)` : ''}`);
113
+ return results;
114
+ }
115
+ // CLI entry point
116
+ if (require.main === module) {
117
+ const sourceFile = process.argv[2];
118
+ if (!sourceFile) {
119
+ console.error('Usage: ts-node runner.ts <source.mcrs>');
120
+ process.exit(1);
121
+ }
122
+ // Example test suite (replace with actual tests)
123
+ const exampleTests = [
124
+ {
125
+ name: 'server is online',
126
+ run: async (mc) => {
127
+ const status = await mc.status();
128
+ if (!status.online)
129
+ throw new Error('Server not online');
130
+ }
131
+ },
132
+ {
133
+ name: 'datapack loads without errors',
134
+ run: async (mc) => {
135
+ await mc.command('/reload');
136
+ await mc.ticks(20);
137
+ // If reload didn't crash, we're good
138
+ }
139
+ }
140
+ ];
141
+ runMCTests(sourceFile, exampleTests)
142
+ .then(results => {
143
+ const failed = results.filter(r => !r.passed);
144
+ process.exit(failed.length > 0 ? 1 : 0);
145
+ })
146
+ .catch(err => {
147
+ console.error(err.message);
148
+ process.exit(1);
149
+ });
150
+ }
151
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * MC Test Setup Script
3
+ *
4
+ * Pre-compiles all RedScript test fixtures into the datapack directory.
5
+ * Run this ONCE before starting the Paper server, or before running tests
6
+ * with a fresh server.
7
+ *
8
+ * Usage:
9
+ * MC_SERVER_DIR=~/mc-test-server npx ts-node src/mc-test/setup.ts
10
+ */
11
+ export {};
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ /**
3
+ * MC Test Setup Script
4
+ *
5
+ * Pre-compiles all RedScript test fixtures into the datapack directory.
6
+ * Run this ONCE before starting the Paper server, or before running tests
7
+ * with a fresh server.
8
+ *
9
+ * Usage:
10
+ * MC_SERVER_DIR=~/mc-test-server npx ts-node src/mc-test/setup.ts
11
+ */
12
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ var desc = Object.getOwnPropertyDescriptor(m, k);
15
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
16
+ desc = { enumerable: true, get: function() { return m[k]; } };
17
+ }
18
+ Object.defineProperty(o, k2, desc);
19
+ }) : (function(o, m, k, k2) {
20
+ if (k2 === undefined) k2 = k;
21
+ o[k2] = m[k];
22
+ }));
23
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
24
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
25
+ }) : function(o, v) {
26
+ o["default"] = v;
27
+ });
28
+ var __importStar = (this && this.__importStar) || (function () {
29
+ var ownKeys = function(o) {
30
+ ownKeys = Object.getOwnPropertyNames || function (o) {
31
+ var ar = [];
32
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
33
+ return ar;
34
+ };
35
+ return ownKeys(o);
36
+ };
37
+ return function (mod) {
38
+ if (mod && mod.__esModule) return mod;
39
+ var result = {};
40
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
41
+ __setModuleDefault(result, mod);
42
+ return result;
43
+ };
44
+ })();
45
+ Object.defineProperty(exports, "__esModule", { value: true });
46
+ const fs = __importStar(require("fs"));
47
+ const path = __importStar(require("path"));
48
+ const compile_1 = require("../compile");
49
+ const MC_SERVER_DIR = process.env.MC_SERVER_DIR ?? path.join(process.env.HOME, 'mc-test-server');
50
+ const DATAPACK_DIR = path.join(MC_SERVER_DIR, 'world', 'datapacks', 'redscript-test');
51
+ const EXAMPLES_DIR = path.join(__dirname, '../examples');
52
+ function writeFixture(source, namespace) {
53
+ const result = (0, compile_1.compile)(source, { namespace });
54
+ let fileCount = 0;
55
+ for (const file of result.files ?? []) {
56
+ const filePath = path.join(DATAPACK_DIR, file.path);
57
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
58
+ fs.writeFileSync(filePath, file.content);
59
+ fileCount++;
60
+ }
61
+ console.log(` ✓ ${namespace} (${fileCount} files)`);
62
+ }
63
+ function main() {
64
+ console.log(`Setting up MC test fixtures in:\n ${DATAPACK_DIR}\n`);
65
+ fs.mkdirSync(DATAPACK_DIR, { recursive: true });
66
+ // Example files
67
+ const exampleNamespaces = ['counter', 'world_manager'];
68
+ for (const ns of exampleNamespaces) {
69
+ const file = path.join(EXAMPLES_DIR, `${ns}.mcrs`);
70
+ if (fs.existsSync(file)) {
71
+ writeFixture(fs.readFileSync(file, 'utf-8'), ns);
72
+ }
73
+ else {
74
+ console.log(` ⚠ ${ns}.mcrs not found, skipping`);
75
+ }
76
+ }
77
+ // Inline test fixtures
78
+ writeFixture(`
79
+ @tick
80
+ fn on_tick() {
81
+ scoreboard_set("#tick_counter", "ticks", scoreboard_get("#tick_counter", "ticks") + 1)
82
+ }
83
+ `, 'tick_test');
84
+ writeFixture(`
85
+ fn check_score() {
86
+ let x: int = scoreboard_get("#check_x", "test_score")
87
+ if (x > 5) {
88
+ scoreboard_set("#check_x", "result", 1)
89
+ } else {
90
+ scoreboard_set("#check_x", "result", 0)
91
+ }
92
+ }
93
+ `, 'inline_test');
94
+ console.log('\n✅ All fixtures written. Restart the MC server to load them.');
95
+ console.log(' Then run: MC_SERVER_DIR=... npx jest mc-integration --testTimeout=60000');
96
+ }
97
+ main();
98
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1,17 @@
1
+ export interface ValidationResult {
2
+ valid: boolean;
3
+ error?: string;
4
+ }
5
+ export declare class MCCommandValidator {
6
+ private readonly root;
7
+ private readonly rootChildren;
8
+ constructor(commandsPath: string);
9
+ validate(line: string): ValidationResult;
10
+ private hasRootCommand;
11
+ private validateExecute;
12
+ private validateScoreboard;
13
+ private validateFunction;
14
+ private validateData;
15
+ private validateReturn;
16
+ private validateAgainstTree;
17
+ }