import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises"; import { existsSync } from "node:fs"; import { tmpdir } from "node:os"; import { dirname, join } from "node:path"; import { describe, expect, it } from "vitest"; import { compileBundle } from "@nengine/pack"; import { createEditEngine } from "../src/edit-engine.js"; import { runEditorPack } from "../src/pack.js"; import { writeProjectYaml } from "../src/project-yaml.js"; const MOD_A = [ "export default {", ' manifest: { id: "a-mod", version: "1.0.0" },', " hooks: { onDayStart() {} },", "};", "", ].join("\n"); const MOD_B = [ "export default {", ' manifest: { id: "b-mod", version: "1.0.0" },', " hooks: { onDayStart() {} },", "};", "", ].join("\n"); const FIXTURE_FILES: Record = { "content/time.yaml": [ "id: default", "dayLengthTicks: 240", "seasons:", " - { name: spring, dayCount: 14 }", "start: { day: 1, season: spring }", "", ].join("\n"), "content/maps/farm.yaml": [ "id: farm", "width: 8", "height: 8", "tilesetRef: farm-tiles", "spawn: { x: 1, y: 1 }", "layers:", " - name: ground", " data:", ...mapRows(), "", ].join("\n"), "mods/a-mod/index.mjs": MOD_A, "mods/b-mod/index.mjs": MOD_B, }; function mapRows(): string[] { const rows: string[] = []; for (let y = 0; y < 8; y++) { const row: string[] = []; for (let x = 0; x < 8; x++) row.push("grass"); rows.push(` - [${row.join(", ")}]`); } return rows; } async function fixtureDir(): Promise { const dir = await mkdtemp(join(tmpdir(), "editor-mods-consumers-")); for (const [rel, content] of Object.entries(FIXTURE_FILES)) { const target = join(dir, rel); await mkdir(dirname(target), { recursive: true }); await writeFile(target, content, "utf8"); } return dir; } async function rmRecursive(dir: string): Promise { await rm(dir, { recursive: true, force: true }); } function packOptions(): Parameters[1] { return { name: "Mods Farm", icon: "", desktop: false, installer: false, mods: true, splitAssets: false, outDir: "" }; } describe("F1 consumer wiring", () => { it("createEditEngine applies the enabledMods filter (undefined = all)", async () => { const dir = await fixtureDir(); try { const filtered = createEditEngine(dir, ["a-mod"]); await filtered.start(); try { expect(filtered.mods.map((m) => m.id)).toEqual(["a-mod"]); } finally { await filtered.stop(); } const all = createEditEngine(dir); await all.start(); try { expect(all.mods.map((m) => m.id).sort()).toEqual(["a-mod", "b-mod"]); } finally { await all.stop(); } } finally { await rmRecursive(dir); } }); it("compileBundle with an enabledMods list packages only the enabled mods", async () => { const dir = await fixtureDir(); try { const filtered = await compileBundle(join(dir, "content"), join(dir, "mods"), false, ["b-mod"]); expect(Object.keys(filtered.mods ?? {})).toEqual(["b-mod"]); const all = await compileBundle(join(dir, "content"), join(dir, "mods")); expect(Object.keys(all.mods ?? {}).sort()).toEqual(["a-mod", "b-mod"]); } finally { await rmRecursive(dir); } }); it("runEditorPack honors project.yaml mods.enabled (main parity)", async () => { const dir = await fixtureDir(); try { await writeProjectYaml(dir, { mods: { enabled: ["a-mod"] } }); const result = await runEditorPack(dir, packOptions(), existsSync(join(dir, "mods"))); expect(result.ok).toBe(true); if (!result.ok) return; expect(result.stats.modCount).toBe(1); const bundle = JSON.parse( await (await import("node:fs/promises")).readFile(join(result.outDir, "bundle.json"), "utf8"), ); expect(Object.keys(bundle.mods ?? {})).toEqual(["a-mod"]); } finally { await rmRecursive(dir); } }); });