diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 1299cc0..c894677 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -48,6 +48,9 @@ jobs: - name: ๐Ÿงช Test build artifacts run: npm test -- test/build-artifacts.spec.ts + - name: ๐Ÿ“ฆ Check package exports + run: npm run check:pkg + - name: ๐Ÿ“Š Upload coverage reports if: matrix.node-version == '24.x' # only upload coverage for one Node version uses: actions/upload-artifact@v4.6.2 diff --git a/package-lock.json b/package-lock.json index e6ed727..27b262c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "@biomejs/biome": "2.6.3", "@types/node": "^24.19.2", "@vitest/coverage-v8": "^5.0.5", + "publint": "^0.3.25", "shelljs": "^0.10.0", "tinybench": "^6.2.0", "tsdown": "~0.23.4", @@ -811,6 +812,22 @@ "url": "https://github.com/sponsors/oxc-project" } }, + "node_modules/@publint/pack": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@publint/pack/-/pack-0.1.7.tgz", + "integrity": "sha512-4EDEmvxWtgsCnnVeBvtFIFZtUhPPt1+bA9JrSwU4Sa//6oKtzCSlGGXYJr44OD9aGISymbieJ4mCKHUygUDU+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyexec": "^1.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://bjornlu.com/sponsor" + } + }, "node_modules/@quansync/fs": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@quansync/fs/-/fs-1.1.0.tgz", @@ -2510,6 +2527,16 @@ "node": ">=6" } }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/nanoid": { "version": "3.3.20", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz", @@ -2557,6 +2584,13 @@ "node": ">=12.20.0" } }, + "node_modules/package-manager-detector": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.9.0.tgz", + "integrity": "sha512-zAMfbta9nPA8AKkA4WdmNAT8R8s6Dk0/xwPsqNnRidMFcLo1YkLuPDTgs2f64XdzS8vbLNnoJ+uUIkgbz7oRHA==", + "dev": true, + "license": "MIT" + }, "node_modules/path-key": { "version": "3.1.1", "dev": true, @@ -2570,8 +2604,7 @@ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.2", @@ -2616,6 +2649,28 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/publint": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/publint/-/publint-0.3.25.tgz", + "integrity": "sha512-WMMbn/d7JqRlfXQL/JUI4n5skC8cJ5WVr8/wT5mmiYWkUdENkZr1I5rgs2+dQPVRgoJd+JRYtB46MTsuDylw9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@publint/pack": "^0.1.7", + "package-manager-detector": "^1.8.0", + "picocolors": "^1.1.1", + "sade": "^1.8.1" + }, + "bin": { + "publint": "src/cli.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://bjornlu.com/sponsor" + } + }, "node_modules/quansync": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/quansync/-/quansync-1.0.0.tgz", @@ -2779,6 +2834,19 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "dev": true, @@ -2849,6 +2917,16 @@ "node": ">=20.0.0" } }, + "node_modules/tinyexec": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz", + "integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/tinyglobby": { "version": "0.2.17", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", @@ -3020,16 +3098,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/tsdown/node_modules/tinyexec": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz", - "integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/tsx": { "version": "4.23.15", "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.15.tgz", @@ -3317,16 +3385,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/vitest/node_modules/tinyexec": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz", - "integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/which": { "version": "2.0.2", "dev": true, diff --git a/package.json b/package.json index d42b873..90e47d8 100644 --- a/package.json +++ b/package.json @@ -20,28 +20,55 @@ "sideEffects": false, "exports": { ".": { - "types": "./dist/index.d.ts", "browser": { - "import": "./dist/index.esm.js", - "require": "./dist/index.umd.js", + "import": { + "types": "./dist/index.d.ts", + "default": "./dist/index.esm.js" + }, + "require": { + "types": "./dist/index.d.cts", + "default": "./dist/index.umd.js" + }, "default": "./dist/index.umd.js" }, "node": { - "import": "./dist/index.mjs", - "require": "./dist/index.cjs" + "import": { + "types": "./dist/index.d.ts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" + } }, - "import": "./dist/index.mjs", - "require": "./dist/index.cjs" + "import": { + "types": "./dist/index.d.ts", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" + } }, "./stream": { - "types": "./dist/stream.d.ts", - "import": "./dist/stream.mjs", - "require": "./dist/stream.cjs" + "import": { + "types": "./dist/stream.d.ts", + "default": "./dist/stream.mjs" + }, + "require": { + "types": "./dist/stream.d.cts", + "default": "./dist/stream.cjs" + } }, "./cli": { - "types": "./dist/cli.d.ts", - "import": "./dist/cli.mjs", - "require": "./dist/cli.cjs" + "import": { + "types": "./dist/cli.d.ts", + "default": "./dist/cli.mjs" + }, + "require": { + "types": "./dist/cli.d.cts", + "default": "./dist/cli.cjs" + } } }, "files": [ @@ -70,6 +97,13 @@ "engines": { "node": ">=20.19.0" }, + "devEngines": { + "runtime": { + "name": "node", + "version": ">=22.18.0", + "onFail": "warn" + } + }, "scripts": { "lint": "biome check", "lint:fix": "biome check --write", @@ -87,13 +121,14 @@ "coverage": "vitest run --coverage", "deploy-docs": "node scripts/gh-pages-publish.cjs", "typecheck": "tsc --noEmit", - "prepare": "node scripts/install-hooks.js", - "hooks:install": "node scripts/install-hooks.js" + "hooks:install": "node scripts/install-hooks.js", + "check:pkg": "publint" }, "devDependencies": { "@biomejs/biome": "2.6.3", "@types/node": "^24.19.2", "@vitest/coverage-v8": "^5.0.5", + "publint": "^0.3.25", "shelljs": "^0.10.0", "tinybench": "^6.2.0", "tsdown": "~0.23.4", diff --git a/test/build-artifacts.spec.ts b/test/build-artifacts.spec.ts index 17781d3..83a446f 100644 --- a/test/build-artifacts.spec.ts +++ b/test/build-artifacts.spec.ts @@ -230,32 +230,29 @@ describe('Build Artifacts', () => { expect(pkg.exports).toBeDefined(); expect(pkg.exports['.']).toBeDefined(); - expect(pkg.exports['.'].types).toBe('./dist/index.d.ts'); - expect(pkg.exports['.'].import).toBe('./dist/index.mjs'); - expect(pkg.exports['.'].require).toBe('./dist/index.cjs'); + expect(pkg.exports['.'].import).toEqual({ types: './dist/index.d.ts', default: './dist/index.mjs' }); + expect(pkg.exports['.'].require).toEqual({ types: './dist/index.d.cts', default: './dist/index.cjs' }); // Check browser exports expect(pkg.exports['.'].browser).toBeDefined(); - expect(pkg.exports['.'].browser.import).toBe('./dist/index.esm.js'); - expect(pkg.exports['.'].browser.require).toBe('./dist/index.umd.js'); + expect(pkg.exports['.'].browser.import).toEqual({ types: './dist/index.d.ts', default: './dist/index.esm.js' }); + expect(pkg.exports['.'].browser.require).toEqual({ types: './dist/index.d.cts', default: './dist/index.umd.js' }); expect(pkg.exports['.'].browser.default).toBe('./dist/index.umd.js'); // Check Node.js specific exports expect(pkg.exports['.'].node).toBeDefined(); - expect(pkg.exports['.'].node.import).toBe('./dist/index.mjs'); - expect(pkg.exports['.'].node.require).toBe('./dist/index.cjs'); + expect(pkg.exports['.'].node.import).toEqual({ types: './dist/index.d.ts', default: './dist/index.mjs' }); + expect(pkg.exports['.'].node.require).toEqual({ types: './dist/index.d.cts', default: './dist/index.cjs' }); // Check stream export expect(pkg.exports['./stream']).toBeDefined(); - expect(pkg.exports['./stream'].types).toBe('./dist/stream.d.ts'); - expect(pkg.exports['./stream'].import).toBe('./dist/stream.mjs'); - expect(pkg.exports['./stream'].require).toBe('./dist/stream.cjs'); + expect(pkg.exports['./stream'].import).toEqual({ types: './dist/stream.d.ts', default: './dist/stream.mjs' }); + expect(pkg.exports['./stream'].require).toEqual({ types: './dist/stream.d.cts', default: './dist/stream.cjs' }); // Check CLI export expect(pkg.exports['./cli']).toBeDefined(); - expect(pkg.exports['./cli'].types).toBe('./dist/cli.d.ts'); - expect(pkg.exports['./cli'].import).toBe('./dist/cli.mjs'); - expect(pkg.exports['./cli'].require).toBe('./dist/cli.cjs'); + expect(pkg.exports['./cli'].import).toEqual({ types: './dist/cli.d.ts', default: './dist/cli.mjs' }); + expect(pkg.exports['./cli'].require).toEqual({ types: './dist/cli.d.cts', default: './dist/cli.cjs' }); }); }); }); diff --git a/tsdown.config.ts b/tsdown.config.ts index ca65628..5105dee 100644 --- a/tsdown.config.ts +++ b/tsdown.config.ts @@ -1,7 +1,7 @@ import { defineConfig, type UserConfig } from 'tsdown'; const baseConfig: UserConfig = { - dts: { sourcemap: false }, + dts: { sourcemap: true }, sourcemap: true, clean: false, treeshake: true,