From 4fdcf45186fc75f9c547f73d460755a4a182e386 Mon Sep 17 00:00:00 2001 From: Titus Date: Mon, 26 Apr 2021 09:44:02 +0200 Subject: [PATCH] Use ESM Closes GH-71. Reviewed-by: Christian Murphy Reviewed-by: Jonathan Haines --- .gitignore | 3 -- example.js | 15 ++++++---- index.js | 4 +-- lib/contents.js | 36 ++++++++++------------- lib/index.js | 38 ++++++++++++------------- lib/search.js | 42 +++++++++++++-------------- lib/to-expression.js | 6 +--- package.json | 51 ++++++++++++++------------------- readme.md | 16 +++++++---- test/index.js | 68 +++++++++++++++++++++----------------------- 10 files changed, 129 insertions(+), 150 deletions(-) diff --git a/.gitignore b/.gitignore index 2b7fb28..d9b991a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,4 @@ .DS_Store *.log -.nyc_output/ coverage/ node_modules/ -mdast-util-toc.js -mdast-util-toc.min.js diff --git a/example.js b/example.js index 91a81db..64509a7 100644 --- a/example.js +++ b/example.js @@ -1,16 +1,19 @@ +// remark-usage-ignore-next +import {inspect} from 'util' + // Dependencies: -var u = require('unist-builder') -var toc = require('.') +import {u} from 'unist-builder' +import {toc} from './index.js' -// Given a mdast tree: -var tree = u('root', [ +// Now running: +const tree = u('root', [ u('heading', {depth: 1}, [u('text', 'Alpha')]), u('heading', {depth: 2}, [u('text', 'Bravo')]), u('heading', {depth: 3}, [u('text', 'Charlie')]), u('heading', {depth: 2}, [u('text', 'Delta')]) ]) -var table = toc(tree) +const table = toc(tree) // Yields: -console.log('javascript', require('util').inspect(table, {depth: 3})) +console.log('javascript', inspect(table, {depth: 3})) diff --git a/index.js b/index.js index 3541ac5..00b97e7 100644 --- a/index.js +++ b/index.js @@ -1,3 +1 @@ -'use strict' - -module.exports = require('./lib') +export {toc} from './lib/index.js' diff --git a/lib/contents.js b/lib/contents.js index f97c275..f556d47 100644 --- a/lib/contents.js +++ b/lib/contents.js @@ -1,14 +1,10 @@ -'use strict' - -var extend = require('extend') - -module.exports = contents +import extend from 'extend' // Transform a list of heading objects to a markdown list. -function contents(map, tight, prefix, ordered) { - var table = {type: 'list', ordered: ordered, spread: false, children: []} - var minDepth = Number.POSITIVE_INFINITY - var index = -1 +export function contents(map, tight, prefix, ordered) { + const table = {type: 'list', ordered, spread: false, children: []} + let minDepth = Number.POSITIVE_INFINITY + let index = -1 // Find minimum depth. while (++index < map.length) { @@ -35,11 +31,11 @@ function contents(map, tight, prefix, ordered) { } // Insert an entry into `parent`. +// eslint-disable-next-line max-params function insert(entry, parent, tight, prefix, ordered) { - var siblings = parent.children - var tail = siblings[siblings.length - 1] - var index = -1 - var item + const siblings = parent.children + const tail = siblings[siblings.length - 1] + let index = -1 if (entry.depth === 1) { siblings.push({ @@ -65,13 +61,13 @@ function insert(entry, parent, tight, prefix, ordered) { entry.depth-- insert(entry, tail, tight, prefix, ordered) } else if (parent.type === 'list') { - item = {type: 'listItem', spread: false, children: []} + const item = {type: 'listItem', spread: false, children: []} siblings.push(item) insert(entry, item, tight, prefix, ordered) } else { - item = { + const item = { type: 'list', - ordered: ordered, + ordered, spread: false, children: [] } @@ -95,8 +91,8 @@ function insert(entry, parent, tight, prefix, ordered) { } function all(children) { - var result = [] - var index = -1 + let result = [] + let index = -1 if (children) { while (++index < children.length) { @@ -108,8 +104,6 @@ function all(children) { } function one(node) { - var copy - if ( node.type === 'link' || node.type === 'linkReference' || @@ -119,7 +113,7 @@ function one(node) { return all(node.children) } - copy = extend({}, node) + let copy = extend({}, node) delete copy.children delete copy.position diff --git a/lib/index.js b/lib/index.js index 2b7fcd0..b5502dd 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,29 +1,27 @@ -'use strict' - -module.exports = toc - -var search = require('./search') -var contents = require('./contents') -var toExpression = require('./to-expression') +import {search} from './search.js' +import {contents} from './contents.js' +import {toExpression} from './to-expression.js' // Get a TOC representation of `node`. -function toc(node, options) { - var settings = options || {} - var heading = settings.heading ? toExpression(settings.heading) : null - var result = search(node, heading, settings) +export function toc(node, options) { + const settings = options || {} + const heading = settings.heading ? toExpression(settings.heading) : null + const result = search(node, heading, settings) - result.map = result.map.length - ? contents( - result.map, - settings.tight, - settings.prefix, - settings.ordered || false - ) - : null + result.map = + result.map.length > 0 + ? contents( + result.map, + settings.tight, + settings.prefix, + settings.ordered || false + ) + : null // No given heading. if (!heading) { - result.endIndex = result.index = null + result.endIndex = null + result.index = null } return result diff --git a/lib/search.js b/lib/search.js index e75152a..55e7e23 100644 --- a/lib/search.js +++ b/lib/search.js @@ -1,21 +1,19 @@ -'use strict' +import Slugger from 'github-slugger' +import toString from 'mdast-util-to-string' +import {visit} from 'unist-util-visit' +import {convert} from 'unist-util-is' +import {toExpression} from './to-expression.js' -module.exports = search - -var toString = require('mdast-util-to-string') -var visit = require('unist-util-visit') -var convert = require('unist-util-is/convert') -var slugs = require('github-slugger')() -var toExpression = require('./to-expression') +const slugs = new Slugger() // Search a node for a location. -function search(root, expression, settings) { - var skip = settings.skip && toExpression(settings.skip) - var parents = convert(settings.parents || root) - var map = [] - var index - var endIndex - var opening +export function search(root, expression, settings) { + const skip = settings.skip && toExpression(settings.skip) + const parents = convert(settings.parents || root) + const map = [] + let index + let endIndex + let opening slugs.reset() @@ -25,16 +23,18 @@ function search(root, expression, settings) { return { index: index || -1, + // + // eslint-disable-next-line unicorn/explicit-length-check endIndex: index ? endIndex || root.children.length : -1, - map: map + map } function onheading(node, position, parent) { - var value = toString(node) - /* istanbul ignore next - to do: remove this when `remark-attr` is up to - * date w/ micromark. */ - var id = node.data && node.data.hProperties && node.data.hProperties.id - var slug = slugs.slug(id || value) + const value = toString(node) + // Remove this when `remark-attr` is up to date w/ micromark. + /* c8 ignore next */ + const id = node.data && node.data.hProperties && node.data.hProperties.id + const slug = slugs.slug(id || value) if (!parents(parent)) { return diff --git a/lib/to-expression.js b/lib/to-expression.js index 6c4b9d6..0075b76 100644 --- a/lib/to-expression.js +++ b/lib/to-expression.js @@ -1,8 +1,4 @@ -'use strict' - -module.exports = toExpression - // Transform a string into an applicable expression. -function toExpression(value) { +export function toExpression(value) { return new RegExp('^(' + value + ')$', 'i') } diff --git a/package.json b/package.json index d1c9d6d..9f2263a 100644 --- a/package.json +++ b/package.json @@ -25,10 +25,13 @@ "Titus Wormer (https://wooorm.com)", "Jonathan Haines (https://barrythepenguin.github.io)" ], + "sideEffects": false, + "type": "module", + "main": "index.js", "types": "types/index.d.ts", "files": [ "types/index.d.ts", - "lib", + "lib/", "index.js" ], "dependencies": { @@ -37,13 +40,12 @@ "extend": "^3.0.2", "github-slugger": "^1.2.1", "mdast-util-to-string": "^2.0.0", - "unist-util-is": "^4.0.0", - "unist-util-visit": "^2.0.0" + "unist-util-is": "^5.0.0", + "unist-util-visit": "^3.0.0" }, "devDependencies": { - "browserify": "^17.0.0", + "c8": "^7.0.0", "dtslint": "^4.0.0", - "nyc": "^15.0.0", "prettier": "^2.0.0", "remark": "^13.0.0", "remark-attr": "^0.11.0", @@ -54,27 +56,16 @@ "remark-preset-wooorm": "^8.0.0", "remark-usage": "^9.0.0", "tape": "^5.0.0", - "tinyify": "^3.0.0", "typescript": "^4.0.0", "unified": "^9.0.0", - "unist-builder": "^2.0.0", - "xo": "^0.38.0" + "unist-builder": "^3.0.0", + "xo": "^0.39.0" }, "scripts": { "format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix", - "build-bundle": "browserify . -s mdastUtilTOC > mdast-util-toc.js", - "build-mangle": "browserify . -s mdastUtilTOC -p tinyify > mdast-util-toc.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" - }, - "nyc": { - "check-coverage": true, - "lines": 100, - "functions": 100, - "branches": 100 + "test-api": "node test/index.js", + "test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov node test/index.js", + "test": "npm run format && npm run test-coverage" }, "prettier": { "tabWidth": 2, @@ -86,16 +77,16 @@ }, "xo": { "prettier": true, - "esnext": false, - "rules": { - "max-params": "off", - "no-multi-assign": "off", - "unicorn/explicit-length-check": "off", - "unicorn/prefer-optional-catch-binding": "off" - }, + "overrides": [ + { + "files": "example.js", + "rules": { + "capitalized-comments": "off" + } + } + ], "ignores": [ - "types/", - "mdast-util-toc.js" + "types/" ] }, "remarkConfig": { diff --git a/readme.md b/readme.md index eb05b8c..df6586b 100644 --- a/readme.md +++ b/readme.md @@ -12,6 +12,9 @@ ## Install +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][]: ```sh @@ -23,21 +26,21 @@ npm install mdast-util-toc Dependencies: ```javascript -var u = require('unist-builder') -var toc = require('mdast-util-toc') +import {u} from 'unist-builder' +import {toc} from 'mdast-util-toc' ``` -Given a mdast tree: +Now running: ```javascript -var tree = u('root', [ +const tree = u('root', [ u('heading', {depth: 1}, [u('text', 'Alpha')]), u('heading', {depth: 2}, [u('text', 'Bravo')]), u('heading', {depth: 3}, [u('text', 'Charlie')]), u('heading', {depth: 2}, [u('text', 'Delta')]) ]) -var table = toc(tree) +const table = toc(tree) ``` Yields: @@ -57,6 +60,9 @@ Yields: ## API +This package exports the following identifiers: `toc`. +There is no default export. + ### `toc(tree[, options])` Generate a Table of Contents from a [tree][]. diff --git a/test/index.js b/test/index.js index 7902021..e63f1ef 100644 --- a/test/index.js +++ b/test/index.js @@ -1,20 +1,20 @@ -var fs = require('fs') -var path = require('path') -var test = require('tape') -var unified = require('unified') -var remarkParse = require('remark-parse') -var remarkGfm = require('remark-gfm') -var remarkFootnotes = require('remark-footnotes') -var u = require('unist-builder') -var toc = require('..') - -var join = path.join - -test('mdast-util-toc', function (t) { +import fs from 'fs' +import path from 'path' +import test from 'tape' +import unified from 'unified' +import remarkParse from 'remark-parse' +import remarkGfm from 'remark-gfm' +import remarkFootnotes from 'remark-footnotes' +import {u} from 'unist-builder' +import {toc} from '../index.js' + +const join = path.join + +test('mdast-util-toc', (t) => { t.is(typeof toc, 'function', 'should be a function') t.throws( - function () { + () => { toc() }, "Cannot read property 'children' of undefined", @@ -24,31 +24,24 @@ test('mdast-util-toc', function (t) { t.end() }) -test('Fixtures', function (t) { - var root = join(__dirname, 'fixtures') - var files = fs.readdirSync(root) - var index = -1 - var name - var input - var expected - var actual - var config - var processor +test('Fixtures', (t) => { + const root = join('test', 'fixtures') + const files = fs.readdirSync(root) + let index = -1 while (++index < files.length) { - name = files[index] + const name = files[index] if (name.indexOf('.') === 0) continue - input = fs.readFileSync(join(root, name, 'input.md')) - expected = JSON.parse(fs.readFileSync(join(root, name, 'output.json'))) - processor = unified().use(remarkParse).use(remarkGfm) + const input = fs.readFileSync(join(root, name, 'input.md')) + let config = {} try { config = JSON.parse(fs.readFileSync(join(root, name, 'config.json'))) - } catch (_) { - config = {} - } + } catch {} + + const processor = unified().use(remarkParse).use(remarkGfm) if (config.useRemarkFootnotes) { processor.use(remarkFootnotes, {inlineNotes: true}) @@ -60,7 +53,10 @@ test('Fixtures', function (t) { continue } - actual = toc(processor.parse(input), config) + const actual = toc(processor.parse(input), config) + const expected = JSON.parse( + fs.readFileSync(join(root, name, 'output.json')) + ) t.deepEqual(actual, expected, name) } @@ -68,15 +64,15 @@ test('Fixtures', function (t) { t.end() }) -test('processing nodes', function (t) { - var rootNode = u('root', [ +test('processing nodes', (t) => { + const rootNode = u('root', [ u('heading', {depth: 1}, [u('text', 'Alpha')]), u('heading', {depth: 2}, [u('text', 'Bravo')]) ]) - var parentNode = u('parent', rootNode.children) + const parentNode = u('parent', rootNode.children) - var blockquoteNode = u('root', [ + const blockquoteNode = u('root', [ u('heading', {depth: 1}, [u('text', 'Charlie')]), u('heading', {depth: 2}, [u('text', 'Delta')]), u('blockquote', rootNode.children)