Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions index.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,20 @@
*
* @module uuid
*/
const { createRequire } = require("module");
const requireESM = createRequire(__filename);
"use strict";

const { UUID, uuid, ISSUER_CATEGORIES } = requireESM("./index.mjs");
// index.cjs is a thin wrapper: it loads index.mjs through Node's synchronous require(esm).
// Node.js versions without require(esm) would fail with a bare ERR_REQUIRE_ESM, so fail
// early with a message that says what to do instead.
if (!process.features?.require_module) {
const error = new Error(
`@cldmv/uuid: require() needs Node.js ^20.19.0 or >=22.12.0 (this is ${process.version}). On older Node.js, load the package with import() instead.`
);
error.code = "ERR_REQUIRE_ESM";
throw error;
}

const { UUID, uuid, ISSUER_CATEGORIES } = require("./index.mjs");

// Export UUID as default
module.exports = UUID;
Expand Down
23 changes: 14 additions & 9 deletions index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,24 @@
*
*/

// Development environment check (must happen before UUID imports)
try {
await import("./devcheck.mjs");
} catch {
// ignore
}
// Development environment check. devcheck.mjs exists only in a source checkout; it is
// never published, so the import is allowed to fail. It runs inside an async function
// rather than as a top-level await: index.cjs loads this file through Node's synchronous
// require(esm), which rejects any module graph containing top-level await
// (ERR_REQUIRE_ASYNC_MODULE).
(async () => {
try {
await import("./devcheck.mjs");
} catch {
// ignore - devcheck.mjs is not published
}
})();

/**
* ESM entry point for UUID
*
* Re-exports all components from the main UUID module
*/
const { UUID, ISSUER_CATEGORIES } = await import("@cldmv/uuid/main");
import { UUID, ISSUER_CATEGORIES } from "@cldmv/uuid/main";

export { UUID, UUID as uuid, ISSUER_CATEGORIES };
export default UUID;
export { UUID as default, UUID, UUID as uuid, ISSUER_CATEGORIES };
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,10 @@
"build:dist": "node -e \"const fs = require('fs'); const path = require('path'); fs.rmSync('dist', {recursive: true, force: true}); fs.mkdirSync('dist', {recursive: true}); fs.cpSync('src', 'dist', {recursive: true});\"",
"build:types": "node -e \"require('fs').rmSync('types', {recursive: true, force: true})\" && tsc --project .configs/tsconfig.dts.jsonc",
"demo": "node scripts/demo-custom-uuids.mjs",
"test": "node tests/run-vitest.mjs",
"test": "node tests/run-vitest.mjs && npm run test:cjs",
"test:cjs": "node --conditions=uuid-dev --test tests/cjs/entry.test.cjs",
"test:watch": "vitest --config .configs/vitest.config.mjs",
"coverage": "node tests/run-vitest.mjs --coverage-quiet",
"coverage": "node tests/run-vitest.mjs --coverage-quiet && npm run test:cjs",
"ci:coverage": "npm run coverage",
"fix:headers": "fix-headers --config .configs/fix-headers.json",
"types:build": "tsc -p .configs/tsconfig.dts.jsonc --noCheck",
Expand Down
54 changes: 54 additions & 0 deletions tests/cjs/entry.test.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
*
* @Project: @cldmv/uuid
* @Filename: /tests/cjs/entry.test.cjs
* @Date: 2026-10-03T10:18:01-07:00 (1791047881)
* @Author: Nate Corcoran <CLDMV>
* @Email: <Shinrai@users.noreply.github.com>
* -----
* @Last modified by: Nate Corcoran <CLDMV> (Shinrai@users.noreply.github.com)
* @Last modified time: 2026-10-03T10:24:06-07:00 (1791048246)
* -----
* @Copyright: Copyright (c) 2013-2026 Catalyzed Motivation Inc. All rights reserved.
*
*/

/**
* CommonJS entry tests. These run under Node's own test runner (`node --test`), not Vitest:
* Vitest loads files through its own module runner, so it cannot show whether a plain
* `require()` of the package works the way it does for a CommonJS consumer.
*/
"use strict";

const { test } = require("node:test");
const assert = require("node:assert/strict");
const { spawnSync } = require("node:child_process");
const path = require("node:path");

const repoRoot = path.resolve(__dirname, "../..");
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;

test("require() returns the same UUID object as import", async () => {
const UUID = require("../../index.cjs");
const esm = await import("../../index.mjs");

assert.equal(UUID, esm.default);
assert.equal(UUID.UUID, esm.UUID);
assert.equal(UUID.uuid, esm.uuid);
assert.equal(UUID.ISSUER_CATEGORIES, esm.ISSUER_CATEGORIES);
assert.match(String(UUID.v4()), UUID_PATTERN);
});

test("require() fails with a clear message where Node.js has no require(esm)", () => {
// --no-experimental-require-module turns require(esm) off, which is what Node.js
// versions before 20.19 / 22.12 look like to the entry.
const res = spawnSync(process.execPath, ["--no-experimental-require-module", "-e", "require('./index.cjs')"], {
cwd: repoRoot,
encoding: "utf8"
});

assert.notEqual(res.status, 0);
assert.match(res.stderr, /ERR_REQUIRE_ESM/);
assert.match(res.stderr, /require\(\) needs Node\.js \^20\.19\.0 or >=22\.12\.0/);
assert.match(res.stderr, /import\(\)/);
});
17 changes: 3 additions & 14 deletions types/index.d.mts
Original file line number Diff line number Diff line change
@@ -1,15 +1,4 @@
export default UUID;
export const UUID: typeof import("@cldmv/uuid/main").UUID;
export const ISSUER_CATEGORIES: {
UNASSIGNED: number;
DRAFTER_RESERVED: number;
CATEGORY_A_START: number;
CATEGORY_A_END: number;
CATEGORY_B_START: number;
CATEGORY_B_END: number;
SPEC_ORIGINATOR: number;
RFC_EXPANSION_START: number;
RFC_EXPANSION_END: number;
};
export { UUID as uuid };
import { UUID } from "@cldmv/uuid/main";
import { ISSUER_CATEGORIES } from "@cldmv/uuid/main";
export { UUID as default, UUID, UUID as uuid, ISSUER_CATEGORIES };
//# sourceMappingURL=index.d.mts.map
2 changes: 1 addition & 1 deletion types/index.d.mts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading