diff --git a/d2js/js/CHANGELOG.md b/d2js/js/CHANGELOG.md index 18767b5cc8..e06a4bac0d 100644 --- a/d2js/js/CHANGELOG.md +++ b/d2js/js/CHANGELOG.md @@ -5,7 +5,8 @@ include changes to the main d2 project.** ## Next -- Fix TypeScript signatures +- Fixed ESM and CJS builds of d2.js [#2286](https://github.com/terrastruct/d2/issues/2286) + [#1448](https://github.com/terrastruct/d2/issues/1448) + ## [0.1.22] ### March 20, 2025 diff --git a/d2js/js/build.js b/d2js/js/build.js index c445f49d4c..880a1f1927 100644 --- a/d2js/js/build.js +++ b/d2js/js/build.js @@ -1,5 +1,5 @@ import { build } from "bun"; -import { copyFile, mkdir, writeFile, readFile, rm } from "node:fs/promises"; +import { copyFile, mkdir, readFile, rm, writeFile } from "node:fs/promises"; import { join, resolve } from "node:path"; const __dirname = new URL(".", import.meta.url).pathname; diff --git a/d2js/js/bun.lockb b/d2js/js/bun.lockb index c2ef20a7e6..8d51918321 100755 Binary files a/d2js/js/bun.lockb and b/d2js/js/bun.lockb differ diff --git a/d2js/js/package.json b/d2js/js/package.json index 7355b74739..9c1ff9faf3 100644 --- a/d2js/js/package.json +++ b/d2js/js/package.json @@ -15,35 +15,33 @@ "publishConfig": { "access": "public" }, - "type": "module", - "main": "./dist/cjs/index.js", - "module": "./dist/esm/index.js", + "main": "./dist/node-cjs/index.js", + "module": "./dist/node-esm/index.js", + "types": "./index.d.ts", "exports": { ".": { + "types": "./index.d.ts", "browser": "./dist/browser/index.js", - "import": { - "browser": "./dist/browser/index.js", - "default": "./dist/node-esm/index.js", - "types": "./index.d.ts" - }, - "require": { - "default": "./dist/node-cjs/index.js", - "types": "./index.d.ts" - }, + "import": "./dist/node-esm/index.js", + "require": "./dist/node-cjs/index.js", "default": "./dist/node-esm/index.js" }, - "./worker": "./dist/browser/worker.js" + "./worker": { + "browser": "./dist/browser/worker.js", + "import": "./dist/node-esm/worker.js", + "require": "./dist/node-cjs/worker.js", + "default": "./dist/node-esm/worker.js" + } }, "files": [ "dist", "index.d.ts" ], - "types": "./index.d.ts", "scripts": { "build": "./make.sh build", - "test": "bun test test/unit", + "test:unit": "bun test test/unit", "test:integration": "bun test test/integration", - "test:all": "bun run test && bun run test:integration", + "test": "bun run test:unit && bun run test:integration", "dev": "bun --watch dev-server.js" }, "keywords": [ @@ -56,6 +54,6 @@ ], "license": "MPL-2.0", "devDependencies": { - "bun": "latest" - } + "bun": "latest" + } } diff --git a/d2js/js/test/integration/cjs.test.js b/d2js/js/test/integration/cjs.test.js index bb83d0f0fc..d4340989ba 100644 --- a/d2js/js/test/integration/cjs.test.js +++ b/d2js/js/test/integration/cjs.test.js @@ -1,7 +1,42 @@ -import { expect, test, describe } from "bun:test"; +import { describe, expect, test } from "bun:test"; describe("D2 CJS Integration", () => { - test("can require and use CJS build", async () => { + test("can require main entry point without error", () => { + expect(() => { + const module = require("../../dist/node-cjs/index.js"); + expect(module).toBeDefined(); + expect(module.D2).toBeDefined(); + expect(typeof module.D2).toBe("function"); + }).not.toThrow(); + }); + + test("worker module file exists", () => { + const fs = require("fs"); + const path = require("path"); + const workerPath = path.resolve(__dirname, "../../dist/node-cjs/worker.js"); + expect(fs.existsSync(workerPath)).toBe(true); + }); + + test("exported D2 class is constructable", () => { + const { D2 } = require("../../dist/node-cjs/index.js"); + expect(() => new D2()).not.toThrow(); + }); + + test("module exports match expected structure", () => { + const module = require("../../dist/node-cjs/index.js"); + expect(module).toHaveProperty("D2"); + expect(typeof module.D2).toBe("function"); + }); + + test("can access both named and default exports", () => { + const module = require("../../dist/node-cjs/index.js"); + const { D2 } = require("../../dist/node-cjs/index.js"); + + expect(module.D2).toBe(D2); + expect(module.D2).toBeDefined(); + }); + + test("can compile a diagram", async () => { const { D2 } = require("../../dist/node-cjs/index.js"); const d2 = new D2(); const result = await d2.compile("x -> y"); diff --git a/d2js/js/test/integration/esm.test.js b/d2js/js/test/integration/esm.test.js index bd1987a24a..021a40d399 100644 --- a/d2js/js/test/integration/esm.test.js +++ b/d2js/js/test/integration/esm.test.js @@ -1,8 +1,33 @@ -import { expect, test, describe } from "bun:test"; -import { D2 } from "../../dist/node-esm/index.js"; +import { describe, expect, test } from "bun:test"; describe("D2 ESM Integration", () => { + test("can import main entry point without error", async () => { + const module = await import("../../dist/node-esm/index.js"); + expect(module).toBeDefined(); + expect(module.D2).toBeDefined(); + expect(typeof module.D2).toBe("function"); + }); + + test("worker module file exists", () => { + const fs = require("fs"); + const path = require("path"); + const workerPath = path.resolve(__dirname, "../../dist/node-esm/worker.js"); + expect(fs.existsSync(workerPath)).toBe(true); + }); + + test("exported D2 class is constructable", () => { + return import("../../dist/node-esm/index.js").then(({ D2 }) => { + expect(() => new D2()).not.toThrow(); + }); + }); + + test("can import all exports from package.json exports field", async () => { + const mainModule = await import("../../index.d.ts"); + expect(mainModule).toBeDefined(); + }); + test("can import and use ESM build", async () => { + const { D2 } = await import("../../dist/node-esm/index.js"); const d2 = new D2(); const result = await d2.compile("x -> y"); expect(result.diagram).toBeDefined();