diff --git a/README.md b/README.md index 950a0b7..958cf25 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,9 @@ Relative paths resolve from the file that calls wisp, not from wisp's own locati ### Latest: v1.0.7 (October 2026) -- **`require()` works in bundles and fails clearly on older Node.js** — `index.cjs` now loads the ESM entry with a plain `require("./index.mjs")` instead of `createRequire(__filename)`, so `require("@cldmv/wisp")` survives esbuild and webpack bundling. On Node.js versions without synchronous `require(esm)`, where `require()` never worked, it now throws an `ERR_REQUIRE_ESM` error that names the supported versions (`^20.19.0` or `>=22.12.0`) and points to `import()`. The ESM entry and the library code are unchanged (#30). -- **A failed validation throws instead of loading the fallback** — `fallback` is now used only when the primary file cannot be read or parsed; a `validate` rejection is reported as an error, and a fallback that also fails no longer loops forever ([#35](https://github.com/CLDMV/wisp/pull/35)). The package is also relicensed under Apache-2.0 ([#34](https://github.com/CLDMV/wisp/pull/34)). +- **`require()` works in bundles and fails clearly on older Node.js** — `index.cjs` now loads the ESM entry with a plain `require("./index.mjs")` instead of `createRequire(__filename)`, so `require("@cldmv/wisp")` survives esbuild and webpack bundling. On Node.js versions without synchronous `require(esm)`, where `require()` never worked, it now throws an `ERR_REQUIRE_ESM` error that names the supported versions (`^20.19.0` or `>=22.12.0`) and points to `import()` ([#30](https://github.com/CLDMV/wisp/pull/30)). +- **A failed validation throws instead of loading the fallback** — `fallback` is now used only when the primary file cannot be read or parsed; a `validate` rejection is reported as an error, and a fallback that also fails no longer loops forever ([#35](https://github.com/CLDMV/wisp/pull/35)). On the `import()` paths, a `validate` rejection now throws the validation error once instead of `Unsupported type`, and `reviver` / `validate` on a module without a default export receive a plain-object copy of its exports instead of failing ([#41](https://github.com/CLDMV/wisp/pull/41)). The package is also relicensed under Apache-2.0 ([#34](https://github.com/CLDMV/wisp/pull/34)). +- **Built package in `dist/`** — the published package is now bundled with tsup into `dist/index.mjs`, with `dist/index.cjs` as a thin `require()` wrapper, and ships only `dist/`, `types/`, `README.md` and `LICENSE`. `import` and `require()` of `@cldmv/wisp` work exactly as before; code that loaded the old root `index.mjs` / `index.cjs` or `src/` files by path must use the package specifier ([#40](https://github.com/CLDMV/wisp/pull/40)). The test suite now runs on `@cldmv/vitest-runner` with 100% coverage ([#37](https://github.com/CLDMV/wisp/pull/37)). - [View full v1.0.7 Changelog](https://github.com/CLDMV/wisp/blob/master/docs/changelog/v1/v1.0.7.md) ### Recent Releases diff --git a/docs/changelog/v1/v1.0.7.md b/docs/changelog/v1/v1.0.7.md index 711863e..0681db5 100644 --- a/docs/changelog/v1/v1.0.7.md +++ b/docs/changelog/v1/v1.0.7.md @@ -10,6 +10,10 @@ Fixes the CommonJS entry point so `require("@cldmv/wisp")` works inside esbuild and webpack bundles, and makes `require()` fail with a clear message on Node.js versions that cannot load ES modules synchronously. It also stops a failed `validate` check from silently loading the `fallback` file, fixes an endless loop when the fallback itself could not be loaded, and relicenses the package under Apache-2.0. +Two more `wisp()` fixes for modules loaded through `import()`: a `reviver` or `validate` on a module without a default export now works instead of ending in "Unsupported type", and a `validate` rejection on any `import()` path throws the validation error once. + +The published package is now built: `src/` is bundled with tsup into `dist/index.mjs`, `dist/index.cjs` is a thin `require()` wrapper around it, and the tarball ships only `dist/`, `types/`, `README.md` and `LICENSE`. The `@cldmv/wisp` entry points and their exports are unchanged; only code that reached into the package's files directly is affected (see Upgrade notes). The test suite moved from mocha to `@cldmv/vitest-runner` with 100% coverage, and the standard lint/format setup was added. + --- ## 🐛 Bug Fixes @@ -20,7 +24,7 @@ Fixes the CommonJS entry point so `require("@cldmv/wisp")` works inside esbuild `index.cjs` has always depended on Node.js's synchronous `require(esm)`, so `require("@cldmv/wisp")` never worked on Node.js versions without it. Those versions used to fail with a bare loader error; `index.cjs` now checks `process.features.require_module` first and throws an `ERR_REQUIRE_ESM` error that names the supported versions (`^20.19.0` or `>=22.12.0`) and points to `import()` instead. `import("@cldmv/wisp")` keeps working on every Node.js version the package supports. -The exports are the same as before: `require("@cldmv/wisp")` returns `wisp`, with `.default`, `.wisp` and `.wispSync` attached. +The exports are the same as before: `require("@cldmv/wisp")` returns `wisp`, with `.default`, `.wisp` and `.wispSync` attached. The CommonJS entry now ships as `dist/index.cjs` (see Packaging below). ### A failed validation throws instead of loading the fallback ([#35](https://github.com/CLDMV/wisp/pull/35), fixes [#33](https://github.com/CLDMV/wisp/issues/33)) @@ -28,6 +32,14 @@ The exports are the same as before: `require("@cldmv/wisp")` returns `wisp`, wit The same change fixes a second bug: the fallback was loaded with the same options, `fallback` included, so a fallback that also failed to load or validate retried itself forever. `wispSync` ended with `Maximum call stack size exceeded` and `wisp` never settled. The fallback is now loaded without a further fallback and throws if it fails. +### `reviver` and `validate` work on a module without a default export ([#41](https://github.com/CLDMV/wisp/pull/41), fixes [#38](https://github.com/CLDMV/wisp/issues/38)) + +When `wisp()` loaded a module through `import()` and was given a `reviver` or `validate`, it copied the module's value with `structuredClone` before handing it over. For a module with no default export that value is the module namespace object, which `structuredClone` cannot copy. The resulting `DataCloneError` was swallowed as a failed import strategy, and the call ended in the generic `Unsupported type '' or failed to load module at ` error. `wisp()` now copies the namespace's exports to a plain object first, so `reviver` and `validate` receive a plain-object copy of the module's exports. Without either option the namespace itself is still returned, as before. `wispSync` only parses JSON files and is not affected. + +### A `validate` rejection on an `import()` path throws the validation error once ([#41](https://github.com/CLDMV/wisp/pull/41), fixes [#39](https://github.com/CLDMV/wisp/issues/39)) + +`validate` ran inside each `import()` strategy's `try` block, so a rejection counted as that strategy failing: the next strategy imported the module again and validated it again. For `type: "json"` the call ended on the file-system path and threw the validation error there, after calling `validate` up to three times; for any other `type` it ended in `Unsupported type`, hiding the validation error entirely. `validate` now runs once, after the module has loaded, and a rejection throws the same error as the file-system path, `Failed to load JSON file at : @cldmv/wisp: `, with the original error as `cause`. The same release refactors the strategy loop to clear a CodeQL `js/unused-loop-variable` finding; behaviour is unchanged by that part. + --- ## 📄 License @@ -36,10 +48,22 @@ The package is relicensed from MIT to Apache-2.0 ([#34](https://github.com/CLDMV --- +## 📦 Packaging + +- **Built `dist/` output** ([#40](https://github.com/CLDMV/wisp/pull/40)) — tsup bundles `src/index.mjs` into a minified `dist/index.mjs` (target Node.js 16, function names kept). `dist/index.cjs` is not a second bundle: it is the CommonJS wrapper from [#30](https://github.com/CLDMV/wisp/pull/30), copied in verbatim, and loads `./index.mjs` through `require(esm)`. The root `index.mjs` / `index.cjs` files are gone (the sources now live at `src/index.mjs` and `src/cjs-shim.cjs`). +- **`files`** now lists only `dist/` (without sourcemaps), `types/`, `README.md` and `LICENSE`. `src/` and the root entry files are no longer published. +- **`exports`** — `import` resolves to `dist/index.mjs`, `require` to `dist/index.cjs`, and a `types` condition plus top-level `main`, `module` and `types` fields point at the built files and at `types/index.d.mts`. A `wisp-dev` condition serves `src/` directly for local development. +- Caller-relative path resolution is checked against the built `dist/` output, for both `import` and `require()`, by the new `tests/bundle/caller-resolution.test.mjs`. + +--- + ## 🔧 CI & tooling +- **Test suite on `@cldmv/vitest-runner`** ([#37](https://github.com/CLDMV/wisp/pull/37)) — the mocha + chai suite under `test/` moved to vitest under `tests/` (`*.test.vitest.mjs`), with new tests for the import strategies and the caller resolver. Coverage is 100% and the coverage badge and PR coverage comment are enabled in CI. The legacy `assert`-strategy tests run on Node.js 24+, because Node.js 20 and 22 cache a failed `import()` of the same URL; older versions check the unsupported-type error instead. +- **Standard lint/format setup** ([#36](https://github.com/CLDMV/wisp/pull/36)) — prettier and ESLint configs in `.configs/`, a `.prettierignore`, `lint` / `lint:fix` / `format` / `format:check` scripts, and a check-only pre-commit hook installed by `prepare`. +- **Build scripts** ([#40](https://github.com/CLDMV/wisp/pull/40)) — `build` runs tsup, `types:build` / `types:check` replace `build:types`, `prepack` builds types and `dist/` before packing, and `build:ci` runs lint, format check, types, build and tests. CI, publish and release workflows build `dist/` alongside the types, and the bundle-size check measures `dist/index.mjs` and `dist/index.cjs`. - New tests for `wisp` and `wispSync`: a primary that fails validation throws without using the fallback, a primary that is invalid JSON uses the fallback, and a fallback that fails validation throws. -- New `test/entry.test.cjs` (run by `npm test` through `npm run test:cjs`) checks that `require()` returns the same functions as `import`, and that the version check fires when `require(esm)` is unavailable. +- New `tests/cjs/entry.test.cjs` (run by `npm test` through `npm run test:cjs`, which now builds `dist/` first) checks that `require()` returns the same functions as `import`, and that the version check fires when `require(esm)` is unavailable. --- @@ -52,7 +76,12 @@ The package is relicensed from MIT to Apache-2.0 ([#34](https://github.com/CLDMV ## 🔧 Dependencies -_No dependency updates_ +No runtime dependencies were added; the package still has none. Development dependencies only: + +- Added `@cldmv/vitest-runner`, `vitest` and `@vitest/coverage-v8`; removed `mocha` and `chai` ([#37](https://github.com/CLDMV/wisp/pull/37)). +- Added `tsup` ([#40](https://github.com/CLDMV/wisp/pull/40)). +- Added prettier, the ESLint plugins and `@cldmv/prettier-plugin-jsonv` / `@cldmv/eslint-plugin-jsonv` for the lint/format setup ([#36](https://github.com/CLDMV/wisp/pull/36)). +- `@cldmv/fix-headers` 2.1.2 → 2.1.4 ([#42](https://github.com/CLDMV/wisp/pull/42)). --- @@ -60,4 +89,7 @@ _No dependency updates_ - **Behaviour change:** if you relied on a failed `validate` check falling back to the `fallback` file, it now throws instead. Catch the error and load the fallback yourself if that is what you want. - On Node.js versions without `require(esm)` (anything outside `^20.19.0` or `>=22.12.0`), `require()` still fails as it always did, now with an explanatory message; use `import()` there. +- **Behaviour change:** a `validate` rejection on a module loaded through `import()` now throws the validation error, called once. Previously a non-JSON `type` reported `Unsupported type` instead, and `validate` could run up to three times for a single load. Code that matched on the `Unsupported type` message for a rejected module should match the validation error instead. +- **Behaviour change:** `wisp()` with a `reviver` or `validate` on a module without a default export now succeeds, and they receive a plain-object copy of the module's exports. Previously that call failed with `Unsupported type`. +- **Packaging change:** the `@cldmv/wisp` entry points (`import` and `require()`) and their exports are unchanged. The package's file layout is not: the root `index.mjs` / `index.cjs` and `src/` are no longer published, and the code ships as `dist/index.mjs` and `dist/index.cjs`. The `exports` map already limited Node.js resolution to `@cldmv/wisp` itself, so subpath imports such as `@cldmv/wisp/src/wisp.mjs` were already rejected; code that bypassed `exports` and loaded files from `node_modules/@cldmv/wisp/` by path (`index.mjs`, `index.cjs`, or anything under `src/`), or a bundler or tool configured to ignore `exports`, has to switch to the `@cldmv/wisp` specifier. - The license is now Apache-2.0.