Skip to content

Commit

Permalink
Merge pull request #2959 from sass/auto-tocs
Browse files Browse the repository at this point in the history
Add a tool for automatically generating/updating TOCs
  • Loading branch information
nex3 committed Nov 24, 2020
2 parents f1b9f9f + 3515086 commit f1c32a8
Show file tree
Hide file tree
Showing 8 changed files with 602 additions and 393 deletions.
8 changes: 4 additions & 4 deletions accepted/forward-with.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@

## Table of Contents

- [Background](#background)
- [Summary](#summary)
- [Syntax](#syntax)
- [Semantics](#semantics)
* [Background](#background)
* [Summary](#summary)
* [Syntax](#syntax)
* [Semantics](#semantics)

## Background

Expand Down
804 changes: 488 additions & 316 deletions package-lock.json

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
"repository. For the official Sass npm package, see ",
"https://npmjs.org/package/sass"
],
"engines": {
"node": ">=1.14.0 <2.0.0"
},
"dependencies": {
"colors": "^1.3.3",
"diff": "^4.0.1",
Expand All @@ -12,11 +15,11 @@
"markdown-toc": "^1.2.0"
},
"devDependencies": {
"standard": "^14.0.0"
"standard": "^14.3.4"
},
"scripts": {
"link-check": "node test/link-check.js",
"toc-check": "node test/toc-check.js",
"link-check": "node test/link-check.mjs",
"toc-check": "node test/toc-check.mjs",
"test": "standard && npm run toc-check && npm run link-check"
}
}
19 changes: 9 additions & 10 deletions test/link-check.js → test/link-check.mjs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
'use strict'

var colors = require('colors/safe')
var fs = require('fs')
var glob = require('glob')
var toc = require('markdown-toc')
var urlModule = require('url')
var markdownLinkCheck = require('markdown-link-check')
var path = require('path')
import colors from 'colors/safe.js'
import * as fs from 'fs'
import glob from 'glob'
import toc from 'markdown-toc'
import * as urlModule from 'url'
import markdownLinkCheck from 'markdown-link-check'
import * as path from 'path'

var files = glob.sync('**/*.md', { ignore: ['node_modules/**/*.md'] })

Expand All @@ -26,8 +24,9 @@ function getToc (file) {
files.forEach(function (file) {
var markdown = fs.readFileSync(file).toString()

var dirname = path.dirname(urlModule.fileURLToPath(import.meta.url))
markdownLinkCheck(markdown, {
baseUrl: path.basename(__dirname) + '/'
baseUrl: path.basename(dirname) + '/'
}, function (err, results) {
if (err) {
console.error('Error', err)
Expand Down
60 changes: 0 additions & 60 deletions test/toc-check.js

This file was deleted.

30 changes: 30 additions & 0 deletions test/toc-check.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import colors from 'colors/safe.js'
import diff from 'diff'
import * as fs from 'fs'

import * as toc from '../tool/src/toc.mjs'

toc.files.forEach(function (file) {
var markdown = fs.readFileSync(file).toString()
console.log('Reading: ' + file)

var currentToc = toc.getCurrent(markdown)
if (currentToc == null) {
console.log(colors.yellow("File doesn't have a table of contents"))
return
}

var generatedToc = toc.generate(markdown)
if (currentToc === generatedToc) return

var tocDiff = diff.diffLines(currentToc, generatedToc)
tocDiff.forEach(function (part) {
var color = part.added
? colors.green
: (part.removed ? colors.red : colors.grey)
process.stderr.write(color(part.value))
})
process.stderr.write('\n')

process.exitCode = 1
})
36 changes: 36 additions & 0 deletions tool/src/toc.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import glob from 'glob'
import markdownToc from 'markdown-toc'

/// Files that may contain tables of contents.
export const files = glob.sync('**/*.md', {
ignore: ['node_modules/**/*.md', '**/*.changes.md']
})

// Returns the index of the first `*` in `markdown`'s table of contents, or
// `null` if `markdown` doesn't include a table of contents.
function findStartIndex (markdown) {
var match = markdown.match(/\n## Table of Contents\n/)
if (match == null) return null
return match.index + match[0].length - 1
}

// Returns the table of contents in `markdown` if it contains one, or `null`
// otherwise.
export function getCurrent (markdown) {
var startIndex = findStartIndex(markdown)
if (startIndex == null) return null

var endIndex = markdown.indexOf('## ', startIndex) - 1
if (endIndex < 0) return null

return markdown.substring(startIndex, endIndex).trim()
}

/// Returns the expected table of contents for `markdown`.
export function generate (markdown) {
return markdownToc(markdown, {
filter: (string, _, __) => string.indexOf('Table of Contents') === -1,
firsth1: false,
bullets: '*'
}).content
}
29 changes: 29 additions & 0 deletions tool/update-toc.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import * as toc from './src/toc.mjs'
import * as fs from 'fs'

toc.files.forEach(function (file) {
var markdown = fs.readFileSync(file).toString()

var currentToc = toc.getCurrent(markdown)
if (currentToc == null) {
var match = markdown.match('## Table of Contents\n\n')
if (!match) return

var tocLocation = match.index + match[0].length

// If there's an empty TOC, fill it in.
fs.writeFileSync(
file,
markdown.substring(0, tocLocation) +
toc.generate(markdown) + '\n\n' +
markdown.substring(tocLocation))
console.log(`Added TOC to ${file}`)
return
}

var generatedToc = toc.generate(markdown)
if (currentToc === generatedToc) return

fs.writeFileSync(file, markdown.replace(currentToc, generatedToc))
console.log(`Updated TOC in ${file}`)
})

0 comments on commit f1c32a8

Please sign in to comment.