@github/cem-plugin-readme
Version:
A Custom Element Manifest plugin to generate a README for a Web Component
88 lines (70 loc) • 2.4 kB
JavaScript
import {accessSync, readFileSync, writeFileSync} from 'fs'
import {join} from 'path'
function generateInstallationInstructions({packageJson: {name}}) {
return `## Installation
Available on [npm](https://www.npmjs.com/) as [**${name}**](https://www.npmjs.com/package/${name}).
\`\`\`
$ npm install --save ${name}
\`\`\``
}
function generateBrowserSupportInstructions() {
return `## Browser support
Browsers without native [custom element support][support] require a [polyfill][].
- Chrome
- Firefox
- Safari
- Microsoft Edge
[support]: https://caniuse.com/custom-elementsv1
[polyfill]: https://github.com/webcomponents/custom-elements`
}
function generateTitle({packageJson: {name}}) {
const formattedName = name
.split('/')
.at(-1)
.replace(/-element$/, '')
return escapeHTML(`<${formattedName}> element`)
}
function generateImportInstructions({packageJson: {name}}) {
return `### Script
Import as ES modules:
\`\`\`js
import '${name}'
\`\`\`
Include with a script tag:
\`\`\`html
<script type="module" src="./node_modules/${name}/dist/index.js">
\`\`\``
}
function generateLicense() {
return `## License
Distributed under the MIT license. See LICENSE for details.`
}
const escapeHTML = (html) => {
return html.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"').replaceAll("'", ''');
}
export function readme({filename = 'README.md', exclude = [], path = '.', title, preamble, footer} = {}) {
const packageJson = JSON.parse(readFileSync(join(path, 'package.json'), 'utf8'))
return {
name: 'readme',
async packageLinkPhase({customElementsManifest}) {
const content = [
`# ${title || generateTitle({packageJson})}`,
escapeHTML(packageJson.description),
preamble,
generateInstallationInstructions({packageJson}),
`## Usage`,
generateImportInstructions({packageJson}),
]
for (const module of customElementsManifest.modules) {
for (const {name, description} of module.declarations.filter(x => x.customElement)) {
if (exclude.includes(name)) continue
content.push(description.trim())
}
}
content.push(generateBrowserSupportInstructions())
content.push(generateLicense())
content.push(footer)
writeFileSync(filename, content.filter(Boolean).join('\n\n'))
}
}
}