@el4cteo/rbx-studio-mcp 0.4.6 → 0.5.2

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.
@@ -1,82 +1,85 @@
1
- /**
2
- * Runs the plugin's unit tests outside Roblox Studio.
3
- *
4
- * The modules under test import their dependencies with `require(script.Parent.X)`,
5
- * which only resolves inside Studio. Rather than mock the engine, this bundles
6
- * the real module source with a stub for its one dependency and runs the result
7
- * through the standalone Luau interpreter, so the tests exercise the shipped
8
- * code rather than a copy of it.
9
- *
10
- * Needs the `luau` binary on PATH, in ./tools, or named by the LUAU variable.
11
- * Get one from https://github.com/luau-lang/luau/releases.
12
- *
13
- * Usage: node scripts/test-plugin.mjs
14
- */
15
- import { spawnSync } from "node:child_process";
16
- import { mkdtempSync, readFileSync, writeFileSync } from "node:fs";
17
- import { tmpdir } from "node:os";
18
- import { dirname, join, resolve } from "node:path";
19
- import { fileURLToPath } from "node:url";
20
- import { locateLuau, missingLuau } from "./locate-luau.mjs";
21
-
22
- const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
23
- const luau = locateLuau("LUAU", ["luau.exe", "luau"]);
24
- if (luau === null) {
25
- process.stderr.write(missingLuau("luau", "LUAU"));
26
- process.exit(1);
27
- }
28
-
29
- /** Modules under test, paired with the test file that exercises each. */
30
- const suites = [{ module: "plugin/src/TextEdit.luau", test: "tests/textedit.luau" }];
31
-
32
- /**
33
- * The stub stands in for Dispatch. It has to raise the same structured table the
34
- * real one does, because the tests assert on `code` -- that contract is what the
35
- * MCP server turns into an actionable error for the agent.
36
- */
37
- const DISPATCH_STUB = `local Dispatch = {}
38
- function Dispatch.fail(code, message, hint)
39
- \terror({ code = code, message = message, hint = hint }, 0)
40
- end
41
- `;
42
-
43
- /** Drops the module's own requires; the stub above is already in scope. */
44
- const stripRequires = (source) =>
45
- source.replace(/^local \w+ = require\(script[^\n]*\n/gm, "");
46
-
47
- let failures = 0;
48
-
49
- for (const suite of suites) {
50
- const moduleSource = stripRequires(readFileSync(join(root, suite.module), "utf8"));
51
- const testSource = readFileSync(join(root, suite.test), "utf8");
52
-
53
- const bundle = [
54
- DISPATCH_STUB,
55
- "local Module = (function()",
56
- moduleSource,
57
- "end)()",
58
- "local run = function(...)",
59
- testSource,
60
- "end",
61
- "run(Module)",
62
- "",
63
- ].join("\n");
64
-
65
- const bundlePath = join(mkdtempSync(join(tmpdir(), "studio-mcp-test-")), "bundle.luau");
66
- writeFileSync(bundlePath, bundle, "utf8");
67
-
68
- const result = spawnSync(luau, [bundlePath], { stdio: "inherit" });
69
- if (result.error) {
70
- process.stderr.write(
71
- `could not run '${luau}': ${result.error.message}\n` +
72
- "Set LUAU to the path of a Luau interpreter.\n",
73
- );
74
- process.exit(1);
75
- }
76
- if (result.status !== 0) {
77
- process.stderr.write(`FAIL ${suite.test}\n`);
78
- failures += 1;
79
- }
80
- }
81
-
82
- process.exit(failures === 0 ? 0 : 1);
1
+ /**
2
+ * Runs the plugin's unit tests outside Roblox Studio.
3
+ *
4
+ * The modules under test import their dependencies with `require(script.Parent.X)`,
5
+ * which only resolves inside Studio. Rather than mock the engine, this bundles
6
+ * the real module source with a stub for its one dependency and runs the result
7
+ * through the standalone Luau interpreter, so the tests exercise the shipped
8
+ * code rather than a copy of it.
9
+ *
10
+ * Needs the `luau` binary on PATH, in ./tools, or named by the LUAU variable.
11
+ * Get one from https://github.com/luau-lang/luau/releases.
12
+ *
13
+ * Usage: node scripts/test-plugin.mjs
14
+ */
15
+ import { spawnSync } from "node:child_process";
16
+ import { mkdtempSync, readFileSync, writeFileSync } from "node:fs";
17
+ import { tmpdir } from "node:os";
18
+ import { dirname, join, resolve } from "node:path";
19
+ import { fileURLToPath } from "node:url";
20
+ import { locateLuau, missingLuau } from "./locate-luau.mjs";
21
+
22
+ const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
23
+ const luau = locateLuau("LUAU", ["luau.exe", "luau"]);
24
+ if (luau === null) {
25
+ process.stderr.write(missingLuau("luau", "LUAU"));
26
+ process.exit(1);
27
+ }
28
+
29
+ /** Modules under test, paired with the test file that exercises each. */
30
+ const suites = [
31
+ { module: "plugin/src/TextEdit.luau", test: "tests/textedit.luau" },
32
+ { module: "plugin/src/Format.luau", test: "tests/format.luau" },
33
+ ];
34
+
35
+ /**
36
+ * The stub stands in for Dispatch. It has to raise the same structured table the
37
+ * real one does, because the tests assert on `code` -- that contract is what the
38
+ * MCP server turns into an actionable error for the agent.
39
+ */
40
+ const DISPATCH_STUB = `local Dispatch = {}
41
+ function Dispatch.fail(code, message, hint)
42
+ \terror({ code = code, message = message, hint = hint }, 0)
43
+ end
44
+ `;
45
+
46
+ /** Drops the module's own requires; the stub above is already in scope. */
47
+ const stripRequires = (source) =>
48
+ source.replace(/^local \w+ = require\(script[^\n]*\n/gm, "");
49
+
50
+ let failures = 0;
51
+
52
+ for (const suite of suites) {
53
+ const moduleSource = stripRequires(readFileSync(join(root, suite.module), "utf8"));
54
+ const testSource = readFileSync(join(root, suite.test), "utf8");
55
+
56
+ const bundle = [
57
+ DISPATCH_STUB,
58
+ "local Module = (function()",
59
+ moduleSource,
60
+ "end)()",
61
+ "local run = function(...)",
62
+ testSource,
63
+ "end",
64
+ "run(Module)",
65
+ "",
66
+ ].join("\n");
67
+
68
+ const bundlePath = join(mkdtempSync(join(tmpdir(), "studio-mcp-test-")), "bundle.luau");
69
+ writeFileSync(bundlePath, bundle, "utf8");
70
+
71
+ const result = spawnSync(luau, [bundlePath], { stdio: "inherit" });
72
+ if (result.error) {
73
+ process.stderr.write(
74
+ `could not run '${luau}': ${result.error.message}\n` +
75
+ "Set LUAU to the path of a Luau interpreter.\n",
76
+ );
77
+ process.exit(1);
78
+ }
79
+ if (result.status !== 0) {
80
+ process.stderr.write(`FAIL ${suite.test}\n`);
81
+ failures += 1;
82
+ }
83
+ }
84
+
85
+ process.exit(failures === 0 ? 0 : 1);