remark-github
Advanced tools
Comparing version 10.1.0 to 11.0.0
269
index.js
@@ -1,25 +0,25 @@ | ||
'use strict' | ||
/** | ||
* @typedef {import('mdast').Root} Root | ||
* | ||
* @typedef Options | ||
* Configuration. | ||
* @property {boolean} [mentionStrong=true] | ||
* Wrap mentions in `<strong>`, true by default. | ||
* This makes them render more like how GitHub styles them. | ||
* But GitHub itself uses CSS instead of a strong. | ||
* @property {string} [repository] | ||
* Repository to link against. | ||
*/ | ||
var visit = require('unist-util-visit') | ||
var toString = require('mdast-util-to-string') | ||
var findAndReplace = require('mdast-util-find-and-replace') | ||
import fs from 'node:fs' | ||
import process from 'node:process' | ||
import path from 'node:path' | ||
import {visit} from 'unist-util-visit' | ||
import {toString} from 'mdast-util-to-string' | ||
import {findAndReplace} from 'mdast-util-find-and-replace' | ||
module.exports = github | ||
// Hide process use from browserify and the like. | ||
var proc = typeof global !== 'undefined' && global.process | ||
// Load `fs` and `path` if available. | ||
var fs | ||
var path | ||
try { | ||
fs = require('fs') | ||
path = require('path') | ||
} catch (_) {} | ||
// Previously, GitHub linked `@mention` and `@mentions` to their blog post about | ||
// mentions (<https://github.com/blog/821>). | ||
// Since June 2019, and possibly earlier, they stopped linking those references. | ||
var denyMention = ['mention', 'mentions'] | ||
const denyMention = new Set(['mention', 'mentions']) | ||
@@ -41,6 +41,12 @@ // Denylist of SHAs that are also valid words. | ||
// <https://github.com/remarkjs/remark-github/issues/20>. | ||
var denyHash = ['acceded', 'deedeed', 'defaced', 'effaced', 'fabaceae'] | ||
const denyHash = new Set([ | ||
'acceded', | ||
'deedeed', | ||
'defaced', | ||
'effaced', | ||
'fabaceae' | ||
]) | ||
// Constants. | ||
var minShaLength = 7 | ||
const minShaLength = 7 | ||
@@ -51,7 +57,7 @@ // Username may only contain alphanumeric characters or single hyphens, and | ||
// \* That is: until <https://github.com/remarkjs/remark-github/issues/13>. | ||
var userGroup = '[\\da-z][-\\da-z]{0,38}' | ||
var projectGroup = '(?:\\.git[\\w-]|\\.(?!git)|[\\w-])+' | ||
var repoGroup = '(' + userGroup + ')\\/(' + projectGroup + ')' | ||
const userGroup = '[\\da-z][-\\da-z]{0,38}' | ||
const projectGroup = '(?:\\.git[\\w-]|\\.(?!git)|[\\w-])+' | ||
const repoGroup = '(' + userGroup + ')\\/(' + projectGroup + ')' | ||
var linkRegex = new RegExp( | ||
const linkRegex = new RegExp( | ||
'^https?:\\/\\/github\\.com\\/' + | ||
@@ -63,3 +69,3 @@ repoGroup + | ||
var repoRegex = new RegExp( | ||
const repoRegex = new RegExp( | ||
'(?:^|/(?:repos/)?)' + repoGroup + '(?=\\.git|[\\/#@]|$)', | ||
@@ -69,3 +75,3 @@ 'i' | ||
var referenceRegex = new RegExp( | ||
const referenceRegex = new RegExp( | ||
'(' + | ||
@@ -79,3 +85,3 @@ userGroup + | ||
var mentionRegex = new RegExp( | ||
const mentionRegex = new RegExp( | ||
'@(' + userGroup + '(?:\\/' + userGroup + ')?)', | ||
@@ -85,29 +91,47 @@ 'gi' | ||
function github(options) { | ||
var settings = options || {} | ||
var repository = settings.repository | ||
var pkg | ||
/** | ||
* Plugin to enable, disable, and ignore messages. | ||
* | ||
* @type {import('unified').Plugin<[Options?]|void[], Root>} | ||
*/ | ||
export default function remarkGithub(options = {}) { | ||
/** | ||
* @typedef {import('mdast').StaticPhrasingContent} StaticPhrasingContent | ||
* @typedef {import('mdast-util-find-and-replace').ReplaceFunction} ReplaceFunction | ||
* @typedef {import('type-fest').PackageJson} PackageJson | ||
* @typedef {{input: string, index: number}} Match | ||
*/ | ||
let repository = options.repository | ||
/** @type {PackageJson|undefined} */ | ||
let pkg | ||
// Get the repository from `package.json`. | ||
if (!repository) { | ||
try { | ||
pkg = JSON.parse(fs.readFileSync(path.join(proc.cwd(), 'package.json'))) | ||
} catch (_) {} | ||
pkg = JSON.parse( | ||
String(fs.readFileSync(path.join(process.cwd(), 'package.json'))) | ||
) | ||
} catch {} | ||
repository = | ||
pkg && pkg.repository ? pkg.repository.url || pkg.repository : '' | ||
pkg && pkg.repository | ||
? // Object form. | ||
/* c8 ignore next 2 */ | ||
typeof pkg.repository === 'object' | ||
? pkg.repository.url | ||
: pkg.repository | ||
: '' | ||
} | ||
// Parse the URL: See the tests for all possible kinds. | ||
repository = repoRegex.exec(repository) | ||
const repositoryMatch = repoRegex.exec(repository || '') | ||
if (!repository) { | ||
if (!repositoryMatch) { | ||
throw new Error('Missing `repository` field in `options`') | ||
} | ||
repository = {user: repository[1], project: repository[2]} | ||
const repositoryInfo = {user: repositoryMatch[1], project: repositoryMatch[2]} | ||
return transformer | ||
function transformer(tree) { | ||
return (tree) => { | ||
findAndReplace( | ||
@@ -123,12 +147,57 @@ tree, | ||
) | ||
visit(tree, 'link', visitor) | ||
visit(tree, 'link', (node) => { | ||
const link = parse(node) | ||
if (!link) { | ||
return | ||
} | ||
const comment = link.comment ? ' (comment)' : '' | ||
/** @type {string} */ | ||
let base | ||
if (link.project !== repositoryInfo.project) { | ||
base = link.user + '/' + link.project | ||
} else if (link.user === repositoryInfo.user) { | ||
base = '' | ||
} else { | ||
base = link.user | ||
} | ||
/** @type {StaticPhrasingContent[]} */ | ||
const children = [] | ||
if (link.page === 'commit') { | ||
if (base) { | ||
children.push({type: 'text', value: base + '@'}) | ||
} | ||
children.push({type: 'inlineCode', value: abbr(link.reference)}) | ||
if (link.comment) { | ||
children.push({type: 'text', value: comment}) | ||
} | ||
} else { | ||
base += '#' | ||
children.push({ | ||
type: 'text', | ||
value: base + abbr(link.reference) + comment | ||
}) | ||
} | ||
node.children = children | ||
}) | ||
} | ||
/** | ||
* @type {ReplaceFunction} | ||
* @param {string} value | ||
* @param {string} username | ||
* @param {Match} match | ||
*/ | ||
function replaceMention(value, username, match) { | ||
var node | ||
if ( | ||
/[\w`]/.test(match.input.charAt(match.index - 1)) || | ||
/[/\w`]/.test(match.input.charAt(match.index + value.length)) || | ||
denyMention.indexOf(username) !== -1 | ||
denyMention.has(username) | ||
) { | ||
@@ -138,5 +207,6 @@ return false | ||
node = {type: 'text', value: value} | ||
/** @type {StaticPhrasingContent} */ | ||
let node = {type: 'text', value} | ||
if (settings.mentionStrong !== false) { | ||
if (options.mentionStrong !== false) { | ||
node = {type: 'strong', children: [node]} | ||
@@ -153,2 +223,8 @@ } | ||
/** | ||
* @type {ReplaceFunction} | ||
* @param {string} value | ||
* @param {string} no | ||
* @param {Match} match | ||
*/ | ||
function replaceIssue(value, no, match) { | ||
@@ -167,11 +243,16 @@ if ( | ||
'https://github.com/' + | ||
repository.user + | ||
repositoryInfo.user + | ||
'/' + | ||
repository.project + | ||
repositoryInfo.project + | ||
'/issues/' + | ||
no, | ||
children: [{type: 'text', value: value}] | ||
children: [{type: 'text', value}] | ||
} | ||
} | ||
/** | ||
* @type {ReplaceFunction} | ||
* @param {string} value | ||
* @param {Match} match | ||
*/ | ||
function replaceHash(value, match) { | ||
@@ -181,3 +262,3 @@ if ( | ||
/\w/.test(match.input.charAt(match.index + value.length)) || | ||
denyHash.indexOf(value) !== -1 | ||
denyHash.has(value) | ||
) { | ||
@@ -192,5 +273,5 @@ return false | ||
'https://github.com/' + | ||
repository.user + | ||
repositoryInfo.user + | ||
'/' + | ||
repository.project + | ||
repositoryInfo.project + | ||
'/commit/' + | ||
@@ -202,5 +283,14 @@ value, | ||
/** | ||
* @type {ReplaceFunction} | ||
* @param {string} $0 | ||
* @param {string} user | ||
* @param {string} project | ||
* @param {string} no | ||
* @param {string} sha | ||
* @param {Match} match | ||
*/ | ||
// eslint-disable-next-line max-params | ||
function replaceReference($0, user, project, no, sha, match) { | ||
var value = '' | ||
var nodes | ||
let value = '' | ||
@@ -214,9 +304,10 @@ if ( | ||
nodes = [] | ||
/** @type {StaticPhrasingContent[]} */ | ||
const nodes = [] | ||
if (user !== repository.user) { | ||
if (user !== repositoryInfo.user) { | ||
value += user | ||
} | ||
if (project && project !== repository.project) { | ||
if (project && project !== repositoryInfo.project) { | ||
value = user + '/' + project | ||
@@ -232,3 +323,3 @@ } | ||
nodes.unshift({type: 'text', value: value}) | ||
nodes.unshift({type: 'text', value}) | ||
@@ -242,3 +333,3 @@ return { | ||
'/' + | ||
(project || repository.project) + | ||
(project || repositoryInfo.project) + | ||
'/' + | ||
@@ -251,45 +342,10 @@ (no ? 'issues' : 'commit') + | ||
} | ||
function visitor(node) { | ||
var link = parse(node) | ||
var children | ||
var base | ||
var comment | ||
if (!link) { | ||
return | ||
} | ||
comment = link.comment ? ' (comment)' : '' | ||
if (link.project !== repository.project) { | ||
base = link.user + '/' + link.project | ||
} else if (link.user === repository.user) { | ||
base = '' | ||
} else { | ||
base = link.user | ||
} | ||
if (link.page === 'commit') { | ||
children = [] | ||
if (base) { | ||
children.push({type: 'text', value: base + '@'}) | ||
} | ||
children.push({type: 'inlineCode', value: abbr(link.reference)}) | ||
if (link.comment) { | ||
children.push({type: 'text', value: comment}) | ||
} | ||
} else { | ||
base += '#' | ||
children = [{type: 'text', value: base + abbr(link.reference) + comment}] | ||
} | ||
node.children = children | ||
} | ||
} | ||
// Abbreviate a SHA. | ||
/** | ||
* Abbreviate a SHA. | ||
* | ||
* @param {string} sha | ||
* @returns {string} | ||
*/ | ||
function abbr(sha) { | ||
@@ -299,6 +355,11 @@ return sha.slice(0, minShaLength) | ||
// Parse a link and determine whether it links to GitHub. | ||
/** | ||
* Parse a link and determine whether it links to GitHub. | ||
* | ||
* @param {import('mdast').Link} node | ||
* @returns {{user: string, project: string, page: string, reference: string, comment: boolean}|undefined} | ||
*/ | ||
function parse(node) { | ||
var url = node.url || '' | ||
var match = linkRegex.exec(url) | ||
const url = node.url || '' | ||
const match = linkRegex.exec(url) | ||
@@ -305,0 +366,0 @@ if ( |
{ | ||
"name": "remark-github", | ||
"version": "10.1.0", | ||
"version": "11.0.0", | ||
"description": "remark plugin to autolink references like in GitHub issues, PRs, and comments", | ||
@@ -35,42 +35,39 @@ "license": "MIT", | ||
], | ||
"types": "types/index.d.ts", | ||
"sideEffects": false, | ||
"type": "module", | ||
"main": "index.js", | ||
"types": "index.d.ts", | ||
"files": [ | ||
"types/index.d.ts", | ||
"index.d.ts", | ||
"index.js" | ||
], | ||
"dependencies": { | ||
"mdast-util-find-and-replace": "^1.0.0", | ||
"mdast-util-to-string": "^1.0.0", | ||
"unist-util-visit": "^2.0.0" | ||
"@types/mdast": "^3.0.0", | ||
"mdast-util-find-and-replace": "^2.0.0", | ||
"mdast-util-to-string": "^3.0.0", | ||
"unified": "^10.0.0", | ||
"unist-util-visit": "^4.0.0" | ||
}, | ||
"devDependencies": { | ||
"browserify": "^17.0.0", | ||
"dtslint": "^3.0.0", | ||
"nyc": "^15.0.0", | ||
"@types/tape": "^4.0.0", | ||
"c8": "^7.0.0", | ||
"prettier": "^2.0.0", | ||
"remark": "^13.0.0", | ||
"remark-cli": "^9.0.0", | ||
"remark-gfm": "^1.0.0", | ||
"remark": "^14.0.0", | ||
"remark-cli": "^10.0.0", | ||
"remark-gfm": "^2.0.0", | ||
"remark-preset-wooorm": "^8.0.0", | ||
"rimraf": "^3.0.0", | ||
"tape": "^5.0.0", | ||
"tinyify": "^3.0.0", | ||
"unified": "^9.0.0", | ||
"xo": "^0.37.0" | ||
"type-coverage": "^2.0.0", | ||
"type-fest": "^2.0.0", | ||
"typescript": "^4.0.0", | ||
"xo": "^0.43.0" | ||
}, | ||
"scripts": { | ||
"build": "rimraf \"test/**/*.d.ts\" \"*.d.ts\" && tsc && type-coverage", | ||
"format": "remark . -qfo --ignore-pattern test/ && prettier . -w --loglevel warn && xo --fix", | ||
"build-bundle": "browserify . -s remarkGitHub > remark-github.js", | ||
"build-mangle": "browserify . -s remarkGitHub -p tinyify > remark-github.min.js", | ||
"build": "npm run build-bundle && npm run build-mangle", | ||
"test-api": "node test", | ||
"test-coverage": "nyc --reporter lcov tape test/index.js", | ||
"test-types": "dtslint types", | ||
"test": "npm run format && npm run build && npm run test-coverage && npm run test-types" | ||
"test-api": "node --conditions development test/index.js", | ||
"test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov npm run test-api", | ||
"test": "npm run build && npm run format && npm run test-coverage" | ||
}, | ||
"nyc": { | ||
"check-coverage": true, | ||
"lines": 100, | ||
"functions": 100, | ||
"branches": 100 | ||
}, | ||
"prettier": { | ||
@@ -85,13 +82,3 @@ "tabWidth": 2, | ||
"xo": { | ||
"prettier": true, | ||
"esnext": false, | ||
"rules": { | ||
"complexity": "off", | ||
"max-params": "off", | ||
"unicorn/prefer-optional-catch-binding": "off", | ||
"unicorn/prefer-includes": "off" | ||
}, | ||
"ignores": [ | ||
"remark-github.js" | ||
] | ||
"prettier": true | ||
}, | ||
@@ -102,3 +89,9 @@ "remarkConfig": { | ||
] | ||
}, | ||
"typeCoverage": { | ||
"atLeast": 100, | ||
"detail": true, | ||
"strict": true, | ||
"ignoreCatch": true | ||
} | ||
} |
@@ -24,2 +24,5 @@ # remark-github | ||
This package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c): | ||
Node 12+ is needed to use it and it must be `import`ed instead of `require`d. | ||
[npm][]: | ||
@@ -56,13 +59,15 @@ | ||
And our script, `example.js`, looks as follows: | ||
And our module, `example.js`, looks as follows: | ||
```js | ||
var vfile = require('to-vfile') | ||
var remark = require('remark') | ||
var github = require('remark-github') | ||
import {readSync} from 'to-vfile' | ||
import {remark} from 'remark' | ||
import remarkGithub from 'remark-github' | ||
const file = readSync('example.md') | ||
remark() | ||
.use(github) | ||
.process(vfile.readSync('example.md'), function (err, file) { | ||
if (err) throw err | ||
.use(remarkGithub) | ||
.process(file) | ||
.then((file) => { | ||
console.log(String(file)) | ||
@@ -97,4 +102,7 @@ }) | ||
### `remark.use(github[, options])` | ||
This package exports no identifiers. | ||
The default export is `remarkGithub`. | ||
### `unified().use(remarkGithub[, options])` | ||
Automatically link references to commits, issues, pull-requests, and users, like | ||
@@ -101,0 +109,0 @@ in GitHub issues, PRs, and comments (see |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
20641
354
223
1
Yes
5
13
1
+ Added@types/mdast@^3.0.0
+ Addedunified@^10.0.0
+ Added@types/mdast@3.0.15(transitive)
+ Addedbail@2.0.2(transitive)
+ Addedescape-string-regexp@5.0.0(transitive)
+ Addedextend@3.0.2(transitive)
+ Addedis-buffer@2.0.5(transitive)
+ Addedis-plain-obj@4.1.0(transitive)
+ Addedmdast-util-find-and-replace@2.2.2(transitive)
+ Addedmdast-util-to-string@3.2.0(transitive)
+ Addedtrough@2.2.0(transitive)
+ Addedunified@10.1.2(transitive)
+ Addedunist-util-is@5.2.1(transitive)
+ Addedunist-util-stringify-position@3.0.3(transitive)
+ Addedunist-util-visit@4.1.2(transitive)
+ Addedunist-util-visit-parents@5.1.3(transitive)
+ Addedvfile@5.3.7(transitive)
+ Addedvfile-message@3.1.4(transitive)
- Removedescape-string-regexp@4.0.0(transitive)
- Removedmdast-util-find-and-replace@1.1.1(transitive)
- Removedmdast-util-to-string@1.1.0(transitive)
- Removedunist-util-is@4.1.0(transitive)
- Removedunist-util-visit@2.0.3(transitive)
- Removedunist-util-visit-parents@3.1.1(transitive)
Updatedmdast-util-to-string@^3.0.0
Updatedunist-util-visit@^4.0.0