Skip to content

Commit

Permalink
feat: sync packageDocumentation between index.ts and README.md (#1398)
Browse files Browse the repository at this point in the history
Adds a typedoc plugin to extract module comments (e.g. `@packageDocumentation`)
and add them to the README in an `About` section when `npm run docs`
is run.

It will also keep them in sync using the source code as a source of truth.
  • Loading branch information
achingbrain authored Oct 30, 2023
1 parent cf9735f commit 752d2bd
Show file tree
Hide file tree
Showing 11 changed files with 356 additions and 194 deletions.
17 changes: 0 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,10 @@
# aegir <!-- omit in toc -->

[![ipfs.tech](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](https://ipfs.tech)
[![Discuss](https://img.shields.io/discourse/https/discuss.ipfs.tech/posts.svg?style=flat-square)](https://discuss.ipfs.tech)
[![codecov](https://img.shields.io/codecov/c/github/ipfs/aegir.svg?style=flat-square)](https://codecov.io/gh/ipfs/aegir)
[![CI](https://img.shields.io/github/actions/workflow/status/ipfs/aegir/js-test-and-release.yml?branch=master\&style=flat-square)](https://github.com/ipfs/aegir/actions/workflows/js-test-and-release.yml?query=branch%3Amaster)

> JavaScript project management
## Table of contents <!-- omit in toc -->

- [Install](#install)
- [Browser `<script>` tag](#browser-script-tag)
- [Project Structure](#project-structure)
- [CLI](#cli)
- [Configuration](#configuration)
- [Continuous Integration](#continuous-integration)
- [Testing helpers](#testing-helpers)
- [Typescript](#typescript)
- [Release steps](#release-steps)
- [API Docs](#api-docs)
- [License](#license)
- [Contribute](#contribute)

## Install

```console
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,6 @@
"mdast-util-gfm-table": "^2.0.0",
"mdast-util-gfm-task-list-item": "^2.0.0",
"mdast-util-to-markdown": "^2.0.0",
"mdast-util-toc": "^7.0.0",
"merge-options": "^3.0.4",
"micromark-extension-gfm": "^3.0.0",
"micromark-extension-gfm-footnote": "^2.0.0",
Expand Down
123 changes: 69 additions & 54 deletions src/check-project/check-monorepo-readme.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/* eslint-disable complexity */
/* eslint-disable no-console */

import path from 'path'
import fs from 'fs-extra'
import { toc as makeToc } from 'mdast-util-toc'
import { APIDOCS } from './readme/api-docs.js'
import { HEADER } from './readme/header.js'
import { LICENSE } from './readme/license.js'
Expand Down Expand Up @@ -50,105 +50,120 @@ export async function checkMonorepoReadme (projectDir, repoUrl, defaultBranch, p
// create basic readme with heading, CI link, etc
const readme = parseMarkdown(HEADER(pkg, repoOwner, repoName, defaultBranch, ciFile))

// remove existing header, CI link, etc
/** @type {import('mdast').Root} */
const parsedReadme = {
type: 'root',
children: []
}
/** @type {import('mdast').RootContent[]} */
const header = []

/** @type {import('mdast').RootContent[]} */
const other = []

/** @type {import('mdast').RootContent[]} */
const about = []

let structureIndex = -1
let tocIndex = -1
let apiDocsIndex = -1
let licenseFound = false
/** @type {import('mdast').RootContent[]} */
const footer = []

file.children.forEach((child, index) => {
let skipBlockHeader = -1
let inAboutBlock = false
let foundBadges = false

// remove existing header, CI link, etc
file.children.forEach((child) => {
const rendered = writeMarkdown(child).toLowerCase()

if (rendered.includes('https://raw.githubusercontent.com/ipfs/helia/main/assets/helia.png')) {
// skip helia logo
return
if (skipBlockHeader > -1 && child.type === 'heading' && child.depth <= skipBlockHeader) {
skipBlockHeader = -1
inAboutBlock = false
}

if (child.type === 'heading' && (index === 0 || rendered.includes(pkg.name))) {
// skip heading
if (rendered === `> ${pkg.description.toLowerCase()}\n`) {
// skip project description
return
}

if (child.type === 'paragraph' && (index === 1 || rendered.includes('![ci]'))) {
if (child.type === 'paragraph' && rendered.includes('![ci]')) {
// skip badges
foundBadges = true
return
}

if (child.type === 'blockquote' && tocIndex === -1 && tocIndex === -1) {
// skip project overview
if (child.type === 'heading' && rendered.includes('# about')) {
// collect about section
skipBlockHeader = child.depth
inAboutBlock = true
about.push(child)
return
}

if (rendered.includes('## table of')) {
// skip toc header
tocIndex = index
if (child.type === 'heading' && rendered.includes('# packages')) {
// skip packages
skipBlockHeader = child.depth
return
}

if (tocIndex !== -1 && index === tocIndex + 1) {
// skip toc
if (child.type === 'heading' && rendered.includes('# api docs')) {
// skip api docs
skipBlockHeader = child.depth
return
}

if (child.type === 'heading' && rendered.includes('structure')) {
// skip structure header
structureIndex = index
if (child.type === 'heading' && rendered.includes('# license')) {
// skip license
skipBlockHeader = child.depth
return
}

if (structureIndex !== -1 && index === structureIndex + 1) {
// skip structure
if (child.type === 'heading' && (rendered.includes('# contribute') || rendered.includes('# contribution'))) {
// skip contribute
skipBlockHeader = child.depth
return
}

if (child.type === 'heading' && rendered.includes('api docs')) {
// skip api docs header
apiDocsIndex = index
if (child.type === 'definition') {
footer.push(child)
return
}

if (apiDocsIndex !== -1 && index === apiDocsIndex + 1) {
// skip api docs link
if (inAboutBlock) {
about.push(child)
return
}

if ((child.type === 'heading' && rendered.includes('license')) || licenseFound) {
licenseFound = true
if (!foundBadges) {
header.push(child)
return
}

parsedReadme.children.push(child)
if (skipBlockHeader > -1) {
// skip this block
return
}

other.push(child)
})

const license = parseMarkdown(LICENSE(pkg, repoOwner, repoName, defaultBranch))
const apiDocs = parseMarkdown(APIDOCS(pkg))
const structure = parseMarkdown(STRUCTURE(projectDir, projectDirs))

parsedReadme.children = [
...structure.children,
...parsedReadme.children,
...apiDocs.children,
...license.children
]

const toc = makeToc(parsedReadme, {
tight: true
})
/** @type {import('mdast').Root} */
let apiDocs = {
type: 'root',
children: []
}

if (toc.map == null) {
throw new Error('Could not create TOC for README.md')
if (fs.existsSync(path.join(projectDir, 'typedoc.json')) || pkg.scripts.docs != null) {
apiDocs = parseMarkdown(APIDOCS(pkg))
}

const structure = parseMarkdown(STRUCTURE(projectDir, projectDirs))

readme.children = [
...header,
...readme.children,
toc.map,
...parsedReadme.children
...about,
...structure.children,
...other,
...apiDocs.children,
...license.children,
...footer
]

await ensureFileHasContents(projectDir, 'README.md', writeMarkdown(readme))
Expand Down
Loading

0 comments on commit 752d2bd

Please sign in to comment.