remark-git-contributors
remark plugin to generate a list of Git contributors.
Contents
- What is this?
- When should I use this?
- Install
- Use
- API
- Examples
- Types
- Compatibility
- Security
- Contribute
- Contributors
- License
What is this?
This package is a unified (remark) plugin that collects contributors from Git history, deduplicates them, augments it with metadata found in options, a module, or package.json
, and passes that to remark-contributors
to add them in a table in ## Contributors
.
unified is a project that transforms content with abstract syntax trees (ASTs). remark adds support for markdown to unified. mdast is the markdown AST that remark uses. This is a remark plugin that transforms mdast.
When should I use this?
This project is particularly useful when you have (open source) projects that are maintained with Git and want to show who helped build them by adding their names, websites, and perhaps some more info, based on their commits, to readmes. This package is useful because it’s automated based on Git: those who commit will get included. The downside is that commits aren’t the only way to contribute (something All Contributors focusses on).
This plugin is a Git layer on top of remark-contributors
, so it shares its benefits. You can also use that plugin when you don’t want Git commits to be the source of truth.
Install
This package is ESM only. In Node.js (version 12.20+, 14.14+, or 16.0+), install with npm:
npm install remark-git-contributors
Contributions are welcome to add support for Deno.
Use
Say we have the following file example.md
in this project:
# Example
Some text.
## Contributors
## License
MIT
And our module example.js
looks as follows:
import {read} from 'to-vfile'
import {remark} from 'remark'
import remarkGfm from 'remark-gfm'
import remarkGitContributors from 'remark-git-contributors'
main()
async function main() {
const file = await remark()
.use(remarkGfm) // Required: add support for tables (a GFM feature).
.use(remarkGitContributors)
.process(await read('example.md'))
console.log(String(file))
}
Now running node example.js
yields:
# Example
Some text.
## Contributors
| Name | GitHub | Social |
| :------------------ | :------------------------------------------- | :---------------------------------------------------- |
| **Vincent Weevers** | [**@vweevers**](https://github.com/vweevers) | [**@vweevers@twitter**](https://twitter.com/vweevers) |
| **Titus Wormer** | [**@wooorm**](https://github.com/wooorm) | [**@wooorm@twitter**](https://twitter.com/wooorm) |
## License
MIT
👉 Note: These contributors are inferred from this project’s
package.json
. Running this example in a different package will yield different results.
API
This package exports no identifiers. The default export is remarkGitContributors
.
unified().use(remarkGitContributors[, options])
Generate a list of Git contributors. In short, this plugin:
- looks for the first heading matching
/^contributors$/i
- if no heading is found and
appendIfMissing
is set, injects such a heading - if there is a heading, replaces everything in that section with a new table with Git contributors
options
Configuration (optional).
options.limit
Limit the total number of contributors rendered (number
, default: Infinity
). A limit of Infinity
or 0
(or lower) results in all contributors being included. The top contributors by commit count are included.
options.contributors
Contributor metadata (Array
or string
, default: []
). Can be a list of contributor objects (see above). Can be a module id that will be import
ed which exports contributors
as either the default export or as a contributors
named export specifier.
options.cwd
Working directory from which to resolve a contributors
module, if any (string
, default: file.cwd
or process.cwd()
).
options.appendIfMissing
Inject a ## Contributors
section if there is none (boolean
, default: false
).
Examples
Example: CLI
It’s recommended to use remark-git-contributors
on the CLI with remark-cli
. Install both (and remark-gfm
) with npm:
npm install remark-cli remark-gfm remark-git-contributors --save-dev
Let’s say we have an example.md
with the following text:
# Hello
Some text.
## Contributors
You can now use the CLI to format example.md
:
npx remark --output --use remark-gfm --use remark-git-contributors example.md
This adds the table of contributors to example.md
, which now contains (when running in this project):
# Hello
Some text.
## Contributors
| Name | GitHub | Social |
| :------------------ | :------------------------------------------- | :---------------------------------------------------- |
| **Vincent Weevers** | [**@vweevers**](https://github.com/vweevers) | [**@vweevers@twitter**](https://twitter.com/vweevers) |
| **Titus Wormer** | [**@wooorm**](https://github.com/wooorm) | [**@wooorm@twitter**](https://twitter.com/wooorm) |
Example: CLI in npm scripts
You can use remark-git-contributors
and remark-cli
in an npm script to format markdown in your project. Install both (and remark-gfm
) with npm:
npm install remark-cli remark-gfm remark-git-contributors --save-dev
Then, add a format script and configuration to package.json
:
{
// …
"scripts": {
// …
"format": "remark . --quiet --output",
// …
},
"remarkConfig": {
"plugins": [
"remark-gfm",
"remark-git-contributors"
]
},
// …
}
💡 Tip: Add other tools such as prettier or ESLint to check and format other files.
💡 Tip: Run
./node_modules/.bin/remark --help
for help withremark-cli
.
Now you format markdown in your project with:
npm run format
Example: appendIfMissing
The default behavior of this plugin is to not generate lists of Git contributors if there is no ## Contributors
(case- and level-insensitive). You can change that by configuring the plugin with appendIfMissing: true
.
The reason for not generating contributors by default is that as we saw in the previous example (CLI in npm scripts) remark and this plugin often run on several files. You can choose where to add the list by explicitly adding ## Contributors
in the main file (readme.md
) and other docs won’t be touched. Or, when you have many contributors, add a specific contributors.md
file, with a primary # Contributors
heading, and the list will be generated there.
To turn appendIfMissing
mode on, pass it like so on the API:
// …
.use(remarkGitContributors, {appendIfMissing: true})
// …
Or on the CLI (in package.json
):
// …
"remarkConfig": {
"plugins": [
// …
[
"remark-git-contributors",
{"appendIfMissing": true}
]
]
},
// …
Example: metadata
The data gathered from Git is only includes names and emails. To add more metadata, either add it to package.json
(used in this project’s package.json
) or configure options.contributors
. On the API, that’s done like so:
// …
.use(remarkGitContributors, {contributors: /* value */})
// …
Or on the CLI (in package.json
):
// …
"remarkConfig": {
"plugins": [
// …
[
"remark-git-contributors",
{"contributors": /* value */}
]
]
},
// …
The value for contributors
is either:
- an array in the form of
[{ email, name, … }, … ]
; - a module id, or path to a file, that exports
contributors
as the default export or as acontributors
named export
👉 Note: contributors that are not in Git history are excluded. This way the
contributors
metadata can be reused in multiple projects.
Each contributor should at least have an email
property to match against Git email addresses. If you’re experiencing people showing up multiple times from Git history, for example because they switched email addresses while contributing to the project, or if their name or email are wrong, you can “merge” and fix contributors in Git by using a .mailmap
file.
The supported properties on contributors are:
name
— person’s name (example:Sara
)email
— person’s email (example:sara@example.com
)github
— GitHub username (example:sara123
)twitter
— Twitter username (example:the_sara
)mastodon
— Mastodon (@user@domain
)
An example of a module is:
// …
.use(remarkGitContributors, {contributors: './data/contributors.js'})
// …
Where data/contributors.js
would contain either:
export const contributors = [{ email, name, /* … */ }, /* … */ ]
Or:
const contributors = [{ email, name, /* … */ }, /* … */ ]
export default contributors
Types
This package is fully typed with TypeScript. It exports an Options
type which models the interface of the accepted options.
Compatibility
Projects maintained by the unified collective are compatible with all maintained versions of Node.js. As of now, that is Node.js 12.20+, 14.14+, and 16.0+. Our projects sometimes work with older versions, but this is not guaranteed.
This plugin works with unified
version 6+ and remark
version 7+.
Security
remark-git-contributors
is typically used in a trusted environment. This section explains potential attack vectors and how to mitigate them if the environment is not (fully) trusted.
options.contributors
(or contributors
in package.json
) and author
from package.json
are used and injected into the tree. git log
also runs in the current working directory. This could open you up to a cross-site scripting (XSS) attack if you pass user provided content in or store user provided content in package.json
or Git.
This may become a problem if the markdown later transformed to rehype (hast) or opened in an unsafe markdown viewer.
If contributors
is a string, it is handled as a module identifier and imported. This could also be very dangerous if an attacker was able to inject code in that package.
Contribute
See contributing.md
in remarkjs/.github
for ways to get started. See support.md
for ways to get help.
This project has a code of conduct. By interacting with this repository, organization, or community you agree to abide by its terms.
Contributors
Name | GitHub | Social |
---|---|---|
Vincent Weevers | @vweevers | @vweevers@twitter |
Titus Wormer | @wooorm | @wooorm@twitter |
License
MIT © Vincent Weevers