Git Product home page Git Product logo

remark-contributors's Introduction

remark-contributors

Build Coverage Downloads Size Sponsors Backers Chat

remark plugin to generate a list of contributors.

Contents

What is this?

This package is a unified (remark) plugin that takes a list of contributors and adds them in a table to a ## Contributors heading.

When should I use this?

This project is useful when you’re writing documentation for a project, typically a Node.js package, that has one or more readmes and maybe some other markdown files as well. You want to show who helped build the project by adding their names, websites, and perhaps some more info. This package is useful because it’s automated: you can customize who is added and how that’s formatted. But it won’t be as expressive as writing such sections manually.

This plugin is used in remark-git-contributors. The difference is that that plugin takes the Git history into account, which isn’t always needed or correct.

Install

This package is ESM only. In Node.js (version 16+), install with npm:

npm install remark-contributors

In Deno with esm.sh:

import remarkContributors from 'https://esm.sh/remark-contributors@7'

In browsers with esm.sh:

<script type="module">
  import remarkContributors from 'https://esm.sh/remark-contributors@7?bundle'
</script>

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 remarkContributors from 'remark-contributors'
import remarkGfm from 'remark-gfm'
import {read} from 'to-vfile'

const file = await remark()
  .use(remarkGfm) // This is needed to add support for tables (a GFM feature).
  .use(remarkContributors)
  .process(await read('example.md'))

console.log(String(file))

…then running node example.js yields:

# Example

Some text.

## Contributors

| Name                | Website                     |
| ------------------- | --------------------------- |
| **Hugh Kennedy**    | <https://hughsk.io>         |
| **Titus Wormer**    | <https://wooorm.com>        |
| **Vincent Weevers** | <https://vincentweevers.nl> |
| **Nick Baugh**      | <https://niftylettuce.com>  |

## License

MIT

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

API

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

unified().use(remarkContributors[, options])

Generate a list of contributors.

In short, this plugin:

  • looks for the first heading matching /^contributors$/i or options.heading
  • 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
Parameters
  • options (Options, optional) — configuration
Returns

Transform (Transformer).

Notes
  • define fields other than name, url, github, or twitter in formatters to label them properly
  • by default, fields named url will be labelled Website (so that package.json contributors field is displayed nicely)
  • by default, fields named email are ignored
  • name fields are displayed as strong
  • GitHub and Twitter URLs are automatically stripped and displayed with @mentions wrapped in an https:// link
  • if a field is undefined for a given contributor, then the value will be an empty table cell
  • columns are sorted in the order they are defined (first defined means first displayed)

Contributor

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

Type
type Contributor = ContributorObject | string

ContributorObject

Contributor with fields (TypeScript type).

Type
type ContributorObject = Record<string, unknown>

Format

Format a field (TypeScript type).

Parameters
  • value (unknown) — value to format
  • key (string) — name of a field in a contributor
  • contributor (Contributor) — whole contributor
Returns

Content (Array<PhrasingContent> | PhrasingContent | string, optional)

Formatter

How to format a field, in short (TypeScript type).

The values can be:

  • null or undefined — does nothing;
  • false — shortcut for {exclude: true, label: key}, can be used to exclude default formatters;
  • true — shortcut for {label: key}, can be used to include default formatters (like email)
  • string — shortcut for {label: value}
  • Formatter — …or a proper formatter object
Type
type Formatter = FormatterObject | boolean | string | null | undefined

FormatterObject

How to format a field (TypeScript type).

Fields
  • exclude (boolean, default: false) — whether to ignore these fields
  • format (Format, optional) — How to format the cell
  • label (string, optional) — text in the header row that labels the column for this field

Formatters

Formatters for fields (TypeScript type).

Type
type Formatters = Record<string, Formatter>

Options

Configuration (TypeScript type).

Fields
  • align (AlignType from mdast, optional) — alignment to use for all cells in the table
  • appendIfMissing (boolean, default: false) — inject the section if there is none; the default does nothing when the section doesn’t exist so that you have to choose where and if the section is added
  • contributors (Array<Contributor>, default: contributors in package.json in Node) — list of contributors to inject; supports string form (name <email> (url)); throws if no contributors are found or given
  • formatters (string, optional) — map of fields found in contributors to formatters; these given formatters extend the default formatters; the keys in formatters should correspond directly (case-sensitive) to keys in contributors
  • heading (RegExp | string, default: 'contributors') — heading to look for

Examples

Example: passing contributors

The following example shows how contributors can be passed:

import {remark} from 'remark'
import remarkContributors from 'remark-contributors'
import remarkGfm from 'remark-gfm'

const file = await remark()
  .use(remarkGfm)
  .use(remarkContributors, {
    contributors: [
      // String form:
      'Jane Doe <[email protected]> (https://example.com/jane)',
      // Object form, with just a name:
      {name: 'John Doe'},
      // Some more info:
      {name: 'Mona Lisa', url: 'https://github.com/monatheoctocat'}
    ]
  })
  .process('## Contributors')

console.log(String(file))

Yields:

## Contributors

| Name          | Website                             |
| ------------- | ----------------------------------- |
| **Jane Doe**  | <https://example.com/jane>          |
| **John Doe**  |                                     |
| **Mona Lisa** | <https://github.com/monatheoctocat> |

Example: formatters

By default, unknown fields in contributors will be added to the table:

import {remark} from 'remark'
import remarkContributors from 'remark-contributors'
import remarkGfm from 'remark-gfm'

const file = await remark()
  .use(remarkGfm)
  .use(remarkContributors, {
    contributors: [
      {name: 'Jane Doe', age: 31, topping: 'Mozzarella'},
      {name: 'John Doe', age: 29, topping: 'Olive'},
      {name: 'Mona Lisa', age: 3, topping: 'Pineapple'}
    ]
  })
  .process('## Contributors')

console.log(String(file))

Yields:

## Contributors

| Name          | age | topping    |
| ------------- | --- | ---------- |
| **Jane Doe**  | 31  | Mozzarella |
| **John Doe**  | 29  | Olive      |
| **Mona Lisa** | 3   | Pineapple  |

It’s possible to customize how these new fields are formatted:

@@ -12,7 +12,16 @@ const file = await remark()
       {name: 'Jane Doe', age: 31, topping: 'Mozzarella'},
       {name: 'John Doe', age: 29, topping: 'Olive'},
       {name: 'Mona Lisa', age: 3, topping: 'Pineapple'}
-    ]
+    ],
+    formatters: {
+      age: {
+        label: 'Age',
+        format(d) {
+          return {type: 'emphasis', children: [{type: 'text', value: String(d)}]}
+        }
+      },
+      topping: 'Topping'
+    }
   })
   .process('## Contributors')

Yields:

| Name          | Age  | Topping    |
| ------------- | ---- | ---------- |
| **Jane Doe**  | *31* | Mozzarella |
| **John Doe**  | *29* | Olive      |
| **Mona Lisa** | *3*  | Pineapple  |

👉 Note: observe that the labels of Age and Topping are now cased, and that the age values are now wrapped in emphasis.

Types

This package is fully typed with TypeScript. It exports the additional types Contributor, ContributorObject, Format, Formatter, FormatterObject, Formatters, 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-contributors@^7, compatible with Node.js 16.

This plugin works with unified version 6+ and remark version 7+.

Security

options.contributors (or contributors in package.json) is used and injected into the tree when given or found. Data in those lists is formatted by options.formatters. If a user has access to either, this could open you up to a cross-site scripting (XSS) attack.

This may become a problem if the markdown is later transformed to rehype (hast) or opened in an unsafe markdown viewer.

Related

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 Website
Hugh Kennedy https://hughsk.io
Titus Wormer https://wooorm.com
Vincent Weevers https://vincentweevers.nl
Nick Baugh https://niftylettuce.com

License

MIT © Hugh Kennedy

remark-contributors's People

Contributors

hughsk avatar niftylettuce avatar nnmrts avatar pke avatar vweevers avatar wooorm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

remark-contributors's Issues

Missing required `path` on `file` / `file.dirname` is undefined

A file object in v5.0.0 looks like this:

file VFile {
  data: {
    remarkValidateLinksReferences: {},
    remarkValidateLinksLandmarks: { '': [Object] }
  },
  messages: [],
  history: [],
  cwd: '/Users/jack/Projects/lad.sh',
  contents: <Buffer 23 20 51 75 69 63 6b 20 53 74 61 72 74 0a 0a 57 65 20 73 74 72 69 63 74 6c 79 20 73 75 70 70 6f 72 74 20 4d 61 63 20 61 6e 64 20 55 62 75 6e 74 75 2d ... 2130 more bytes>
}

As you can see, it does not contain a file.dirname property, that your new commit in v5.0.0 is referencing here dafb61c#diff-168726dbe96b3ce427e7fedce31bb0bcR26.

Therefore an exception will be thrown like this:

[03:40:31] TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received undefined
    at validateString (internal/validators.js:117:11)
    at Object.resolve (path.js:980:7)
    at transform (/Users/jack/Projects/lad.sh/node_modules/remark-contributors/index.js:26:39)
    at wrapped (/Users/jack/Projects/lad.sh/node_modules/trough/wrap.js:25:19)
    at next (/Users/jack/Projects/lad.sh/node_modules/trough/index.js:57:24)
    at done (/Users/jack/Projects/lad.sh/node_modules/trough/wrap.js:55:16)
    at then (/Users/jack/Projects/lad.sh/node_modules/trough/wrap.js:62:5)
    at wrapped (/Users/jack/Projects/lad.sh/node_modules/trough/wrap.js:45:9)
    at next (/Users/jack/Projects/lad.sh/node_modules/trough/index.js:57:24)
    at done (/Users/jack/Projects/lad.sh/node_modules/trough/wrap.js:55:16)
    at then (/Users/jack/Projects/lad.sh/node_modules/trough/wrap.js:62:5)
    at wrapped (/Users/jack/Projects/lad.sh/node_modules/trough/wrap.js:45:9)
    at next (/Users/jack/Projects/lad.sh/node_modules/trough/index.js:57:24)
    at done (/Users/jack/Projects/lad.sh/node_modules/trough/wrap.js:55:16)
    at then (/Users/jack/Projects/lad.sh/node_modules/trough/wrap.js:62:5)
    at wrapped (/Users/jack/Projects/lad.sh/node_modules/trough/wrap.js:45:9)

This logic also does not check if there's a package.json in the root of the repository.

Thanks @wooorm just let me know when it's fixed/released.

Add `heading` option to match custom headings

Subject of the feature

Add a simple match option, so one can match any other heading than the english word "contributors".

Problem

Currently you can't use remark-contributors on multilingual (or just any other language than english) readmes. This would fix it, but probably other use cases exist as well. For example, one could prefer a heading like "Contributors Table" or "Contributing People".

Expected behavior

The regular expression passed to this option should determine the heading under which remark-contributors generates the contributors info.

Alternatives

The only alternative solution to this would be to use your own plugin, which is what I considered at first. But I think this can't be a just a "me-issue".

Inspired by remarkjs/remark-license#12.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.