redscript-mc 1.2.29 → 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 (274) 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/README.md +29 -28
  8. package/README.zh.md +28 -28
  9. package/demo.gif +0 -0
  10. package/dist/cli.js +2 -554
  11. package/dist/compile.js +2 -266
  12. package/dist/index.js +2 -159
  13. package/dist/lexer/index.js +9 -1
  14. package/dist/lowering/index.js +22 -5
  15. package/dist/src/__tests__/cli.test.d.ts +1 -0
  16. package/dist/src/__tests__/cli.test.js +104 -0
  17. package/dist/src/__tests__/codegen.test.d.ts +1 -0
  18. package/dist/src/__tests__/codegen.test.js +152 -0
  19. package/dist/src/__tests__/compile-all.test.d.ts +10 -0
  20. package/dist/src/__tests__/compile-all.test.js +108 -0
  21. package/dist/src/__tests__/dce.test.d.ts +1 -0
  22. package/dist/src/__tests__/dce.test.js +102 -0
  23. package/dist/src/__tests__/diagnostics.test.d.ts +4 -0
  24. package/dist/src/__tests__/diagnostics.test.js +177 -0
  25. package/dist/src/__tests__/e2e.test.d.ts +6 -0
  26. package/dist/src/__tests__/e2e.test.js +1789 -0
  27. package/dist/src/__tests__/entity-types.test.d.ts +1 -0
  28. package/dist/src/__tests__/entity-types.test.js +203 -0
  29. package/dist/src/__tests__/formatter.test.d.ts +1 -0
  30. package/dist/src/__tests__/formatter.test.js +40 -0
  31. package/dist/src/__tests__/lexer.test.d.ts +1 -0
  32. package/dist/src/__tests__/lexer.test.js +343 -0
  33. package/dist/src/__tests__/lowering.test.d.ts +1 -0
  34. package/dist/src/__tests__/lowering.test.js +1015 -0
  35. package/dist/src/__tests__/macro.test.d.ts +8 -0
  36. package/dist/src/__tests__/macro.test.js +306 -0
  37. package/dist/src/__tests__/mc-integration.test.d.ts +12 -0
  38. package/dist/src/__tests__/mc-integration.test.js +817 -0
  39. package/dist/src/__tests__/mc-syntax.test.d.ts +1 -0
  40. package/dist/src/__tests__/mc-syntax.test.js +124 -0
  41. package/dist/src/__tests__/nbt.test.d.ts +1 -0
  42. package/dist/src/__tests__/nbt.test.js +82 -0
  43. package/dist/src/__tests__/optimizer-advanced.test.d.ts +1 -0
  44. package/dist/src/__tests__/optimizer-advanced.test.js +124 -0
  45. package/dist/src/__tests__/optimizer.test.d.ts +1 -0
  46. package/dist/src/__tests__/optimizer.test.js +149 -0
  47. package/dist/src/__tests__/parser.test.d.ts +1 -0
  48. package/dist/src/__tests__/parser.test.js +807 -0
  49. package/dist/src/__tests__/repl.test.d.ts +1 -0
  50. package/dist/src/__tests__/repl.test.js +27 -0
  51. package/dist/src/__tests__/runtime.test.d.ts +1 -0
  52. package/dist/src/__tests__/runtime.test.js +289 -0
  53. package/dist/src/__tests__/stdlib-advanced.test.d.ts +4 -0
  54. package/dist/src/__tests__/stdlib-advanced.test.js +374 -0
  55. package/dist/src/__tests__/stdlib-bigint.test.d.ts +7 -0
  56. package/dist/src/__tests__/stdlib-bigint.test.js +426 -0
  57. package/dist/src/__tests__/stdlib-math.test.d.ts +7 -0
  58. package/dist/src/__tests__/stdlib-math.test.js +351 -0
  59. package/dist/src/__tests__/stdlib-vec.test.d.ts +4 -0
  60. package/dist/src/__tests__/stdlib-vec.test.js +263 -0
  61. package/dist/src/__tests__/structure-optimizer.test.d.ts +1 -0
  62. package/dist/src/__tests__/structure-optimizer.test.js +33 -0
  63. package/dist/src/__tests__/typechecker.test.d.ts +1 -0
  64. package/dist/src/__tests__/typechecker.test.js +552 -0
  65. package/dist/src/__tests__/var-allocator.test.d.ts +1 -0
  66. package/dist/src/__tests__/var-allocator.test.js +69 -0
  67. package/dist/src/ast/types.d.ts +515 -0
  68. package/dist/src/ast/types.js +9 -0
  69. package/dist/src/builtins/metadata.d.ts +36 -0
  70. package/dist/src/builtins/metadata.js +1014 -0
  71. package/dist/src/cli.d.ts +11 -0
  72. package/dist/src/cli.js +443 -0
  73. package/dist/src/codegen/cmdblock/index.d.ts +26 -0
  74. package/dist/src/codegen/cmdblock/index.js +45 -0
  75. package/dist/src/codegen/mcfunction/index.d.ts +40 -0
  76. package/dist/src/codegen/mcfunction/index.js +606 -0
  77. package/dist/src/codegen/structure/index.d.ts +24 -0
  78. package/dist/src/codegen/structure/index.js +279 -0
  79. package/dist/src/codegen/var-allocator.d.ts +45 -0
  80. package/dist/src/codegen/var-allocator.js +104 -0
  81. package/dist/src/compile.d.ts +37 -0
  82. package/dist/src/compile.js +165 -0
  83. package/dist/src/diagnostics/index.d.ts +44 -0
  84. package/dist/src/diagnostics/index.js +140 -0
  85. package/dist/src/events/types.d.ts +35 -0
  86. package/dist/src/events/types.js +59 -0
  87. package/dist/src/formatter/index.d.ts +1 -0
  88. package/dist/src/formatter/index.js +26 -0
  89. package/dist/src/index.d.ts +22 -0
  90. package/dist/src/index.js +45 -0
  91. package/dist/src/ir/builder.d.ts +33 -0
  92. package/dist/src/ir/builder.js +99 -0
  93. package/dist/src/ir/types.d.ts +132 -0
  94. package/dist/src/ir/types.js +15 -0
  95. package/dist/src/lexer/index.d.ts +37 -0
  96. package/dist/src/lexer/index.js +569 -0
  97. package/dist/src/lowering/index.d.ts +188 -0
  98. package/dist/src/lowering/index.js +3405 -0
  99. package/dist/src/mc-test/client.d.ts +128 -0
  100. package/dist/src/mc-test/client.js +174 -0
  101. package/dist/src/mc-test/runner.d.ts +28 -0
  102. package/dist/src/mc-test/runner.js +151 -0
  103. package/dist/src/mc-test/setup.d.ts +11 -0
  104. package/dist/src/mc-test/setup.js +98 -0
  105. package/dist/src/mc-validator/index.d.ts +17 -0
  106. package/dist/src/mc-validator/index.js +322 -0
  107. package/dist/src/nbt/index.d.ts +86 -0
  108. package/dist/src/nbt/index.js +250 -0
  109. package/dist/src/optimizer/commands.d.ts +38 -0
  110. package/dist/src/optimizer/commands.js +451 -0
  111. package/dist/src/optimizer/dce.d.ts +34 -0
  112. package/dist/src/optimizer/dce.js +639 -0
  113. package/dist/src/optimizer/passes.d.ts +34 -0
  114. package/dist/src/optimizer/passes.js +243 -0
  115. package/dist/src/optimizer/structure.d.ts +9 -0
  116. package/dist/src/optimizer/structure.js +356 -0
  117. package/dist/src/parser/index.d.ts +93 -0
  118. package/dist/src/parser/index.js +1687 -0
  119. package/dist/src/repl.d.ts +16 -0
  120. package/dist/src/repl.js +165 -0
  121. package/dist/src/runtime/index.d.ts +107 -0
  122. package/dist/src/runtime/index.js +1409 -0
  123. package/dist/src/typechecker/index.d.ts +61 -0
  124. package/dist/src/typechecker/index.js +1034 -0
  125. package/dist/src/types/entity-hierarchy.d.ts +29 -0
  126. package/dist/src/types/entity-hierarchy.js +107 -0
  127. package/dist/src2/__tests__/e2e/basic.test.d.ts +8 -0
  128. package/dist/src2/__tests__/e2e/basic.test.js +140 -0
  129. package/dist/src2/__tests__/e2e/macros.test.d.ts +9 -0
  130. package/dist/src2/__tests__/e2e/macros.test.js +182 -0
  131. package/dist/src2/__tests__/e2e/migrate.test.d.ts +13 -0
  132. package/dist/src2/__tests__/e2e/migrate.test.js +2739 -0
  133. package/dist/src2/__tests__/hir/desugar.test.d.ts +1 -0
  134. package/dist/src2/__tests__/hir/desugar.test.js +234 -0
  135. package/dist/src2/__tests__/lir/lower.test.d.ts +1 -0
  136. package/dist/src2/__tests__/lir/lower.test.js +559 -0
  137. package/dist/src2/__tests__/lir/types.test.d.ts +1 -0
  138. package/dist/src2/__tests__/lir/types.test.js +185 -0
  139. package/dist/src2/__tests__/lir/verify.test.d.ts +1 -0
  140. package/dist/src2/__tests__/lir/verify.test.js +221 -0
  141. package/dist/src2/__tests__/mir/arithmetic.test.d.ts +1 -0
  142. package/dist/src2/__tests__/mir/arithmetic.test.js +130 -0
  143. package/dist/src2/__tests__/mir/control-flow.test.d.ts +1 -0
  144. package/dist/src2/__tests__/mir/control-flow.test.js +205 -0
  145. package/dist/src2/__tests__/mir/verify.test.d.ts +1 -0
  146. package/dist/src2/__tests__/mir/verify.test.js +223 -0
  147. package/dist/src2/__tests__/optimizer/block_merge.test.d.ts +1 -0
  148. package/dist/src2/__tests__/optimizer/block_merge.test.js +78 -0
  149. package/dist/src2/__tests__/optimizer/branch_simplify.test.d.ts +1 -0
  150. package/dist/src2/__tests__/optimizer/branch_simplify.test.js +58 -0
  151. package/dist/src2/__tests__/optimizer/constant_fold.test.d.ts +1 -0
  152. package/dist/src2/__tests__/optimizer/constant_fold.test.js +131 -0
  153. package/dist/src2/__tests__/optimizer/copy_prop.test.d.ts +1 -0
  154. package/dist/src2/__tests__/optimizer/copy_prop.test.js +91 -0
  155. package/dist/src2/__tests__/optimizer/dce.test.d.ts +1 -0
  156. package/dist/src2/__tests__/optimizer/dce.test.js +76 -0
  157. package/dist/src2/__tests__/optimizer/pipeline.test.d.ts +1 -0
  158. package/dist/src2/__tests__/optimizer/pipeline.test.js +102 -0
  159. package/dist/src2/emit/compile.d.ts +19 -0
  160. package/dist/src2/emit/compile.js +80 -0
  161. package/dist/src2/emit/index.d.ts +17 -0
  162. package/dist/src2/emit/index.js +172 -0
  163. package/dist/src2/hir/lower.d.ts +15 -0
  164. package/dist/src2/hir/lower.js +378 -0
  165. package/dist/src2/hir/types.d.ts +373 -0
  166. package/dist/src2/hir/types.js +16 -0
  167. package/dist/src2/lir/lower.d.ts +15 -0
  168. package/dist/src2/lir/lower.js +453 -0
  169. package/dist/src2/lir/types.d.ts +136 -0
  170. package/dist/src2/lir/types.js +11 -0
  171. package/dist/src2/lir/verify.d.ts +14 -0
  172. package/dist/src2/lir/verify.js +113 -0
  173. package/dist/src2/mir/lower.d.ts +9 -0
  174. package/dist/src2/mir/lower.js +1030 -0
  175. package/dist/src2/mir/macro.d.ts +22 -0
  176. package/dist/src2/mir/macro.js +168 -0
  177. package/dist/src2/mir/types.d.ts +183 -0
  178. package/dist/src2/mir/types.js +11 -0
  179. package/dist/src2/mir/verify.d.ts +16 -0
  180. package/dist/src2/mir/verify.js +216 -0
  181. package/dist/src2/optimizer/block_merge.d.ts +12 -0
  182. package/dist/src2/optimizer/block_merge.js +84 -0
  183. package/dist/src2/optimizer/branch_simplify.d.ts +9 -0
  184. package/dist/src2/optimizer/branch_simplify.js +28 -0
  185. package/dist/src2/optimizer/constant_fold.d.ts +10 -0
  186. package/dist/src2/optimizer/constant_fold.js +85 -0
  187. package/dist/src2/optimizer/copy_prop.d.ts +9 -0
  188. package/dist/src2/optimizer/copy_prop.js +113 -0
  189. package/dist/src2/optimizer/dce.d.ts +8 -0
  190. package/dist/src2/optimizer/dce.js +155 -0
  191. package/dist/src2/optimizer/pipeline.d.ts +10 -0
  192. package/dist/src2/optimizer/pipeline.js +42 -0
  193. package/dist/tsconfig.tsbuildinfo +1 -0
  194. package/docs/compiler-pipeline-redesign.md +2243 -0
  195. package/docs/optimization-ideas.md +1076 -0
  196. package/editors/vscode/package-lock.json +3 -3
  197. package/editors/vscode/package.json +1 -1
  198. package/examples/readme-demo.mcrs +44 -66
  199. package/jest.config.js +1 -1
  200. package/package.json +6 -5
  201. package/scripts/postbuild.js +15 -0
  202. package/src/__tests__/cli.test.ts +8 -220
  203. package/src/__tests__/dce.test.ts +11 -56
  204. package/src/__tests__/diagnostics.test.ts +59 -38
  205. package/src/__tests__/mc-integration.test.ts +1 -2
  206. package/src/ast/types.ts +6 -1
  207. package/src/cli.ts +29 -156
  208. package/src/compile.ts +6 -162
  209. package/src/index.ts +14 -178
  210. package/src/lexer/index.ts +9 -1
  211. package/src/mc-test/runner.ts +4 -3
  212. package/src/parser/index.ts +1 -1
  213. package/src/repl.ts +1 -1
  214. package/src/runtime/index.ts +1 -1
  215. package/src2/__tests__/e2e/basic.test.ts +154 -0
  216. package/src2/__tests__/e2e/macros.test.ts +199 -0
  217. package/src2/__tests__/e2e/migrate.test.ts +3008 -0
  218. package/src2/__tests__/hir/desugar.test.ts +263 -0
  219. package/src2/__tests__/lir/lower.test.ts +619 -0
  220. package/src2/__tests__/lir/types.test.ts +207 -0
  221. package/src2/__tests__/lir/verify.test.ts +249 -0
  222. package/src2/__tests__/mir/arithmetic.test.ts +156 -0
  223. package/src2/__tests__/mir/control-flow.test.ts +242 -0
  224. package/src2/__tests__/mir/verify.test.ts +254 -0
  225. package/src2/__tests__/optimizer/block_merge.test.ts +84 -0
  226. package/src2/__tests__/optimizer/branch_simplify.test.ts +64 -0
  227. package/src2/__tests__/optimizer/constant_fold.test.ts +145 -0
  228. package/src2/__tests__/optimizer/copy_prop.test.ts +99 -0
  229. package/src2/__tests__/optimizer/dce.test.ts +83 -0
  230. package/src2/__tests__/optimizer/pipeline.test.ts +116 -0
  231. package/src2/emit/compile.ts +99 -0
  232. package/src2/emit/index.ts +222 -0
  233. package/src2/hir/lower.ts +428 -0
  234. package/src2/hir/types.ts +216 -0
  235. package/src2/lir/lower.ts +556 -0
  236. package/src2/lir/types.ts +109 -0
  237. package/src2/lir/verify.ts +129 -0
  238. package/src2/mir/lower.ts +1160 -0
  239. package/src2/mir/macro.ts +167 -0
  240. package/src2/mir/types.ts +106 -0
  241. package/src2/mir/verify.ts +218 -0
  242. package/src2/optimizer/block_merge.ts +93 -0
  243. package/src2/optimizer/branch_simplify.ts +27 -0
  244. package/src2/optimizer/constant_fold.ts +88 -0
  245. package/src2/optimizer/copy_prop.ts +106 -0
  246. package/src2/optimizer/dce.ts +133 -0
  247. package/src2/optimizer/pipeline.ts +44 -0
  248. package/tsconfig.json +2 -2
  249. package/src/__tests__/codegen.test.ts +0 -161
  250. package/src/__tests__/e2e.test.ts +0 -2039
  251. package/src/__tests__/entity-types.test.ts +0 -236
  252. package/src/__tests__/lowering.test.ts +0 -1185
  253. package/src/__tests__/macro.test.ts +0 -343
  254. package/src/__tests__/nbt.test.ts +0 -58
  255. package/src/__tests__/optimizer-advanced.test.ts +0 -144
  256. package/src/__tests__/optimizer.test.ts +0 -162
  257. package/src/__tests__/runtime.test.ts +0 -305
  258. package/src/__tests__/stdlib-advanced.test.ts +0 -379
  259. package/src/__tests__/stdlib-bigint.test.ts +0 -427
  260. package/src/__tests__/stdlib-math.test.ts +0 -374
  261. package/src/__tests__/stdlib-vec.test.ts +0 -259
  262. package/src/__tests__/structure-optimizer.test.ts +0 -38
  263. package/src/__tests__/var-allocator.test.ts +0 -75
  264. package/src/codegen/cmdblock/index.ts +0 -63
  265. package/src/codegen/mcfunction/index.ts +0 -662
  266. package/src/codegen/structure/index.ts +0 -346
  267. package/src/codegen/var-allocator.ts +0 -104
  268. package/src/ir/builder.ts +0 -116
  269. package/src/ir/types.ts +0 -134
  270. package/src/lowering/index.ts +0 -3860
  271. package/src/optimizer/commands.ts +0 -534
  272. package/src/optimizer/dce.ts +0 -679
  273. package/src/optimizer/passes.ts +0 -250
  274. 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
+ }