react-markdown-github
Advanced tools
Comparing version
# `react-markdown-github` | ||
### 3.0.0 | ||
- [#4] improving headline ID/anchor rendering to be more GH compliant | ||
- [#5] **BREAKING** Change `resolver` prop to `transformLinkUri` to be consistent with `react-markdown` | ||
- Create prop pass-through to provide props to `react-markdown` | ||
### 2.0.0 | ||
@@ -20,1 +26,6 @@ | ||
- Initial release | ||
[#1]: https://github.com/godaddy/react-markdown-github/pull/1 | ||
[#2]: https://github.com/godaddy/react-markdown-github/pull/2 | ||
[#3]: https://github.com/godaddy/react-markdown-github/pull/3 | ||
[#5]: https://github.com/godaddy/react-markdown-github/pull/5 |
{ | ||
"name": "react-markdown-github", | ||
"description": "React component that renders Markdown similarly to Github's formatting", | ||
"version": "2.0.0", | ||
"main": "lib/index.js", | ||
"browser": "lib/index.js", | ||
"module": "src/index.js", | ||
"version": "3.0.0", | ||
"main": "./lib/index.js", | ||
"browser": "./lib/index.js", | ||
"module": "./src/index.js", | ||
"babel": { | ||
@@ -19,3 +19,3 @@ "plugins": [ | ||
"lint": "eslint-godaddy-react src/*.js test/*.js", | ||
"prepublishOnly": "mkdir -p lib && babel -o lib/index.js src/index.js", | ||
"prepublishOnly": "mkdir -p lib && babel -d ./lib src/*.js", | ||
"pretest": "npm run lint", | ||
@@ -64,5 +64,4 @@ "test": "nyc --reporter=text --reporter=json-summary npm run test:mocha", | ||
"react-markdown": "^3.3.0", | ||
"slugify": "^1.2.9", | ||
"url-parse": "^1.4.0" | ||
} | ||
} |
@@ -21,3 +21,3 @@ # `react-markdown-github` | ||
sourceUri='https://github.mycorp.com/org/component/blob/master/README.md' | ||
resolver={ ({ uri, github, org, repo, filename, filepath }) => { } } | ||
transformLinkUri={ ({ uri, github, org, repo, filename, filepath }) => { } } | ||
transformImageUri={ ({ uri, github, org, repo, filename }) => {} } | ||
@@ -32,3 +32,3 @@ renderers={ code: myCodeFormatter } | ||
resolved relative to this URL. | ||
- `resolver` URL resolver function. To override the URL resolver and point a url | ||
- `transformLinkUri` URL resolver function. To override the URL resolver and point a url | ||
to an alternate location. | ||
@@ -35,0 +35,0 @@ - `transformImageUri` image URL resolver function. Default behavior is to not modify image urls. |
211
src/index.js
@@ -1,208 +0,7 @@ | ||
import React, { Component } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import ReactMarkdown from 'react-markdown'; | ||
import slugify from 'slugify'; | ||
import URL from 'url-parse'; | ||
import ReactMarkdownGithub from './component.js'; | ||
import GithubSlugify from './gh-slugify.js'; | ||
const isHash = /^#/; | ||
/** | ||
* A react component that wraps [react-markdown](react-markdown) that: | ||
* - links all headers with an anchor link. | ||
* - resolves all relative links to absolute Github URLs based on the sourceUri of the document. | ||
* e.g. /foo/bar.md becomes https://github.mycorp.com/org/component/blob/master/foo/bar.md | ||
* - allows the parent component to override the resolved url | ||
* | ||
* @class ReactMarkdownGithub | ||
* @api public | ||
*/ | ||
export default class ReactMarkdownGithub extends Component { | ||
constructor() { | ||
super(...arguments); | ||
this.transformLinkUri = this.transformLinkUri.bind(this); | ||
this.renderHeading = this.renderHeading.bind(this); | ||
this.transformImageUri = this.transformImageUri.bind(this); | ||
this.slugs = {}; | ||
this.state = {}; | ||
} | ||
/** | ||
* Parses url into usable github components. | ||
* @param {String} uri - a valid Github url. | ||
* @returns {Object} { github, org, repo, filename, filepath } | ||
* @api private | ||
*/ | ||
static normalizeGithubUrl(uri) { | ||
const { origin, pathname } = new URL(uri); | ||
const parts = pathname.split('/'); | ||
const [, org, repo] = parts; | ||
const filepath = `/${parts.slice(5).join('/')}`; | ||
const filename = parts[parts.length - 1]; | ||
return { | ||
github: `${origin}/`, | ||
filepath, | ||
filename, | ||
org, | ||
repo | ||
}; | ||
} | ||
/** | ||
* React lifecyle method to ensure that the github url prop is parsed each time | ||
* it is updated. | ||
* @param {Object} nextProps - new component props | ||
* @param {Object} prevState - prior component state | ||
* @returns {Object} returns new state or null if not modified. | ||
* @api private | ||
*/ | ||
static getDerivedStateFromProps({ sourceUri }, prevState) { | ||
if (sourceUri !== prevState.sourceUri) { | ||
return { | ||
sourceUri: sourceUri, | ||
...ReactMarkdownGithub.normalizeGithubUrl(sourceUri) | ||
}; | ||
} | ||
return null; | ||
} | ||
/** | ||
* Converts the passed url until an absolute url. If the passed URL is absolute | ||
* it will be returned unmodified. If the URL is realitive then it will be | ||
* merged with the current `sourceUri` property. | ||
* | ||
* @param {String} uri - absolute or realitive URL. | ||
* @returns {url} - will return a absolute URL. | ||
* @api private | ||
*/ | ||
normalizeLinkUri(uri) { | ||
// Do not attempt to parse "pure" hashes since they | ||
// are not fully qualified URLs by definition. This will | ||
// not work for querystring plus hash, but Github does not | ||
// support querystring so this is by design. | ||
if (isHash.test(uri)) { | ||
return uri; | ||
} | ||
const withinFile = new RegExp(`.?/?${this.state.filename}#(.*)$`, 'i'); | ||
const parsed = new URL(uri, this.props.sourceUri); | ||
const isWithinFile = withinFile.test(uri); | ||
return isWithinFile | ||
? parsed.hash | ||
: parsed.href; | ||
} | ||
/** | ||
* The callback handler from `ReactMarkdown` . | ||
* | ||
* @param {String} uri - Markdown link URL. | ||
* @param {Object} children - Child Elements of the link. | ||
* @param {String} title - link title. | ||
* @returns {url} - will return a absolute URL. | ||
* @api private | ||
*/ | ||
transformLinkUri(uri, children, title) { | ||
const { resolver } = this.props; | ||
const normalized = this.normalizeLinkUri(uri); | ||
const opts = { ...this.state, uri: normalized, children, title }; | ||
return resolver && resolver(opts) || normalized; | ||
} | ||
/** | ||
* The callback handler from `ReactMarkdown` . | ||
* | ||
* @param {String} uri - Markdown image URL. | ||
* @returns {url} - will return a absolute URL. | ||
* @api private | ||
*/ | ||
transformImageUri(uri) { | ||
const { transformImageUri } = this.props; | ||
const opts = { ...this.state, uri }; | ||
return transformImageUri && transformImageUri(opts) || uri; | ||
} | ||
/** | ||
* The callback handler from `ReactMarkdown` . Generates an `A` anchor link | ||
* around the Header text | ||
* | ||
* @param {Object} props - properties passed from `ReactMarkdown` | ||
* @param {Int} props.level - The level of the header to render. used for | ||
* generating <h{1-n}> | ||
* @param {Array} props.children - Array of strings from the heading | ||
* @returns {Component} - A react component for the linked header. | ||
* @api private | ||
*/ | ||
renderHeading(props) { | ||
let title = ''; | ||
props.children.forEach((child) => { | ||
if (child.props && child.props.children) { | ||
title += child.props.children + ' '; | ||
} else { | ||
title += child; | ||
} | ||
}); | ||
const slug = slugify(title, { lower: true }); | ||
let uniqueSlug = slug; | ||
this.slugs[slug] = this.slugs[slug] || 0; | ||
if (this.slugs[slug]) { | ||
uniqueSlug = `${slug}${this.slugs[slug]}`; | ||
} | ||
this.slugs[slug] += 1; | ||
// eslint-disable-next-line react/no-children-prop | ||
return React.createElement(`h${props.level}`, { | ||
id: uniqueSlug, | ||
className: 'headline-primary', | ||
children: <a href={ `#${uniqueSlug}` }> | ||
{ props.children } | ||
</a> | ||
}); | ||
} | ||
/** | ||
* @returns {ReactMarkdown} react tree | ||
* @api private | ||
*/ | ||
render() { | ||
const { className, source, resolver } = this.props; | ||
const renderers = { | ||
heading: this.renderHeading, | ||
...this.props.renderers | ||
}; | ||
return ( | ||
<ReactMarkdown | ||
source={ source } | ||
renderers={ renderers } | ||
className={ className } | ||
resolver={ resolver } | ||
transformLinkUri={ this.transformLinkUri } | ||
transformImageUri={ this.transformImageUri } /> | ||
); | ||
} | ||
} | ||
ReactMarkdownGithub.propTypes = { | ||
/** {source} The Markdown content to be rendered by `ReactMarkdown` */ | ||
source: PropTypes.string, | ||
/** {sourceUri} The absolute url to the Github source document. All | ||
* relative urls will be assumed to be realitve to this file: | ||
* e.g. https://github.mycorp.com/org/component/blob/master/README.md' | ||
*/ | ||
sourceUri: PropTypes.string, | ||
/** {resolver} The callback function executed for each found URL */ | ||
resolver: PropTypes.func, | ||
/** {transformImageUri} The callback function executed for each found image */ | ||
transformImageUri: PropTypes.func, | ||
/** {renderers} the collection of resolvers to pass to `ReactMarkdown` */ | ||
renderers: PropTypes.object, | ||
/** {className} the css class to to pass to `ReactMarkdown` */ | ||
className: PropTypes.string | ||
export { | ||
ReactMarkdownGithub, | ||
GithubSlugify | ||
}; |
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
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
43378
31.69%4
-20%16
60%878
32.43%2
Infinity%- Removed
- Removed