diff --git a/index.js b/index.js index 3dfb120..46108b7 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,7 @@ /** * @typedef {import('mdast').Root} Root * @typedef {import('micromark-extension-gfm').Options & import('mdast-util-gfm').Options} Options + * @typedef {import('unified').Processor} Processor */ import {gfm} from 'micromark-extension-gfm' @@ -9,11 +10,16 @@ import {gfmFromMarkdown, gfmToMarkdown} from 'mdast-util-gfm' /** * Plugin to support GFM (autolink literals, footnotes, strikethrough, tables, tasklists). * - * @this {import('unified').Processor} - * @type {import('unified').Plugin<[Options?]|void[], Root>} + * @param {Options | null | undefined} [options='yaml'] + * Configuration (default: `'yaml'`). + * @returns {undefined} + * Nothing. */ export default function remarkGfm(options = {}) { - const data = this.data() + // @ts-expect-error: TS is wrong about `this`. + // eslint-disable-next-line unicorn/no-this-assignment + const self = /** @type {Processor} */ (this) + const data = self.data() add('micromarkExtensions', gfm(options)) add('fromMarkdownExtensions', gfmFromMarkdown()) diff --git a/package.json b/package.json index bc6bc8e..d5a764b 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "unified": "^11.0.0" }, "devDependencies": { - "@types/tape": "^5.0.0", + "@types/node": "^20.0.0", "c8": "^8.0.0", "is-hidden": "^2.0.0", "prettier": "^3.0.0", @@ -51,7 +51,6 @@ "remark-cli": "^11.0.0", "remark-preset-wooorm": "^9.0.0", "string-width": "^6.0.0", - "tape": "^5.0.0", "to-vfile": "^8.0.0", "type-coverage": "^2.0.0", "typescript": "^5.0.0", @@ -85,6 +84,16 @@ "strict": true }, "xo": { + "overrides": [ + { + "files": [ + "test/**/*.js" + ], + "rules": { + "no-await-in-loop": "off" + } + } + ], "prettier": true } } diff --git a/test/fixtures/tasklist/output.md b/test/fixtures/tasklist/output.md index 5ae8479..b146fab 100644 --- a/test/fixtures/tasklist/output.md +++ b/test/fixtures/tasklist/output.md @@ -1,3 +1,3 @@ -* [x] done -* [ ] to do -* other +* [x] done +* [ ] to do +* other diff --git a/test/index.js b/test/index.js index 5eecbd0..23140be 100644 --- a/test/index.js +++ b/test/index.js @@ -3,91 +3,91 @@ * @typedef {import('../index.js').Options} Options */ -import fs from 'node:fs' -import path from 'node:path' +import assert from 'node:assert/strict' +import fs from 'node:fs/promises' import process from 'node:process' -import test from 'tape' -import {readSync} from 'to-vfile' -import {unified} from 'unified' -import {remark} from 'remark' +import test from 'node:test' import {isHidden} from 'is-hidden' +import {remark} from 'remark' import stringWidth from 'string-width' -import gfm from '../index.js' +import remarkGfm from '../index.js' + +test('remarkGfm', async function (t) { + await t.test('should expose the public api', async function () { + assert.deepEqual(Object.keys(await import('../index.js')).sort(), [ + 'default' + ]) + }) + + await t.test('should not throw if not passed options', async function () { + assert.doesNotThrow(function () { + remark().use(remarkGfm).freeze() + }) + }) +}) -test('gfm()', (t) => { - t.doesNotThrow(() => { - // @ts-expect-error: to do: remove when remark is released. - remark().use(gfm).freeze() - }, 'should not throw if not passed options') +test('fixtures', async function (t) { + const base = new URL('fixtures/', import.meta.url) + const folders = await fs.readdir(base) - t.doesNotThrow(() => { - unified().use(gfm).freeze() - }, 'should not throw if without parser or compiler') + let index = -1 - t.end() -}) + while (++index < folders.length) { + const folder = folders[index] -test('fixtures', (t) => { - const base = path.join('test', 'fixtures') - const entries = fs.readdirSync(base) - let index = -1 + if (isHidden(folder)) continue + + await t.test(folder, async function () { + const folderUrl = new URL(folder + '/', base) + const inputUrl = new URL('input.md', folderUrl) + const outputUrl = new URL('output.md', folderUrl) + const treeUrl = new URL('tree.json', folderUrl) + const configUrl = new URL('config.json', folderUrl) - while (++index < entries.length) { - if (isHidden(entries[index])) continue + const input = String(await fs.readFile(inputUrl)) - const file = readSync(path.join(base, entries[index], 'input.md')) - const input = String(file.value) - const treePath = path.join(base, entries[index], 'tree.json') - /** @type {Options|undefined} */ - let config + /** @type {Options | undefined} */ + let config + /** @type {Root} */ + let expected + /** @type {string} */ + let output - try { - config = JSON.parse( - String(fs.readFileSync(path.join(base, entries[index], 'config.json'))) - ) - } catch {} + try { + config = JSON.parse(String(await fs.readFile(configUrl))) + } catch {} - if (entries[index] === 'table-string-length') { - config = {stringLength: stringWidth} - } + if (folder === 'table-string-length') { + config = {stringLength: stringWidth} + } + + const proc = remark().use(remarkGfm, config) + /** @type {Root} */ + // @ts-expect-error: remove when remark is released. + const actual = proc.parse(input) + + try { + output = String(await fs.readFile(outputUrl)) + } catch { + output = input + } - // @ts-expect-error: to do: remove when remark is released. - const proc = remark().use(gfm, config).freeze() - const actual = proc.parse(file) - /** @type {Root} */ - let expected + try { + if ('UPDATE' in process.env) { + throw new Error('Updating…') + } - try { - expected = JSON.parse(String(fs.readFileSync(treePath))) + expected = JSON.parse(String(await fs.readFile(treeUrl))) + } catch { + expected = actual - if ('UPDATE' in process.env) { - throw new Error('Regenerate') + // New fixture. + await fs.writeFile(treeUrl, JSON.stringify(actual, undefined, 2) + '\n') } - } catch { - // New fixture. - fs.writeFileSync(treePath, JSON.stringify(actual, null, 2) + '\n') - expected = actual - } - - /** @type {string} */ - let output - - try { - output = fs.readFileSync( - path.join(base, entries[index], 'output.md'), - 'utf8' - ) - } catch { - output = input - } - - t.deepEqual(actual, expected, entries[index] + ' (tree)') - t.equal( - String(proc.processSync(file)), - output, - entries[index] + ' (process)' - ) - } - t.end() + assert.deepEqual(actual, expected) + + assert.equal(String(await proc.process(input)), String(output)) + }) + } })