diff --git a/README.md b/README.md index 26f53b5..a4218cc 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,47 @@ # @cldmv/wisp -A Node.js module for version-agnostic JSON importing, providing transparent support for modern and legacy import syntaxes with automatic fallbacks. +**@cldmv/wisp** loads JSON files in Node.js without caring which JSON import syntax the running Node.js version understands. It tries the modern `import ... with { type: "json" }` form first, falls back to the legacy `assert` form, and finally reads and parses the file itself, so the same call works from Node.js 16 through the current release. -## Overview +Relative paths resolve from the file that calls wisp, not from wisp's own location, so `wispSync("./config.json")` means what it looks like it means from anywhere in your project — including from packages that depend on wisp. -`@cldmv/wisp` allows you to load JSON files in Node.js without worrying about version-specific import syntax. It automatically tries the most modern import methods first and falls back to reliable file system operations. +> _Load JSON the same way on every Node.js version — quietly, like a wisp._ -## Node.js Version Support +[![npm version]][npm_version_url] [![npm downloads]][npm_downloads_url] [![GitHub downloads]][github_downloads_url] [![Last commit]][last_commit_url] [![npm last update]][npm_last_update_url] + +[![Contributors]][contributors_url] [![Sponsor shinrai]][sponsor_url] + +--- + +## ✨ What's New + +### 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)). +- [View full v1.0.7 Changelog](https://github.com/CLDMV/wisp/blob/master/docs/changelog/v1/v1.0.7.md) + +### Recent Releases + +- **v1.0.6** (October 2026) — Uniform file headers via `@cldmv/fix-headers`, a CI fix and a development-dependency security update; no runtime change ([Changelog](https://github.com/CLDMV/wisp/blob/master/docs/changelog/v1/v1.0.6.md)) +- **v1.0.5** (October 2026) — First npm release since v1.0.1; TypeScript 6, chai 6 and `@types/node` 26 for development, v4 workflow syncs; no runtime change ([Changelog](https://github.com/CLDMV/wisp/blob/master/docs/changelog/v1/v1.0.5.md)) +- **v1.0.4** (September 2026) — Thrown errors now carry the original error as `cause`; ESLint wired up; mocha 12 ([Changelog](https://github.com/CLDMV/wisp/blob/master/docs/changelog/v1/v1.0.4.md)) +- **v1.0.3** (August 2026) — Development-dependency security update (`picomatch`); no runtime change ([Changelog](https://github.com/CLDMV/wisp/blob/master/docs/changelog/v1/v1.0.3.md)) + +📚 **For complete version history and detailed release notes, see the [docs/changelog/](https://github.com/CLDMV/wisp/tree/master/docs/changelog/) folder.** + +--- + +## 🚀 Key Features + +- **Version-agnostic JSON imports** — `with`, then `assert`, then a file-system read; whichever the running Node.js supports. +- **Caller-aware paths** — relative paths resolve from the calling file; `base` overrides it. +- **Async and sync** — `wisp()` returns a promise, `wispSync()` returns the value directly. +- **Validation and revivers** — `validate` rejects bad data, `reviver` is passed to `JSON.parse`. +- **Fallback files** — `fallback` names a second file to try when the first cannot be loaded. +- **ESM and CommonJS** — `import` and `require()` entry points, with TypeScript declarations included. +- **Zero runtime dependencies.** + +### Node.js Version Support | Node Version | `import ... with { type: 'json' }` | `import ... assert { type: 'json' }` | Fallback | | ------------ | ---------------------------------- | ------------------------------------ | -------- | @@ -16,15 +51,26 @@ A Node.js module for version-agnostic JSON importing, providing transparent supp | ≥ 16.14 | ❌ | ✅ | ✅ | | < 16.14 | ❌ | ❌ | ✅ | -## Installation +--- + +## 📦 Installation + +### Requirements + +- **Node.js 16 or higher** for `import` (ESM). +- **`require()` needs Node.js ^20.19.0 or >=22.12.0** (synchronous `require(esm)`). On older Node.js versions, load the package with `import()` instead. + +### Install ```bash npm install @cldmv/wisp ``` -## Usage +--- + +## 🚀 Quick Start -### ESM (Modern) +### ESM ```javascript import { wisp, wispSync } from "@cldmv/wisp"; @@ -36,7 +82,7 @@ const config = await wisp("./config.json"); const data = wispSync("./data.json"); ``` -### CJS (CommonJS) +### CommonJS ```javascript const { wisp, wispSync } = require("@cldmv/wisp"); @@ -50,7 +96,9 @@ wisp("./config.json").then((config) => { const data = wispSync("./data.json"); ``` -## API Reference +--- + +## 📖 API Reference ### `wisp(input, options?)` @@ -63,6 +111,8 @@ Asynchronously loads JSON from a file. - `base` (string | URL, optional): Base URL for resolving relative paths. Defaults to the caller's file URL. - `validate` (function, optional): Validation function called with the parsed JSON. Throws if validation fails. - `reviver` (function, optional): Reviver function passed to `JSON.parse`. + - `type` (string, optional): Import attribute type used for the `import()` attempts. Defaults to `"json"`; the file-system fallback only runs for `"json"`. + - `fallback` (string | URL, optional): A second file to load when `input` cannot be read or parsed. A `validate` failure on `input` throws rather than falling back. #### Returns @@ -88,11 +138,11 @@ Synchronously loads JSON from a file. #### Parameters - `input` (string | URL): Path or URL to the JSON file -- `options` (object, optional): Same as `wisp` options. +- `options` (object, optional): Same as `wisp` options, except `type` (the file is always read and parsed as JSON). #### Returns -`Promise<*>`: The parsed JSON value. +`*`: The parsed JSON value. #### Example @@ -106,15 +156,21 @@ const data = wispSync("./config.json", { }); ``` -## Options +--- -| Option | Type | Description | -| ---------- | ---------- | ------------------------------------------------------------------------ | -| `base` | string/URL | Base URL for relative path resolution. Defaults to caller's file URL. | -| `validate` | function | Validation function. Receives parsed JSON, should throw on invalid data. | -| `reviver` | function | JSON.parse reviver function for custom parsing. | +## ⚙️ Options -## Path Resolution +| Option | Type | Description | +| ---------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| `base` | string/URL | Base URL for relative path resolution. Defaults to caller's file URL. | +| `validate` | function | Validation function. Receives parsed JSON, should throw on invalid data. | +| `reviver` | function | JSON.parse reviver function for custom parsing. | +| `type` | string | Import attribute type for `wisp()`'s `import()` attempts. Defaults to `"json"`. | +| `fallback` | string/URL | File to load instead when `input` cannot be read or parsed (missing, unreadable, or not valid JSON). A `validate` failure throws instead. | + +--- + +## 🧭 Path Resolution `@cldmv/wisp` uses caller-aware path resolution: @@ -122,7 +178,9 @@ const data = wispSync("./config.json", { - Absolute paths and URLs are used as-is - The `base` option overrides the default caller-based resolution -## Fallback Order +--- + +## 🔁 Fallback Order The module attempts to load JSON in this order: @@ -130,11 +188,13 @@ The module attempts to load JSON in this order: 2. `import(url, { assert: { type: 'json' } })` (Node ≥ 16.14) 3. `fs.readFile` / `fs.readFileSync` (all supported Node versions) -This ensures maximum compatibility across Node.js versions. +This ensures maximum compatibility across Node.js versions. `wispSync` always uses `fs.readFileSync`. -## Error Handling +--- -Validation errors are prefixed with `@cldmv/wisp:` for easy identification: +## 🛡 Error Handling + +Errors thrown by wisp are prefixed with `@cldmv/wisp:` for easy identification, and carry the underlying error as `error.cause`. A validation failure is reported as part of the load error: ```javascript try { @@ -144,10 +204,69 @@ try { } }); } catch (error) { - console.log(error.message); // "@cldmv/wisp: Custom validation failed" + console.log(error.message); // "@cldmv/wisp: Failed to load JSON file at file:///…/invalid.json: @cldmv/wisp: Custom validation failed" } ``` -## License +--- + +## 📚 Documentation + +- **[Changelog](https://github.com/CLDMV/wisp/tree/master/docs/changelog/)** — release notes for every version +- **[Bug reports and fixes](https://github.com/CLDMV/wisp/blob/master/BUGS.md)** — write-ups of notable bugs and how they were fixed + +[![CodeFactor]][codefactor_url] [![OpenSSF Scorecard]][ossf_scorecard_url] [![npms.io score]][npms_url] [![npm unpacked size]][npm_size_url] [![Repo size]][repo_size_url] + +--- + +## 🤝 Contributing + +Contributions are welcome — open an [issue](https://github.com/CLDMV/wisp/issues) or a pull request. + +[![Contributors]][contributors_url] [![Sponsor shinrai]][sponsor_url] + +--- + +## 🔗 Links + +- **npm**: [@cldmv/wisp](https://www.npmjs.com/package/@cldmv/wisp) +- **GitHub**: [CLDMV/wisp](https://github.com/CLDMV/wisp) +- **Issues**: [GitHub Issues](https://github.com/CLDMV/wisp/issues) +- **Changelog**: [docs/changelog/](https://github.com/CLDMV/wisp/tree/master/docs/changelog/) + +--- + +## 📄 License + +[![GitHub license]][github_license_url] [![npm license]][npm_license_url] Apache-2.0 © CLDMV Inc. See [LICENSE](https://github.com/CLDMV/wisp/blob/master/LICENSE) for the full text. + +[npm version]: https://img.shields.io/npm/v/%40cldmv%2Fwisp.svg?style=for-the-badge&logo=npm&logoColor=white&labelColor=CB3837 +[npm_version_url]: https://www.npmjs.com/package/@cldmv/wisp +[last commit]: https://img.shields.io/github/last-commit/CLDMV/wisp?style=for-the-badge&logo=github&logoColor=white&labelColor=181717 +[last_commit_url]: https://github.com/CLDMV/wisp/commits +[npm last update]: https://img.shields.io/npm/last-update/%40cldmv%2Fwisp?style=for-the-badge&logo=npm&logoColor=white&labelColor=CB3837 +[npm_last_update_url]: https://www.npmjs.com/package/@cldmv/wisp +[codefactor]: https://img.shields.io/codefactor/grade/github/CLDMV/wisp?style=for-the-badge&logo=codefactor&logoColor=white&labelColor=F44A6A +[codefactor_url]: https://www.codefactor.io/repository/github/cldmv/wisp +[openssf scorecard]: https://img.shields.io/ossf-scorecard/github.com/CLDMV/wisp?style=for-the-badge&label=OpenSSF%20Scorecard +[ossf_scorecard_url]: https://scorecard.dev/viewer/?uri=github.com/CLDMV/wisp +[npms.io score]: https://img.shields.io/npms-io/final-score/%40cldmv%2Fwisp?style=for-the-badge&logo=npms&logoColor=white&labelColor=0B5D57 +[npms_url]: https://npms.io/search?q=%40cldmv%2Fwisp +[npm downloads]: https://img.shields.io/npm/dm/%40cldmv%2Fwisp.svg?style=for-the-badge&logo=npm&logoColor=white&labelColor=CB3837 +[npm_downloads_url]: https://www.npmjs.com/package/@cldmv/wisp +[github downloads]: https://img.shields.io/github/downloads/CLDMV/wisp/total?style=for-the-badge&logo=github&logoColor=white&labelColor=181717 +[github_downloads_url]: https://github.com/CLDMV/wisp/releases +[npm unpacked size]: https://img.shields.io/npm/unpacked-size/%40cldmv%2Fwisp.svg?style=for-the-badge&logo=npm&logoColor=white&labelColor=CB3837 +[npm_size_url]: https://www.npmjs.com/package/@cldmv/wisp +[repo size]: https://img.shields.io/github/repo-size/CLDMV/wisp?style=for-the-badge&logo=github&logoColor=white&labelColor=181717 +[repo_size_url]: https://github.com/CLDMV/wisp +[github license]: https://img.shields.io/github/license/CLDMV/wisp.svg?style=for-the-badge&logo=github&logoColor=white&labelColor=181717 +[github_license_url]: https://github.com/CLDMV/wisp/blob/HEAD/LICENSE +[npm license]: https://img.shields.io/npm/l/%40cldmv%2Fwisp.svg?style=for-the-badge&logo=npm&logoColor=white&labelColor=CB3837 +[npm_license_url]: https://www.npmjs.com/package/@cldmv/wisp +[contributors]: https://img.shields.io/github/contributors/CLDMV/wisp.svg?style=for-the-badge&logo=github&logoColor=white&labelColor=181717 +[contributors_url]: https://github.com/CLDMV/wisp/graphs/contributors +[sponsor shinrai]: https://img.shields.io/github/sponsors/shinrai?style=for-the-badge&logo=githubsponsors&logoColor=white&labelColor=EA4AAA&label=Sponsor +[sponsor_url]: https://github.com/sponsors/shinrai diff --git a/docs/changelog/v1/v1.0.0.md b/docs/changelog/v1/v1.0.0.md new file mode 100644 index 0000000..8e00066 --- /dev/null +++ b/docs/changelog/v1/v1.0.0.md @@ -0,0 +1,34 @@ +# Wisp v1.0.0 Changelog + +**Release Date**: November 2025 +**Release Type**: Major (initial release) + +--- + +## Overview + +First public release of `@cldmv/wisp`, a small library for loading JSON files in Node.js without caring which JSON import syntax the running Node.js version supports. + +--- + +## ✨ Features + +### Version-agnostic JSON loading + +- `wisp(input, options)` loads a JSON file asynchronously. It tries `import(url, { with: { type: "json" } })` first, then the legacy `import(url, { assert: { type: "json" } })`, and finally reads and parses the file with `fs.readFile`. +- `wispSync(input, options)` loads a JSON file synchronously with `fs.readFileSync`. +- `input` accepts a relative path, an absolute path, a `file://` string or a `URL`. Relative paths resolve from the file that called `wisp` / `wispSync`, unless `options.base` is given. +- Options: `base` (base path or URL for relative inputs), `validate` (called with the parsed value; a throw rejects the load), `reviver` (passed to `JSON.parse`), `type` (import attribute type, `"json"` by default, async only) and `fallback` (a second path or URL to try when the first one cannot be loaded). +- Values returned with a `reviver` or `validate` are deep-cloned (with `structuredClone` when available), so the module cache is never mutated. + +### Packaging + +- Dual entry points: `index.mjs` for `import` and `index.cjs` for `require()`, with `wisp` as the default export. +- Declared `engines.node` of `>=16.14`. + +--- + +## Upgrade notes + +- Initial release; nothing to upgrade from. +- Relative-path resolution from the caller's location does not work correctly in this version when the package is installed as a dependency (paths resolve from inside the package). Upgrade to [v1.0.1](./v1.0.1.md). diff --git a/docs/changelog/v1/v1.0.1.md b/docs/changelog/v1/v1.0.1.md new file mode 100644 index 0000000..6cf9fc2 --- /dev/null +++ b/docs/changelog/v1/v1.0.1.md @@ -0,0 +1,31 @@ +# Wisp v1.0.1 Changelog + +**Release Date**: November 2025 +**Release Type**: Patch + +--- + +## Overview + +Fixes caller path resolution, which made relative paths unusable from any package that depended on `@cldmv/wisp`, and starts shipping the type declarations. + +--- + +## 🐛 Bug Fixes + +### Relative paths resolve from the caller again + +In v1.0.0, `wispSync("../examples/data.json")` called from a consuming module resolved the path relative to `node_modules/@cldmv/wisp/src/wisp.mjs` instead of the caller, and failed with `ENOENT`. The resolver in `src/lib/resolve-from-caller.mjs` was rewritten: it finds the package root by walking up to the nearest `package.json`, walks the call stack, and picks the first frame after the stack leaves the package's `src/` or `dist/` directory. It no longer depends on hard-coded file names or on an `index.mjs` frame being present (Node.js does not create one for `export *` re-exports). The bug and the fix are described in [BUGS.md](https://github.com/CLDMV/wisp/blob/master/BUGS.md). + +--- + +## 📦 Packaging + +- The `types/` folder (generated `.d.mts` declarations) is now included in the published package. +- `engines.node` lowered from `>=16.14` to `>=16.0.0`; on Node.js before 16.14 the file-system fallback is used. + +--- + +## Upgrade notes + +- No API changes — drop-in for v1.0.0. Code that worked around the path bug by passing an absolute path or `base` keeps working. diff --git a/docs/changelog/v1/v1.0.2.md b/docs/changelog/v1/v1.0.2.md new file mode 100644 index 0000000..805f2d2 --- /dev/null +++ b/docs/changelog/v1/v1.0.2.md @@ -0,0 +1,25 @@ +# Wisp v1.0.2 Changelog + +**Release Date**: July 2026 +**Release Type**: Patch + +--- + +## Overview + +Moves the repository onto the CLDMV v4 staging-branch release flow. No runtime code changed. + +This version was tagged on GitHub but was not published to npm; npm went from v1.0.1 to v1.0.5. + +--- + +## 🔧 CI & tooling + +- Replaced the old release workflow with the CLDMV v4 workflow set: work merges into `next`, a persistent release PR carries it to `master`, and `hotfixes` handles urgent fixes ([#2](https://github.com/CLDMV/wisp/pull/2)). +- Added CodeQL, OpenSSF Scorecard, dependency review, CLA, labeler, PR-title normalization, stale, branch-retention, tag-health and release-notification workflows. + +--- + +## Upgrade notes + +- No runtime change — drop-in for v1.0.1. diff --git a/docs/changelog/v1/v1.0.3.md b/docs/changelog/v1/v1.0.3.md new file mode 100644 index 0000000..8fe85f1 --- /dev/null +++ b/docs/changelog/v1/v1.0.3.md @@ -0,0 +1,24 @@ +# Wisp v1.0.3 Changelog + +**Release Date**: August 2026 +**Release Type**: Patch + +--- + +## Overview + +A development-dependency security update. No runtime code changed. + +This version was tagged on GitHub but was not published to npm; npm went from v1.0.1 to v1.0.5. + +--- + +## 🔧 Dependencies + +- `picomatch` 2.3.1 → 2.3.2, a development-only transitive dependency of `mocha` ([#3](https://github.com/CLDMV/wisp/pull/3), [#4](https://github.com/CLDMV/wisp/pull/4)). + +--- + +## Upgrade notes + +- No runtime change — drop-in for v1.0.2. diff --git a/docs/changelog/v1/v1.0.4.md b/docs/changelog/v1/v1.0.4.md new file mode 100644 index 0000000..8bda855 --- /dev/null +++ b/docs/changelog/v1/v1.0.4.md @@ -0,0 +1,47 @@ +# Wisp v1.0.4 Changelog + +**Release Date**: September 2026 +**Release Type**: Patch + +--- + +## Overview + +Wires up ESLint for the first time, keeps the original error attached to the errors wisp throws, and moves the test toolchain to mocha 12. + +This version was tagged on GitHub but was not published to npm; npm went from v1.0.1 to v1.0.5. + +--- + +## 🐛 Bug Fixes + +### Errors keep their original cause + +Errors thrown by `wisp` and `wispSync` (validation failures and "Failed to load JSON file" errors) now pass the underlying error as `cause`, so `error.cause` holds the original `ENOENT`, `SyntaxError` or validation error. The messages are unchanged. + +### Lint cleanup + +`wispSync` no longer destructures the `type` option it never used, and an unused variable was removed from the caller resolver. Neither changes behavior. + +--- + +## 🔧 CI & tooling + +- ESLint is now actually configured (`.configs/eslint.config.mjs`); the `lint` script previously pointed at a missing setup. +- Added `.github/dependabot.yml` targeting `next`, the `feature-pr.yml` auto-PR workflow, and moved the release and feature-PR workflows to the current thin-caller templates ([#6](https://github.com/CLDMV/wisp/pull/6)). +- The hotfix redirector now uses the v4 reusable workflow and signs its security cherry-picks ([#8](https://github.com/CLDMV/wisp/pull/8)). +- The CI Node.js matrix now runs from 22.12.0 up to 26 ([#10](https://github.com/CLDMV/wisp/pull/10)). + +--- + +## 🔧 Dependencies + +- `mocha` ^10.2.0 → ^12.0.1, which fixes ESM/CJS interop on Node.js 26 and removes a large set of old transitive dependencies ([#9](https://github.com/CLDMV/wisp/pull/9), [#10](https://github.com/CLDMV/wisp/pull/10)). +- Development dependency group update ([#5](https://github.com/CLDMV/wisp/pull/5)). +- Added `eslint`, `@eslint/js` and `globals` as development dependencies. + +--- + +## Upgrade notes + +- No API changes — drop-in for v1.0.3. Code that inspects `error.cause` now gets the original error instead of `undefined`. diff --git a/docs/changelog/v1/v1.0.5.md b/docs/changelog/v1/v1.0.5.md new file mode 100644 index 0000000..710e50d --- /dev/null +++ b/docs/changelog/v1/v1.0.5.md @@ -0,0 +1,35 @@ +# Wisp v1.0.5 Changelog + +**Release Date**: October 2026 +**Release Type**: Patch + +--- + +## Overview + +Development toolchain updates (TypeScript 6, chai 6, `@types/node` 26) and v4 workflow syncs. The only source change is a type-checker cast; runtime behavior is unchanged. This is the first npm release since v1.0.1, so it also delivers the changes from v1.0.2–v1.0.4 to npm. + +--- + +## 🔧 CI & tooling + +- Synced the v4 workflows with the CLDMV/.github v4.29.2 templates ([#20](https://github.com/CLDMV/wisp/pull/20)), added the bundle-size workflow measuring the published JS files ([#22](https://github.com/CLDMV/wisp/pull/22)), and stopped a skipped PR-run mirror job from satisfying the required PR check ([#24](https://github.com/CLDMV/wisp/pull/24)). +- `tsconfig.json` moved to `module` / `moduleResolution` `NodeNext` for TypeScript 6. The legacy `import(…, { assert })` call in `src/wisp.mjs` gained a type cast so the checker accepts the `assert` key; the call itself is unchanged. + +--- + +## 🔧 Dependencies + +- `typescript` ^5.2.0 → ^6.0.3 ([#21](https://github.com/CLDMV/wisp/pull/21)) +- `chai` 4.5.0 → 6.2.2 ([#15](https://github.com/CLDMV/wisp/pull/15)) +- `@types/node` 20.19.24 → 26.6.3 ([#18](https://github.com/CLDMV/wisp/pull/18), [#23](https://github.com/CLDMV/wisp/pull/23)) +- `eslint` 10.10.0 → 10.11.0 ([#17](https://github.com/CLDMV/wisp/pull/17)) +- `mocha` 12.0.1 → 12.0.2 ([#16](https://github.com/CLDMV/wisp/pull/16)) + +All are development dependencies; the package still has no runtime dependencies. + +--- + +## Upgrade notes + +- No runtime change — drop-in for v1.0.1 (the previous npm release). See [v1.0.4](./v1.0.4.md) for the `error.cause` addition that reaches npm with this version. diff --git a/docs/changelog/v1/v1.0.6.md b/docs/changelog/v1/v1.0.6.md new file mode 100644 index 0000000..0ae98df --- /dev/null +++ b/docs/changelog/v1/v1.0.6.md @@ -0,0 +1,30 @@ +# Wisp v1.0.6 Changelog + +**Release Date**: October 2026 +**Release Type**: Patch + +--- + +## Overview + +Uniform file headers, a CI fix and a development-dependency security update. No runtime code changed; the published `.mjs` / `.cjs` files differ only in their header comments. + +--- + +## 🔧 CI & tooling + +- Adopted the shared CLDMV `@cldmv/fix-headers` config (`npm run fix:headers`) and stamped uniform file headers across the source and workflow files ([#28](https://github.com/CLDMV/wisp/pull/28)). +- The in-repo PR mirror job now runs instead of being skipped ([#29](https://github.com/CLDMV/wisp/pull/29)). + +--- + +## 🔧 Dependencies + +- `brace-expansion` 5.0.9 → 5.0.12 and `serialize-javascript` 7.1.1 → 7.1.2, development-only transitive dependencies ([#26](https://github.com/CLDMV/wisp/pull/26)). +- Added `@cldmv/fix-headers` and `@cldmv/configs` as development dependencies. + +--- + +## Upgrade notes + +- No runtime change — drop-in for v1.0.5. diff --git a/docs/changelog/v1/v1.0.7.md b/docs/changelog/v1/v1.0.7.md new file mode 100644 index 0000000..711863e --- /dev/null +++ b/docs/changelog/v1/v1.0.7.md @@ -0,0 +1,63 @@ +# Wisp v1.0.7 Changelog + +**Release Date**: October 2026 +**Release Type**: Patch +**Branch**: `release/1.0.7` + +--- + +## Overview + +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. + +--- + +## 🐛 Bug Fixes + +### `require()` works in bundles and fails clearly on older Node.js ([#30](https://github.com/CLDMV/wisp/pull/30)) + +`index.cjs` loaded `index.mjs` through `createRequire(__filename)`, which bundlers such as esbuild and webpack cannot follow. It now uses the plain `require("./index.mjs")` that a `.cjs` file already has in scope. + +`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. + +### 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)) + +`wisp` and `wispSync` ran `validate` inside the same `try` block as reading and parsing the file, so when the primary file loaded fine but the caller's `validate` rejected it, wisp fell through to `fallback` as if the file were missing. The data the caller asked to reject was silently replaced by the fallback's. The fallback is now used only when the primary file cannot be read or parsed (missing, unreadable, or not valid JSON). A validation failure throws, in the same format as before: `Failed to load JSON file at : @cldmv/wisp: `. + +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. + +--- + +## 📄 License + +The package is relicensed from MIT to Apache-2.0 ([#34](https://github.com/CLDMV/wisp/pull/34)), and the `LICENSE` file now carries the Apache-2.0 text. + +--- + +## 🔧 CI & tooling + +- 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. + +--- + +## 📚 Documentation + +- **NEW:** [docs/changelog/v1/](https://github.com/CLDMV/wisp/tree/master/docs/changelog/v1) — per-version changelogs for every release from v1.0.0. +- README reorganized; the error-handling example now shows the actual error message, and the `wispSync` return type and the `type` / `fallback` options are documented. + +--- + +## 🔧 Dependencies + +_No dependency updates_ + +--- + +## Upgrade notes + +- **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. +- The license is now Apache-2.0.