metalsmith-markdown-partials 2.3.0 → 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.
- package/.c8rc.json +13 -0
- package/.env +1 -0
- package/.nvmrc +1 -0
- package/.release-it.json +5 -7
- package/CHANGELOG.md +68 -1
- package/CLAUDE.md +488 -0
- package/README.md +25 -4
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +116 -0
- package/coverage/lcov-report/index.js.html +646 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +196 -0
- package/coverage/lcov.info +232 -0
- package/coverage/tmp/coverage-44920-1742597774927-0.json +1 -0
- package/coverage/tmp/coverage-44921-1742597774583-0.json +1 -0
- package/eslint.config.js +51 -0
- package/lib/index.cjs +184 -0
- package/lib/index.cjs.map +1 -0
- package/lib/index.js +123 -81
- package/lib/index.js.map +1 -0
- package/metalsmith-markdown-partials-2.4.0.tgz +0 -0
- package/package.json +34 -21
- package/prettier.config.js +9 -0
- package/scripts/update-coverage-badge.js +225 -0
- package/src/index.js +187 -0
- package/test/cjs.test.cjs +55 -0
- package/test/index.js +139 -0
- package/.eslintcache +0 -1
- package/.nyc_output/2f18c0a6-17f5-4c4e-be96-fea82a584403.json +0 -1
- package/.nyc_output/processinfo/2f18c0a6-17f5-4c4e-be96-fea82a584403.json +0 -1
- package/.nyc_output/processinfo/index.json +0 -1
- package/.prettierrc.yml +0 -7
- package/metalsmith-markdown-partials-2.0.3.tgz +0 -0
- package/tests/index.js +0 -42
- /package/{tests → test}/fixtures/build/markdown.md +0 -0
- /package/{tests → test}/fixtures/expected/final-markdown.md +0 -0
- /package/{tests → test}/fixtures/src/markdown.md +0 -0
- /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": "
|
|
18
|
+
"releaseName": "metalsmith-markdown-partials ${version}",
|
|
21
19
|
"tokenRef": "GITHUB_TOKEN",
|
|
22
|
-
"assets": ["metalsmith
|
|
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
|
-
####
|
|
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.
|