Skip to content

remarkjs/remark-git-contributors

Repository files navigation

remark-git-contributors

Version Build Coverage Downloads Sponsors Backers Chat

remark plugin to generate a list of Git contributors.

Contents

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.

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 16+), 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 a module example.js:

import {remark} from 'remark'
import remarkGfm from 'remark-gfm'
import remarkGitContributors from 'remark-git-contributors'
import {read} from 'to-vfile'

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))

…then running node example.js yields:

# Example

Some text.

## Contributors

| Name                | GitHub                                       | Social                                                |
| :------------------ | :------------------------------------------- | :---------------------------------------------------- |
| **Titus Wormer**    | [**@wooorm**](https://github.com/wooorm)     | [**@wooorm@twitter**](https://twitter.com/wooorm)     |
| **Vincent Weevers** | [**@vweevers**](https://github.com/vweevers) | [**@vweevers@twitter**](https://twitter.com/vweevers) |

## License

MIT

👉 Note: These contributors are inferred from the Git history and package.json in this repo. Running this example in a different package will yield different results.

API

This package exports no identifiers. The default export is remarkGitContributors.

defaultFilter(contributor, metadata)

Default filter for contributors (Filter); currently filters out Greenkeeper.

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
Parameters
  • options (Options or string, optional) — configuration; passing string is as if passing options.contributors
Returns

Transform (Transformer).

Contributor

Contributor in string form (name <email> (url)) or as object (TypeScript type).

Type
type Contributor = Record<string, unknown> | string

Filter

Filter contributors (TypeScript type).

Parameters
  • contributor (Contributor) — contributor found by contributorsFromGit
  • metadata (Record<string, unknown>) — associated metadata found in package.json or options.contributors
Returns

Whether to include the contributor (boolean).

Options

Configuration (TypeScript type).

Fields
  • appendIfMissing (boolean, default: false) — inject the section if there is none
  • contributors (Array<Contributor> or string, optional) — list of contributors to inject; defaults to the contributors field in the closest package.json upwards from the processed file, if there is one; supports the string form (name <email> (url)) as well; throws if no contributors are found or given
  • cwd (string, default: file.cwd) — working directory from which to resolve a contributors module, if any
  • filter (Filter, default: defaultFilter) — filter contributors
  • limit (number, default: 0) — limit the rendered contributors; 0 (or lower) includes all contributors; if limit is given, only the top <limit> contributors, sorted by commit count, are rendered

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                                                |
| :------------------ | :------------------------------------------- | :---------------------------------------------------- |
| **Titus Wormer**    | [**@wooorm**](https://github.com/wooorm)     | [**@wooorm@twitter**](https://twitter.com/wooorm)     |
| **Vincent Weevers** | [**@vweevers**](https://github.com/vweevers) | [**@vweevers@twitter**](https://twitter.com/vweevers) |

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 . --output --quiet",
    // …
  },
  "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 with remark-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 options.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 a contributors 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:

  • email — person’s email (example: [email protected])
  • github — GitHub username (example: sara123)
  • mastodon — Mastodon (@user@domain)
  • name — person’s name (example: Sara)
  • twitter — Twitter username (example: the_sara)

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 the additional types Contributor, Filter, and Options.

Compatibility

Projects maintained by the unified collective are compatible with maintained versions of Node.js.

When we cut a new major release, we drop support for unmaintained versions of Node. This means we try to keep the current release line, remark-git-contributors@^5, compatible with Node.js 16.

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
Titus Wormer @wooorm @wooorm@twitter
Vincent Weevers @vweevers @vweevers@twitter

License

MIT © Vincent Weevers