metalsmith-markdown-partials 2.3.1 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/.c8rc.json +13 -0
  2. package/.env +1 -0
  3. package/.nvmrc +1 -0
  4. package/.release-it.json +5 -7
  5. package/CHANGELOG.md +68 -1
  6. package/CLAUDE.md +488 -0
  7. package/README.md +25 -4
  8. package/coverage/lcov-report/base.css +224 -0
  9. package/coverage/lcov-report/block-navigation.js +87 -0
  10. package/coverage/lcov-report/favicon.png +0 -0
  11. package/coverage/lcov-report/index.html +116 -0
  12. package/coverage/lcov-report/index.js.html +646 -0
  13. package/coverage/lcov-report/prettify.css +1 -0
  14. package/coverage/lcov-report/prettify.js +2 -0
  15. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  16. package/coverage/lcov-report/sorter.js +196 -0
  17. package/coverage/lcov.info +232 -0
  18. package/coverage/tmp/coverage-44920-1742597774927-0.json +1 -0
  19. package/coverage/tmp/coverage-44921-1742597774583-0.json +1 -0
  20. package/eslint.config.js +51 -0
  21. package/lib/index.cjs +184 -0
  22. package/lib/index.cjs.map +1 -0
  23. package/lib/index.js +123 -81
  24. package/lib/index.js.map +1 -0
  25. package/metalsmith-markdown-partials-2.4.0.tgz +0 -0
  26. package/package.json +27 -14
  27. package/prettier.config.js +9 -0
  28. package/scripts/update-coverage-badge.js +225 -0
  29. package/src/index.js +187 -0
  30. package/test/cjs.test.cjs +55 -0
  31. package/test/index.js +139 -0
  32. package/.eslintcache +0 -1
  33. package/.nyc_output/181518ec-15ce-4116-8650-58fc4a5be71d.json +0 -1
  34. package/.nyc_output/processinfo/181518ec-15ce-4116-8650-58fc4a5be71d.json +0 -1
  35. package/.nyc_output/processinfo/index.json +0 -1
  36. package/.prettierrc.yml +0 -7
  37. package/metalsmith-markdown-partials-2.0.3.tgz +0 -0
  38. package/tests/index.js +0 -42
  39. /package/{tests → test}/fixtures/build/markdown.md +0 -0
  40. /package/{tests → test}/fixtures/expected/final-markdown.md +0 -0
  41. /package/{tests → test}/fixtures/src/markdown.md +0 -0
  42. /package/{tests → test}/fixtures/src/md-partials/test-partial.md +0 -0
package/.c8rc.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "all": true,
3
+ "include": ["src/**/*.js"],
4
+ "exclude": ["node_modules/**", "test/**", "lib/**"],
5
+ "reporter": ["text", "lcov"],
6
+ "report-dir": "./coverage",
7
+ "watermarks": {
8
+ "lines": [80, 95],
9
+ "functions": [80, 95],
10
+ "branches": [80, 95],
11
+ "statements": [80, 95]
12
+ }
13
+ }
package/.env ADDED
@@ -0,0 +1 @@
1
+ GITHUB_TOKEN=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
package/.nvmrc ADDED
@@ -0,0 +1 @@
1
+ 20.12.1
package/.release-it.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "hooks": {
3
3
  "before:init": ["npm run lint", "npm test"],
4
4
  "after:bump": "auto-changelog -p --commit-limit false --ignore-commit-pattern '^((dev|chore|ci):|Release)'",
5
- "after:npm:bump": "npm pack",
5
+ "after:npm:bump": "npm pack && ls *.tgz",
6
6
  "after:release": "echo Successfully released ${name} v${version} to ${repo.repository}."
7
7
  },
8
8
  "git": {
@@ -10,15 +10,13 @@
10
10
  "commitArgs": ["-S"],
11
11
  "tagAnnotation": "Release ${version}",
12
12
  "tagArgs": ["-s"],
13
- "changelog": "auto-changelog -u --commit-limit false --ignore-commit-pattern '^((dev|chore|ci):|Release)' --stdout"
14
- },
15
- "npm": {
16
- "publish": false
13
+ "changelog": "auto-changelog -u --commit-limit false --ignore-commit-pattern '^((dev|chore|ci):|Release)' --stdout -t https://raw.githubusercontent.com/release-it/release-it/master/templates/changelog-compact.hbs"
17
14
  },
15
+ "npm": { "publish": false },
18
16
  "github": {
19
17
  "release": true,
20
- "releaseName": "@metalsmith/~core-plugin~ ${version}",
18
+ "releaseName": "metalsmith-markdown-partials ${version}",
21
19
  "tokenRef": "GITHUB_TOKEN",
22
- "assets": ["metalsmith-~core-plugin~-${version}.tgz"]
20
+ "assets": ["metalsmith-markdown-partials-${version}.tgz"]
23
21
  }
24
22
  }
package/CHANGELOG.md CHANGED
@@ -4,9 +4,76 @@ All notable changes to this project will be documented in this file. Dates are d
4
4
 
5
5
  Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
6
6
 
7
- #### Unreleased
7
+ #### [v2.4.0](https://github.com/wernerglinka/metalsmith-markdown-partials/compare/v2.3.1...v2.4.0)
8
+
9
+ - feat: add dual ESM/CJS module support [`84b61d3`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/84b61d39b4d01f01066ac98719ffa15959254166)
10
+ - updated dependencies [`07a2658`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/07a2658c276ed31c5630e30dd2924b96f2267e44)
11
+ - updated to ms2.6 [`27a9944`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/27a9944d46388f558146eac1dcceb6a198cf1c68)
12
+ - updated packages, ms to 2.5.0 [`c8ab04f`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/c8ab04f15994cbf243fc4e1deaf63515d6b86a34)
13
+ - converted plugin to es6 [`b9a7573`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/b9a75738fa4c381b033016b435058d621289b551)
14
+ - updated dependencies [`dec7b1b`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/dec7b1bdfcebc1dabf4102fc39d75a4ba9e87792)
15
+ - Update coverage badge in README [`c375bdb`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/c375bdbbe899cbac465dddf19f6aaff949bcddb9)
16
+ - Bump package.json to 2.3.1 [`dde7e7a`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/dde7e7a6d65489201412638385774e4c844137bc)
17
+ - Bump package.json to 2.3.0 [`1623204`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/1623204d7b21bda03b774bdce9d480686786d7ac)
18
+ - Bump package.json to 2.2.0 [`297b94d`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/297b94d7055b0168bc08dad2f183ce70e77acf16)
19
+ - Bump package.json to 2.1.1 [`a7bf8a7`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/a7bf8a7fe34a6f2e20ab1bd393b4a1b59b21dd7d)
20
+ - Bump package.json to 2.1.0 [`14d0fc7`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/14d0fc7d31333644c2b2bde7209eb8aa8a592ecf)
21
+
22
+ #### [v2.3.1](https://github.com/wernerglinka/metalsmith-markdown-partials/compare/v2.3.0...v2.3.1)
23
+
24
+ > 11 November 2024
25
+
26
+ - updated dependencies [`7fc7b23`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/7fc7b233da4d6fb3a24584349a144f0a7b88f3db)
27
+ - Bump package.json to 2.3.1 [`eaadf39`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/eaadf391660aa1cc99697c8ecc25d1ea310358ea)
28
+
29
+ #### [v2.3.0](https://github.com/wernerglinka/metalsmith-markdown-partials/compare/v2.2.0...v2.3.0)
30
+
31
+ > 31 January 2024
32
+
33
+ - converted plugin to es6 [`f14e341`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/f14e341185f76bcc1a4954abf2f1d84931623799)
34
+ - Bump package.json to 2.3.0 [`f419a58`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/f419a58a79fbda033756f7127b44597c27b0aa4e)
35
+
36
+ #### [v2.2.0](https://github.com/wernerglinka/metalsmith-markdown-partials/compare/v2.1.1...v2.2.0)
37
+
38
+ > 2 June 2023
39
+
40
+ - updated to ms2.6 [`4f52254`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/4f52254fc276df1def382ae5981e137f260c108a)
41
+ - Bump package.json to 2.2.0 [`2ab528c`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/2ab528cefca34187a6accc11f146ac0ad8ce7686)
42
+
43
+ #### [v2.1.1](https://github.com/wernerglinka/metalsmith-markdown-partials/compare/v2.1.0...v2.1.1)
44
+
45
+ > 18 October 2022
46
+
47
+ - updated dependencies [`a8a94d1`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/a8a94d124e017ace3aebdb0f900d252713f79f12)
48
+ - Bump package.json to 2.1.1 [`e313840`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/e313840d40cf148fe5a63a79f658e85de70c4186)
49
+
50
+ #### [v2.1.0](https://github.com/wernerglinka/metalsmith-markdown-partials/compare/v2.0.2...v2.1.0)
51
+
52
+ > 24 September 2022
53
+
54
+ - updated packages, ms to 2.5.0 [`6bcffce`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/6bcffcee79a9535ad638cac873b1559e102c1d60)
55
+ - Bump package.json to 2.1.0 [`e2e0691`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/e2e0691345181406e50e4041a15f7f192b5ec0d2)
56
+ - Bump package.json to 2.0.4 [`1252474`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/125247419f2dac902c9af2bd0b06c3164bb02c35)
57
+ - Bump package.json to 2.0.3 [`7a9de6a`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/7a9de6a33828819988b14da0f65378fab5aafea9)
58
+
59
+ #### [v2.0.2](https://github.com/wernerglinka/metalsmith-markdown-partials/compare/v2.0.1...v2.0.2)
60
+
61
+ > 3 February 2022
62
+
63
+ - updated readme file [`c3998e9`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/c3998e9d5dc8ccb3cbd0bdd6114c43bdae5f212a)
64
+
65
+ #### [v2.0.1](https://github.com/wernerglinka/metalsmith-markdown-partials/compare/v2.0.0...v2.0.1)
66
+
67
+ > 3 February 2022
68
+
69
+ - refactored plugin code, moved library into content folder [`124154d`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/124154da94875adf561987dd890451d0d5f70183)
70
+
71
+ #### v2.0.0
72
+
73
+ > 1 February 2022
8
74
 
9
75
  - added various config files [`1be389c`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/1be389cb9aedf82405c08c79cdfa866e7d3560d9)
76
+ - updated readme [`d037ed5`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/d037ed5a42f0743f28e37bc07c0a52393ad53028)
10
77
  - updated to ES6 style JS, added license [`37b000f`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/37b000fa3669d928f693ec23a7ccfa629c0e7163)
11
78
  - added test [`d998103`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/d998103cb57b4a35ac9224afb11f4264b56f4abe)
12
79
  - initial commit [`9a91277`](https://github.com/wernerglinka/metalsmith-markdown-partials/commit/9a91277da228d9a718b2c86b012901559c95470d)
package/CLAUDE.md ADDED
@@ -0,0 +1,488 @@
1
+ # Claude Memory File
2
+
3
+ ## Dual Module Implementation for metalsmith-markdown-partials
4
+
5
+ The plugin has been successfully converted to support both ESM and CommonJS module formats. Key changes:
6
+
7
+ 1. **File Structure**
8
+ - Created `/src/index.js` with dual export syntax
9
+ - Using microbundle to generate both ESM (`.js`) and CommonJS (`.cjs`) versions in `/lib/`
10
+ - Test files in both ESM (`test/index.js`) and CommonJS (`test/cjs.test.cjs`) formats
11
+ - Test fixtures in `/test/fixtures/`
12
+
13
+ 2. **Code Improvements**
14
+ - Added Metalsmith's built-in debug support (`const debug = metalsmith.debug ? metalsmith.debug(debugNs) : () => {}`)
15
+ - Added better error handling with try/catch blocks
16
+ - Improved marker detection with null checks to prevent errors
17
+ - Added duplicate detection with Set to track processed partials
18
+ - Better JSDoc documentation throughout the code
19
+
20
+ 3. **Current Test Coverage**
21
+ - Statements: 94.17%
22
+ - Branches: 79.16%
23
+ - Functions: 100%
24
+ - Lines: 94.17%
25
+ - Coverage tracked and displayed in README.md
26
+
27
+ 4. **Configuration Files Added**
28
+ - `.c8rc.json` for coverage configuration
29
+ - `.nvmrc` for Node.js version specification
30
+ - `scripts/update-coverage-badge.js` for updating README coverage badge
31
+
32
+ 5. **GitHub Token Security**
33
+ - Removed `.env` file from git tracking
34
+ - Added to `.gitignore` to prevent accidental commits
35
+ - Added `test/fixtures/build/` to `.gitignore` to exclude test outputs
36
+
37
+ ## Badges for Metalsmith Plugins
38
+
39
+ Common badges to add to README.md:
40
+
41
+ ```markdown
42
+ [![metalsmith:plugin][metalsmith-badge]][metalsmith-url]
43
+ [![npm: version][npm-badge]][npm-url]
44
+ [![license: MIT][license-badge]][license-url]
45
+ [![coverage][coverage-badge]][coverage-url]
46
+ [![ESM/CommonJS][modules-badge]][npm-url]
47
+
48
+ [npm-badge]: https://img.shields.io/npm/v/metalsmith-static-files.svg
49
+ [npm-url]: https://www.npmjs.com/package/metalsmith-static-files
50
+ [metalsmith-badge]: https://img.shields.io/badge/metalsmith-plugin-green.svg?longCache=true
51
+ [metalsmith-url]: https://metalsmith.io
52
+ [license-badge]: https://img.shields.io/github/license/wernerglinka/metalsmith-static-files
53
+ [license-url]: LICENSE
54
+ [coverage-badge]: https://img.shields.io/badge/coverage-98%25-brightgreen
55
+ [coverage-url]: #test-coverage
56
+ [modules-badge]: https://img.shields.io/badge/modules-ESM%2FCJS-blue
57
+ ```
58
+
59
+ These are the actual badges used for metalsmith-static-files. Just replace them with your plugin's name and GitHub repository for other plugins.
60
+
61
+ ## Environment Setup
62
+
63
+ When starting a new session, run this to ensure the correct Node.js version is used:
64
+
65
+ ```bash
66
+ source ~/.nvm/nvm.sh && nvm use
67
+ ```
68
+
69
+ This will load NVM and automatically use the Node.js version specified in the project's .nvmrc file (20.12.1).
70
+
71
+ ## Common Commands
72
+
73
+ Build the project:
74
+ ```bash
75
+ npm run build
76
+ ```
77
+
78
+ Run tests with coverage:
79
+ ```bash
80
+ npm test
81
+ ```
82
+
83
+ ## Release Process
84
+
85
+ Check if the release will work correctly:
86
+ ```bash
87
+ npm run release:check
88
+ ```
89
+
90
+ Create an actual release:
91
+ ```bash
92
+ npm run release
93
+ ```
94
+
95
+ The release process:
96
+ 1. Loads environment variables from .env file
97
+ 2. Runs linting and tests
98
+ 3. Updates the version in package.json
99
+ 4. Generates a changelog with auto-changelog
100
+ 5. Creates a git tag
101
+ 6. Creates a GitHub release with the changelog
102
+ 7. Creates an npm package (.tgz file) but does not publish it to npm
103
+
104
+ Required environment variables:
105
+ - `GITHUB_TOKEN` - A GitHub personal access token with repo scope
106
+
107
+ Notes on token handling:
108
+ 1. The token is extracted directly from the .env file using grep and cut
109
+ 2. It's set as an environment variable for the release-it command
110
+ 3. No dotenv dependency is required for this approach
111
+ 4. This ensures the token is reliably available to release-it
112
+
113
+ Reliable token extraction script for package.json:
114
+ ```json
115
+ "release": "npm run build && GITHUB_TOKEN=$(grep GITHUB_TOKEN .env | cut -d '=' -f2) ./node_modules/.bin/release-it .",
116
+ "release:check": "npm run lint:check && npm run build && GITHUB_TOKEN=$(grep GITHUB_TOKEN .env | cut -d '=' -f2) ./node_modules/.bin/release-it . --dry-run"
117
+ ```
118
+
119
+ This approach directly extracts the token from the .env file using grep and cut, making it more reliable than other methods.
120
+
121
+ You can also run the command with the token inline if needed:
122
+ ```bash
123
+ GITHUB_TOKEN=your_token npm run release
124
+ ```
125
+
126
+ ## Metalsmith Plugin Best Practices
127
+
128
+ ### Project Structure for Dual Module Packages
129
+ - `/src/` - Source code with dual export syntax
130
+ - `/lib/` - Built code (contains both ESM `.js` and CommonJS `.cjs` versions)
131
+ - `/test/` - Test files including specific tests for both module formats
132
+
133
+ ### Dual Module Support Implementation (ESM and CommonJS)
134
+ - Configure package.json for dual module support:
135
+ ```json
136
+ "type": "module",
137
+ "main": "./lib/index.cjs",
138
+ "module": "./lib/index.js",
139
+ "exports": {
140
+ "import": "./lib/index.js",
141
+ "require": "./lib/index.cjs"
142
+ }
143
+ ```
144
+ - Use microbundle to build both formats:
145
+ ```json
146
+ "build": "microbundle --entry src/index.js --output lib/index.js --target node -f esm,cjs --strict --generateTypes=false"
147
+ ```
148
+ - Add both export types in source code:
149
+ ```javascript
150
+ // ESM export
151
+ export default myPlugin;
152
+
153
+ // CommonJS export compatibility
154
+ if (typeof module !== 'undefined') {
155
+ module.exports = myPlugin;
156
+ }
157
+ ```
158
+ - Create optimized tests for dual module support:
159
+ - Main ESM test file (`test/index.js`) that imports directly from the src directory for full coverage:
160
+ ```javascript
161
+ // ESM test file for Metalsmith plugins
162
+ import { strict as assert } from 'node:assert';
163
+ import { fileURLToPath } from 'node:url';
164
+ import { dirname, resolve } from 'node:path';
165
+ import { readFileSync } from 'node:fs';
166
+ import metalsmith from 'metalsmith';
167
+
168
+ // Import the plugin directly from src for accurate coverage
169
+ import plugin from '../src/index.js';
170
+
171
+ // Get current directory and setup path utilities
172
+ const __dirname = dirname(fileURLToPath(import.meta.url));
173
+
174
+ describe('metalsmith-plugin-name (ESM)', () => {
175
+ // Main functionality tests here
176
+
177
+ // Verify ESM module loading
178
+ it('should be importable as an ES module', () => {
179
+ assert.strictEqual(typeof plugin, 'function', 'Plugin should be a function when imported with ESM');
180
+ assert.strictEqual(typeof plugin(), 'function', 'Plugin should return a function when called');
181
+ });
182
+ });
183
+ ```
184
+ - Minimal CommonJS test file (`test/cjs.test.cjs`) to verify CJS compatibility:
185
+ ```javascript
186
+ // Minimal CommonJS test file - just verifies the CJS module works
187
+ const assert = require('node:assert').strict;
188
+
189
+ // Import the plugin using the CommonJS format
190
+ const plugin = require('../lib/index.cjs');
191
+
192
+ describe('metalsmith-plugin-name (CommonJS)', () => {
193
+ // Verify the module loads correctly and exports a function
194
+ it('should be properly importable as a CommonJS module', () => {
195
+ assert.strictEqual(typeof plugin, 'function', 'Plugin should be a function when required with CommonJS');
196
+ assert.strictEqual(typeof plugin(), 'function', 'Plugin should return a function when called');
197
+ });
198
+
199
+ // Add a basic functionality test to verify the plugin works
200
+ it('should create expected metadata collections when used', () => {
201
+ const instance = plugin();
202
+ const files = { /* minimal test files */ };
203
+ const metadata = {};
204
+ const metalsmithMock = {
205
+ metadata: function() { return metadata; }
206
+ };
207
+
208
+ instance(files, metalsmithMock, () => {});
209
+
210
+ // Verify basic functionality works
211
+ assert.strictEqual(typeof metadata.someExpectedProperty, 'object', 'Plugin should add expected metadata');
212
+ });
213
+ });
214
+ ```
215
+ - Configure package.json to run both tests:
216
+ ```json
217
+ "scripts": {
218
+ "test": "c8 --include=src/**/*.js mocha 'test/index.js' 'test/cjs.test.cjs' -t 15000",
219
+ "test:esm": "c8 --include=src/**/*.js mocha test/index.js -t 15000",
220
+ "test:cjs": "c8 --include=src/**/*.js mocha test/cjs.test.cjs -t 15000"
221
+ }
222
+ ```
223
+ - ESLint and Prettier configuration:
224
+ - Keep ESLint config in `eslint.config.js` with ESM format
225
+ - Keep Prettier config in `prettier.config.js` with ESM format
226
+ - Include `.nvmrc` file to ensure consistent Node.js version
227
+ - Ensure ESLint/Prettier ignore patterns include `lib/`, `coverage/` and `node_modules/`
228
+
229
+ ### Code Quality
230
+ - Use Metalsmith's built-in debug capability instead of external debug module
231
+ ```javascript
232
+ // Define namespace at the top of the file
233
+ const debugNs = 'metalsmith-plugin-name';
234
+
235
+ // Then in your plugin function
236
+ function plugin(options) {
237
+ return function(files, metalsmith, done) {
238
+ const debug = metalsmith.debug ? metalsmith.debug(debugNs) : () => {};
239
+ debug('Running with options: %o', options);
240
+ // rest of your code...
241
+ };
242
+ }
243
+ ```
244
+
245
+ - Test the debug functionality (both with and without debug available):
246
+ ```javascript
247
+ it('should use metalsmith debug when available', function(done) {
248
+ // Create a mock debug function that records calls
249
+ const debugCalls = [];
250
+ const mockMetalsmith = {
251
+ path: (p) => p,
252
+ destination: () => 'build',
253
+ debug: () => (...args) => {
254
+ debugCalls.push(args);
255
+ return true;
256
+ }
257
+ };
258
+
259
+ // Create and call the plugin
260
+ const pluginInstance = plugin({ source: 'src', destination: 'dest' });
261
+ pluginInstance({}, mockMetalsmith, () => {
262
+ // Verify debug was called with correct arguments
263
+ assert(debugCalls.length > 0, 'Debug function should have been called');
264
+ assert(debugCalls[0][0].includes('options'), 'Should include options message');
265
+ assert(debugCalls[0][1].source === 'src', 'Should include source option');
266
+ done();
267
+ });
268
+ });
269
+
270
+ it('should handle missing debug method gracefully', function(done) {
271
+ // Create a metalsmith mock without debug method
272
+ const mockMetalsmith = {
273
+ path: (p) => p,
274
+ destination: () => 'build'
275
+ // No debug property
276
+ };
277
+
278
+ // Should not throw error when debug is missing
279
+ const pluginInstance = plugin({ source: 'src', destination: 'dest' });
280
+ pluginInstance({}, mockMetalsmith, (err) => {
281
+ assert.strictEqual(err, undefined, 'No error should occur when debug is missing');
282
+ done();
283
+ });
284
+ });
285
+ ```
286
+ - Use robust error handling
287
+ - Track loaded resources to prevent duplicates
288
+ - Add thorough documentation with JSDoc
289
+ - Add a Set to track loaded resources (like languages) to avoid duplicates
290
+ - Only run setup code conditionally when needed
291
+ - Use exact matching for conditionals instead of regex when possible
292
+
293
+ ### Testing Strategy for Dual Module Packages
294
+
295
+ #### Test Organization
296
+ - `test/index.js` - Main ESM test file with complete functionality tests
297
+ - `test/cjs.test.cjs` - Minimal CommonJS compatibility tests
298
+ - `test/fixtures/` - Test fixtures for various scenarios
299
+
300
+ #### C8 Configuration for Accurate Coverage
301
+ Use a proper .c8rc.json configuration file:
302
+ ```json
303
+ {
304
+ "all": true,
305
+ "include": ["src/**/*.js"],
306
+ "exclude": ["node_modules/**", "test/**", "lib/**"],
307
+ "reporter": ["text", "lcov"],
308
+ "report-dir": "./coverage",
309
+ "watermarks": {
310
+ "lines": [80, 95],
311
+ "functions": [80, 95],
312
+ "branches": [80, 95],
313
+ "statements": [80, 95]
314
+ }
315
+ }
316
+ ```
317
+
318
+ #### Key Coverage Reporting Strategies
319
+ 1. **Import from src/ not lib/**:
320
+ - ESM tests should import directly from `src/index.js` for accurate coverage
321
+ - CJS tests must use `lib/index.cjs` since they can't import ESM directly
322
+
323
+ 2. **Coverage Badge Script**:
324
+ - Use a dedicated script to update the README with current coverage
325
+ - Create a script like `scripts/update-coverage-badge.js` that:
326
+ - Runs tests to generate coverage data
327
+ - Extracts coverage information from the report
328
+ - Updates README.md with badge and coverage table
329
+
330
+ Example implementation:
331
+ ```javascript
332
+ #!/usr/bin/env node
333
+
334
+ import fs from 'fs/promises';
335
+ import { execSync } from 'child_process';
336
+ import path from 'path';
337
+ import { fileURLToPath } from 'url';
338
+
339
+ // Get the current directory
340
+ const __filename = fileURLToPath(import.meta.url);
341
+ const __dirname = path.dirname(__filename);
342
+ const rootDir = path.join(__dirname, '..');
343
+
344
+ function determineBadgeColor(percentage) {
345
+ if (percentage >= 90) {return 'brightgreen';}
346
+ if (percentage >= 80) {return 'green';}
347
+ if (percentage >= 70) {return 'yellowgreen';}
348
+ if (percentage >= 60) {return 'yellow';}
349
+ if (percentage >= 50) {return 'orange';}
350
+ return 'red';
351
+ }
352
+
353
+ async function main() {
354
+ try {
355
+ process.stderr.write('Updating coverage badge in README.md...\n');
356
+
357
+ // Run the full test suite to collect coverage
358
+ process.stderr.write('Running full test suite for coverage data...\n');
359
+ execSync('npm test', { stdio: 'inherit' });
360
+
361
+ // Get the coverage data from the c8 report
362
+ process.stderr.write('Extracting coverage data from report...\n');
363
+ const coverageOutput = execSync('npx c8 report --reporter=text', { encoding: 'utf-8' });
364
+
365
+ // Parse the coverage report
366
+ const coverageData = parseCoverageReport(coverageOutput);
367
+
368
+ if (coverageData) {
369
+ process.stderr.write(`Successfully parsed coverage data\n`);
370
+ await updateReadme(coverageData);
371
+ } else {
372
+ process.stderr.write('Could not parse coverage data, falling back to hardcoded values\n');
373
+ await useHardcodedValues();
374
+ }
375
+ } catch (error) {
376
+ console.error('Error updating coverage badge:', error);
377
+ process.exit(1);
378
+ }
379
+ }
380
+
381
+ // Implement parseCoverageReport, updateReadme, and useHardcodedValues functions
382
+ // to extract data and update the README
383
+
384
+ main();
385
+ ```
386
+
387
+ 3. **Package.json Scripts**:
388
+ ```json
389
+ "scripts": {
390
+ "build": "microbundle --entry src/index.js --output lib/index.js --target node -f esm,cjs --strict --generateTypes=false",
391
+ "changelog": "auto-changelog -u --commit-limit false --ignore-commit-pattern '^((dev|chore|ci):|Release)'",
392
+ "coverage": "npm test && c8 report --reporter=text-lcov > ./coverage.info",
393
+ "format": "prettier --write \"**/*.{yml,md,js,json}\"",
394
+ "format:check": "prettier --list-different \"**/*.{yml,md,js,json}\"",
395
+ "lint": "eslint --fix .",
396
+ "lint:check": "eslint --fix-dry-run .",
397
+ "prepublishOnly": "npm run build",
398
+ "update-coverage": "node scripts/update-coverage-badge.js",
399
+ "prerelease": "npm run update-coverage && git add README.md && git commit -m \"Update coverage badge in README\" || true",
400
+ "release": "npm run build && GITHUB_TOKEN=$(grep GITHUB_TOKEN .env | cut -d '=' -f2) ./node_modules/.bin/release-it . ",
401
+ "release:check": "npm run lint:check && npm run build && GITHUB_TOKEN=$(grep GITHUB_TOKEN .env | cut -d '=' -f2) ./node_modules/.bin/release-it . --dry-run",
402
+ "test": "c8 --include=src/**/*.js mocha 'test/index.js' 'test/cjs.test.cjs' -t 15000",
403
+ "test:esm": "c8 --include=src/**/*.js mocha test/index.js -t 15000",
404
+ "test:cjs": "c8 --include=src/**/*.js mocha test/cjs.test.cjs -t 15000",
405
+ "test:e2e": "serve -l 3000 test/fixtures",
406
+ "depcheck": "depcheck"
407
+ },
408
+ ```
409
+
410
+ #### Example Coverage Report in README
411
+ ```
412
+ ----------|---------|----------|---------|---------|-------------------
413
+ File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
414
+ ----------|---------|----------|---------|---------|-------------------
415
+ All files | 99.06 | 87.09 | 100 | 99.06 |
416
+ index.js | 99.06 | 87.09 | 100 | 99.06 | 214-215
417
+ ----------|---------|----------|---------|---------|-------------------
418
+ ```
419
+
420
+ Include tests for:
421
+ 1. **Basic functionality** - Core features
422
+ 2. **Error handling** - Graceful handling of failures
423
+ 3. **Edge cases** - Malformed input, missing data, etc.
424
+ 4. **Multiple inputs** - Processing various inputs in one run
425
+ 5. **Combined options** - Multiple options working together
426
+ 6. **Performance** - Handling large inputs efficiently
427
+ 7. **Context sensitivity** - Processing in correct contexts only
428
+ 8. **Real-world examples** - Complex, realistic code
429
+
430
+ Test using direct plugin invocation for speed:
431
+ ```javascript
432
+ const plugin = metalsmithPluginName(options);
433
+ plugin(files, metalsmith, done);
434
+ ```
435
+
436
+ ## Release Configuration Notes
437
+
438
+ - Keep `"npm": { "publish": false }` in .release-it.json - this project is manually published to npm
439
+ - The GitHub asset naming pattern should be: `metalsmith-<plugin-name>-${version}.tgz`
440
+
441
+ ### Excluding Commits from Release Notes
442
+
443
+ The .release-it.json file includes patterns to exclude certain commits from appearing in release notes:
444
+
445
+ ```json
446
+ "ignore-commit-pattern": "^((dev|chore|ci|docs|build|test):|Release|Update coverage|Fix.*badge|Remove dotenv)"
447
+ ```
448
+
449
+ This pattern excludes:
450
+ - Commits that start with common prefixes like `chore:`, `docs:`, `test:`, etc.
451
+ - Commits related to coverage badge updates
452
+ - Dependency maintenance commits
453
+ - Release commits themselves
454
+
455
+ When making maintenance commits that shouldn't appear in release notes, use one of these prefixes or patterns.
456
+
457
+ For example:
458
+ - `chore: update dependencies`
459
+ - `docs: improve API documentation`
460
+ - `test: add more test cases`
461
+ - `build: fix build process`
462
+
463
+ Alternatively, you can update the ignore pattern in .release-it.json to exclude specific types of commits.
464
+
465
+ ## Summary: Testing and Coverage for Dual Module Packages
466
+
467
+ ### Key Insights
468
+ 1. **Separate ESM and CJS Tests**:
469
+ - Main ESM tests: Comprehensive functionality tests that import directly from `src/` for accurate coverage
470
+ - Minimal CJS tests: Just enough to verify the CJS module works correctly
471
+
472
+ 2. **Coverage Reporting Best Practices**:
473
+ - Configure c8 with `.c8rc.json` to focus on source files (`src/`) and exclude built files (`lib/`)
474
+ - Use a dedicated script to update the README with current coverage information
475
+ - Import directly from `src/` in ESM tests to get accurate coverage metrics
476
+ - Remember that CJS tests won't show coverage for ES modules - this is expected
477
+
478
+ 3. **File Organization**:
479
+ - `/test/index.js` - Main ESM tests with comprehensive coverage
480
+ - `/test/cjs.test.cjs` - Minimal CJS compatibility tests
481
+ - `/scripts/update-coverage-badge.js` - Coverage badge updater
482
+
483
+ 4. **Common Issues and Solutions**:
484
+ - If coverage reporting shows 0% when importing from `lib/`, switch to importing from `src/` in ESM tests
485
+ - Use `.cjs` extension for CommonJS test files in an ESM project
486
+ - If all else fails, use manually verified hardcoded values as a fallback in the coverage script
487
+
488
+ This approach ensures reliable code coverage reporting for dual-module packages while maintaining compatibility with both ESM and CommonJS.