From 2c0531da0d5744e00e17d88546c2ead555c0df08 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Tue, 16 Jul 2024 10:49:48 -0400 Subject: [PATCH 01/10] feat!: Switch to ESM fixes #218 --- .github/workflows/release-please.yml | 5 ++- .gitignore | 1 + .../{eslint.config.js => eslint.config.mjs} | 12 +++--- .../{eslint.config.js => eslint.config.mjs} | 10 ++--- index.js | 8 ---- npm-prepare.js => npm-prepare.cjs | 0 package.json | 30 ++++++++------ {lib => src}/index.js | 6 +-- {lib => src}/processor.js | 8 ++-- tests/examples/{all.js => all.test.js} | 17 ++++---- tests/fixtures/eslint.config.js | 6 +-- tests/fixtures/recommended.js | 6 +-- tests/{lib/plugin.js => plugin.test.js} | 41 ++++++++++++------- tests/{lib/processor.js => processor.test.js} | 25 +++++++++-- 14 files changed, 101 insertions(+), 74 deletions(-) rename examples/react/{eslint.config.js => eslint.config.mjs} (76%) rename examples/typescript/{eslint.config.js => eslint.config.mjs} (62%) delete mode 100644 index.js rename npm-prepare.js => npm-prepare.cjs (100%) rename {lib => src}/index.js (97%) rename {lib => src}/processor.js (99%) rename tests/examples/{all.js => all.test.js} (80%) rename tests/{lib/plugin.js => plugin.test.js} (98%) rename tests/{lib/processor.js => processor.test.js} (96%) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 6bc1f651..b857d80d 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -20,7 +20,10 @@ jobs: node-version: lts/* registry-url: https://registry.npmjs.org if: ${{ steps.release.outputs.release_created }} - - run: npm publish --provenance + - run: | + npm install + npm run build --if-present + npm publish --provenance env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} if: ${{ steps.release.outputs.release_created }} diff --git a/.gitignore b/.gitignore index 05c7c9ea..9c5c5a93 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ npm-debug.log yarn.lock package-lock.json pnpm-lock.yaml +dist diff --git a/examples/react/eslint.config.js b/examples/react/eslint.config.mjs similarity index 76% rename from examples/react/eslint.config.js rename to examples/react/eslint.config.mjs index efd097da..5f8b3947 100644 --- a/examples/react/eslint.config.js +++ b/examples/react/eslint.config.mjs @@ -1,13 +1,13 @@ -"use strict"; -const markdown = require("eslint-plugin-markdown"); -const js = require("@eslint/js"); -const globals = require("globals"); +import js from "@eslint/js"; +import markdown from "../../src/index.js"; +import globals from "globals"; +import reactRecommended from "eslint-plugin-react/configs/recommended.js"; -module.exports = [ +export default [ js.configs.recommended, ...markdown.configs.recommended, - require("eslint-plugin-react/configs/recommended"), + reactRecommended, { settings: { react: { diff --git a/examples/typescript/eslint.config.js b/examples/typescript/eslint.config.mjs similarity index 62% rename from examples/typescript/eslint.config.js rename to examples/typescript/eslint.config.mjs index e1409236..a36c941d 100644 --- a/examples/typescript/eslint.config.js +++ b/examples/typescript/eslint.config.mjs @@ -1,10 +1,8 @@ -"use strict"; +import js from "@eslint/js"; +import markdown from "../../src/index.js"; +import tseslint from "typescript-eslint"; -const markdown = require("eslint-plugin-markdown"); -const js = require("@eslint/js") -const tseslint = require("typescript-eslint"); - -module.exports = tseslint.config( +export default tseslint.config( js.configs.recommended, ...markdown.configs.recommended, { diff --git a/index.js b/index.js deleted file mode 100644 index 1638f11e..00000000 --- a/index.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @fileoverview Exports the processor. - * @author Brandon Mills - */ - -"use strict"; - -module.exports = require("./lib"); diff --git a/npm-prepare.js b/npm-prepare.cjs similarity index 100% rename from npm-prepare.js rename to npm-prepare.cjs diff --git a/package.json b/package.json index c1ace70e..e6c6024d 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,16 @@ "name": "Brandon Mills", "url": "https://github.com/btmills" }, + "type": "module", + "main": "src/index.js", + "exports": { + "import": { + "default": "./srcindex.js" + } + }, + "files": [ + "src" + ], "repository": "eslint/eslint-plugin-markdown", "bugs": { "url": "https://github.com/eslint/eslint-plugin-markdown/issues" @@ -21,32 +31,28 @@ ], "scripts": { "lint": "eslint .", - "prepare": "node ./npm-prepare.js", + "prepare": "node ./npm-prepare.cjs", "release:generate:latest": "eslint-generate-release", "release:generate:alpha": "eslint-generate-prerelease alpha", "release:generate:beta": "eslint-generate-prerelease beta", "release:generate:rc": "eslint-generate-prerelease rc", "release:publish": "eslint-publish-release", - "test": "nyc _mocha -- -c tests/{examples,lib}/**/*.js --timeout 30000" + "test": "c8 mocha tests/**/*.test.js --timeout 30000" }, - "main": "index.js", - "files": [ - "index.js", - "lib/index.js", - "lib/processor.js" - ], "devDependencies": { + "@eslint/core": "^0.2.0", "@eslint/js": "^9.4.0", - "chai": "^4.2.0", + "c8": "^10.1.2", + "chai": "^5.1.1", "eslint": "^9.4.0", "eslint-config-eslint": "^11.0.0", "eslint-release": "^3.1.2", "globals": "^15.1.0", - "mocha": "^6.2.2", - "nyc": "^14.1.1" + "mocha": "^10.6.0", + "rollup": "^4.18.1" }, "dependencies": { - "mdast-util-from-markdown": "^0.8.5" + "mdast-util-from-markdown": "^2.0.1" }, "peerDependencies": { "eslint": ">=8" diff --git a/lib/index.js b/src/index.js similarity index 97% rename from lib/index.js rename to src/index.js index b210d72d..5c375274 100644 --- a/lib/index.js +++ b/src/index.js @@ -3,9 +3,7 @@ * @author Brandon Mills */ -"use strict"; - -const processor = require("./processor"); +import { processor } from "./processor.js"; const rulesConfig = { @@ -100,4 +98,4 @@ plugin.configs.recommended = [ } ]; -module.exports = plugin; +export default plugin; diff --git a/lib/processor.js b/src/processor.js similarity index 99% rename from lib/processor.js rename to src/processor.js index 93f56ada..43fa6618 100644 --- a/lib/processor.js +++ b/src/processor.js @@ -25,9 +25,7 @@ * @typedef {ASTNode & BlockBase} Block */ -"use strict"; - -const parse = require("mdast-util-from-markdown"); +import { fromMarkdown } from "mdast-util-from-markdown"; const UNSATISFIABLE_RULES = new Set([ "eol-last", // The Markdown parser strips trailing newlines in code fences @@ -248,7 +246,7 @@ const languageToFileExtension = { * @returns {Array<{ filename: string, text: string }>} Source code blocks to lint. */ function preprocess(text, filename) { - const ast = parse(text); + const ast = fromMarkdown(text); const blocks = []; blocksCache.set(filename, blocks); @@ -409,7 +407,7 @@ function postprocess(messages, filename) { }); } -module.exports = { +export const processor = { meta: { name: "eslint-plugin-markdown/markdown", version: "5.1.0" // x-release-please-version diff --git a/tests/examples/all.js b/tests/examples/all.test.js similarity index 80% rename from tests/examples/all.js rename to tests/examples/all.test.js index 2efdf192..98cb7529 100644 --- a/tests/examples/all.js +++ b/tests/examples/all.test.js @@ -1,10 +1,13 @@ -"use strict"; - -const assert = require("chai").assert; -const fs = require("fs"); -const path = require("path"); -const semver = require("semver"); +import { assert } from "chai"; +import fs from "node:fs"; +import path from "node:path"; +import semver from "semver"; +import { createRequire } from "node:module"; +import { fileURLToPath } from "node:url"; +const require = createRequire(import.meta.url); +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); const examplesDir = path.resolve(__dirname, "../../examples/"); const examples = fs.readdirSync(examplesDir) .filter(exampleDir => fs.statSync(path.join(examplesDir, exampleDir)).isDirectory()) @@ -14,7 +17,7 @@ for (const example of examples) { const cwd = path.join(examplesDir, example); // The plugin officially supports ESLint as early as v6, but the examples - // use ESLint v7, which has a higher minimum Node.js version than does v6. + // use ESLint v8, which has a higher minimum Node.js version than does v6. // Only exercise the example if the running Node.js version satisfies the // minimum version constraint. In CI, this will skip these tests in Node.js // v8 and run them on all other Node.js versions. diff --git a/tests/fixtures/eslint.config.js b/tests/fixtures/eslint.config.js index 0cd96371..d8c4ecb7 100644 --- a/tests/fixtures/eslint.config.js +++ b/tests/fixtures/eslint.config.js @@ -1,7 +1,7 @@ -const markdown = require("../../"); -const globals = require("globals"); +import markdown from "../../src/index.js"; +import globals from "globals"; -module.exports = [ +export default [ { plugins: { markdown diff --git a/tests/fixtures/recommended.js b/tests/fixtures/recommended.js index d2d72b84..d04e32b1 100644 --- a/tests/fixtures/recommended.js +++ b/tests/fixtures/recommended.js @@ -1,7 +1,7 @@ -const markdown = require("../../"); -const js = require("@eslint/js") +import markdown from "../../src/index.js"; +import js from "@eslint/js"; -module.exports = [ +export default [ js.configs.recommended, ...markdown.configs.recommended, { diff --git a/tests/lib/plugin.js b/tests/plugin.test.js similarity index 98% rename from tests/lib/plugin.js rename to tests/plugin.test.js index d7e91ae3..94edb62c 100644 --- a/tests/lib/plugin.js +++ b/tests/plugin.test.js @@ -3,17 +3,28 @@ * @author Brandon Mills */ -"use strict"; +//----------------------------------------------------------------------------- +// Imports +//----------------------------------------------------------------------------- + +import { assert } from "chai"; +import api from "eslint"; +import unsupportedAPI from "eslint/use-at-your-own-risk"; +import path from "node:path"; +import plugin from "../src/index.js"; +import fs from "node:fs"; +import { fileURLToPath } from "node:url"; + +const ESLint = api.ESLint; +const LegacyESLint = unsupportedAPI.LegacyESLint; +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); //----------------------------------------------------------------------------- -// Requirements +// Data //----------------------------------------------------------------------------- -const assert = require("chai").assert; -const { LegacyESLint, FlatESLint } = require("eslint/use-at-your-own-risk"); -const path = require("node:path"); -const plugin = require("../.."); -const pkg = require("../../package.json"); +const pkg = JSON.parse(fs.readFileSync(path.resolve(__dirname, "../package.json"), "utf8")); //----------------------------------------------------------------------------- // Helpers @@ -27,10 +38,10 @@ const pkg = require("../../package.json"); */ function initLegacyESLint(fixtureConfigName, options = {}) { return new LegacyESLint({ - cwd: path.resolve(__dirname, "../fixtures/"), + cwd: path.resolve(__dirname, "./fixtures/"), ignore: false, useEslintrc: false, - overrideConfigFile: path.resolve(__dirname, "../fixtures/", fixtureConfigName), + overrideConfigFile: path.resolve(__dirname, "./fixtures/", fixtureConfigName), plugins: { markdown: plugin }, ...options }); @@ -40,13 +51,13 @@ function initLegacyESLint(fixtureConfigName, options = {}) { * Helper function which creates ESLint instance with enabled/disabled autofix feature. * @param {string} fixtureConfigName ESLint config filename. * @param {Object} [options={}] Whether to enable autofix feature. - * @returns {FlatESLint} ESLint instance to execute in tests. + * @returns {ESLint} ESLint instance to execute in tests. */ function initFlatESLint(fixtureConfigName, options = {}) { - return new FlatESLint({ - cwd: path.resolve(__dirname, "../fixtures/"), + return new ESLint({ + cwd: path.resolve(__dirname, "./fixtures/"), ignore: false, - overrideConfigFile: path.resolve(__dirname, "../fixtures/", fixtureConfigName), + overrideConfigFile: path.resolve(__dirname, "./fixtures/", fixtureConfigName), ...options }); } @@ -245,7 +256,7 @@ describe("LegacyESLint", () => { }); it("should extract blocks and remap messages", async () => { - const results = await eslint.lintFiles([path.resolve(__dirname, "../fixtures/long.md")]); + const results = await eslint.lintFiles([path.resolve(__dirname, "./fixtures/long.md")]); assert.strictEqual(results.length, 1); assert.strictEqual(results[0].messages.length, 5); @@ -1207,7 +1218,7 @@ describe("FlatESLint", () => { }); it("should extract blocks and remap messages", async () => { - const results = await eslint.lintFiles([path.resolve(__dirname, "../fixtures/long.md")]); + const results = await eslint.lintFiles([path.resolve(__dirname, "./fixtures/long.md")]); assert.strictEqual(results.length, 1); assert.strictEqual(results[0].messages.length, 5); diff --git a/tests/lib/processor.js b/tests/processor.test.js similarity index 96% rename from tests/lib/processor.js rename to tests/processor.test.js index 23433be2..bb00eb33 100644 --- a/tests/lib/processor.js +++ b/tests/processor.test.js @@ -3,11 +3,28 @@ * @author Brandon Mills */ -"use strict"; +//----------------------------------------------------------------------------- +// Imports +//----------------------------------------------------------------------------- -const assert = require("chai").assert; -const processor = require("../../lib/processor"); -const pkg = require("../../package.json"); +import { assert } from "chai"; +import path from "node:path"; +import { processor } from "../src/processor.js"; +import fs from "node:fs"; +import { fileURLToPath } from "node:url"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +//----------------------------------------------------------------------------- +// Data +//----------------------------------------------------------------------------- + +const pkg = JSON.parse(fs.readFileSync(path.resolve(__dirname, "../package.json"), "utf8")); + +//----------------------------------------------------------------------------- +// Tests +//----------------------------------------------------------------------------- describe("processor", () => { From ce420e9a1be9d1cf670b0328d80a3a9730ec5e8a Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Tue, 16 Jul 2024 12:19:31 -0400 Subject: [PATCH 02/10] Clean up --- .gitignore | 1 - package.json | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 9c5c5a93..05c7c9ea 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,3 @@ npm-debug.log yarn.lock package-lock.json pnpm-lock.yaml -dist diff --git a/package.json b/package.json index e6c6024d..d99981c8 100644 --- a/package.json +++ b/package.json @@ -48,8 +48,7 @@ "eslint-config-eslint": "^11.0.0", "eslint-release": "^3.1.2", "globals": "^15.1.0", - "mocha": "^10.6.0", - "rollup": "^4.18.1" + "mocha": "^10.6.0" }, "dependencies": { "mdast-util-from-markdown": "^2.0.1" From 10b1c048ac7ba77098457a6e8d5d84262853fe4c Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Tue, 16 Jul 2024 12:23:42 -0400 Subject: [PATCH 03/10] Update docs --- README.md | 59 ------------------------------------------------------- 1 file changed, 59 deletions(-) diff --git a/README.md b/README.md index bd2c497e..21583118 100644 --- a/README.md +++ b/README.md @@ -38,15 +38,6 @@ export default [ ]; ``` -If you are still using the deprecated `.eslintrc.js` file format for ESLint, you can extend the `plugin:markdown/recommended-legacy` config to enable the Markdown processor on all `.md` files: - -```js -// .eslintrc.js -module.exports = { - extends: "plugin:markdown/recommended-legacy" -}; -``` - #### Advanced Configuration You can manually include the Markdown processor by setting the `processor` option in your configuration file for all `.md` files. @@ -96,32 +87,6 @@ export default [ ]; ``` -In the deprecated `.eslintrc.js` format: - -```js -// .eslintrc.js -module.exports = { - // 1. Add the plugin. - plugins: ["markdown"], - overrides: [ - { - // 2. Enable the Markdown processor for all .md files. - files: ["**/*.md"], - processor: "markdown/markdown" - }, - { - // 3. Optionally, customize the configuration ESLint uses for ```js - // fenced code blocks inside .md files. - files: ["**/*.md/*.js"], - // ... - rules: { - // ... - } - } - ] -}; -``` - #### Frequently-Disabled Rules Some rules that catch mistakes in regular code are less helpful in documentation. @@ -163,30 +128,6 @@ export default [ ]; ``` -And in the deprecated `.eslintrc.js` format: - -```js -// .eslintrc.js -module.exports = { - plugins: ["markdown"], - overrides: [ - { - files: ["**/*.md"], - processor: "markdown/markdown" - }, - { - // 1. Target ```js code blocks in .md files. - files: ["**/*.md/*.js"], - rules: { - // 2. Disable other rules. - "no-console": "off", - "import/no-unresolved": "off" - } - } - ] -}; -``` - #### Strict Mode `"use strict"` directives in every code block would be annoying. From f043a9b638d8a4c2a5482639fc0115ade195f02c Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Tue, 16 Jul 2024 12:32:01 -0400 Subject: [PATCH 04/10] Fix lint errors --- eslint.config.js | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index fb37936b..5febc486 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,17 +1,17 @@ -"use strict"; +import globals from "globals"; +import eslintConfigESLint from "eslint-config-eslint"; +import eslintConfigESLintFormatting from "eslint-config-eslint/formatting"; +import markdown from "./src/index.js"; -module.exports = [ - ...require("eslint-config-eslint/cjs").map(config => ({ - ...config, - files: ["**/*.js"] - })), +export default [ + ...eslintConfigESLint, { - ...require("eslint-config-eslint/formatting"), + ...eslintConfigESLintFormatting, files: ["**/*.js"] }, { plugins: { - markdown: require(".") + markdown } }, { @@ -25,8 +25,11 @@ module.exports = [ files: ["tests/**/*.js"], languageOptions: { globals: { - ...require("globals").mocha + ...globals.mocha } + }, + rules: { + "no-underscore-dangle": "off" } }, { From fc3191e0310b1ada3915e4c1092e53b319891b78 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Wed, 17 Jul 2024 16:04:35 -0400 Subject: [PATCH 05/10] Update package.json Co-authored-by: Milos Djermanovic --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d99981c8..dec85588 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "main": "src/index.js", "exports": { "import": { - "default": "./srcindex.js" + "default": "./src/index.js" } }, "files": [ From 23d770d449af204725e10e333ad34845c22e19d9 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Wed, 17 Jul 2024 16:04:41 -0400 Subject: [PATCH 06/10] Update package.json Co-authored-by: Milos Djermanovic --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dec85588..f268a4df 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "mdast-util-from-markdown": "^2.0.1" }, "peerDependencies": { - "eslint": ">=8" + "eslint": ">=9" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" From 47da3a10ea11c7ad7c75f8e1ec8df8f6fc067f14 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Wed, 17 Jul 2024 16:05:48 -0400 Subject: [PATCH 07/10] Fix extra-files names --- release-please-config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-please-config.json b/release-please-config.json index 829aeaf7..a0bcc0d9 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -4,8 +4,8 @@ "release-type": "node", "pull-request-title-pattern": "chore: release ${version} 🚀", "extra-files": [ - "lib/index.js", - "lib/processor.js" + "src/index.js", + "src/processor.js" ] } } From 32096778c59a8c93336b9d68c070de8915f3e940 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Mon, 22 Jul 2024 10:36:04 -0400 Subject: [PATCH 08/10] Update package.json Co-authored-by: Milos Djermanovic --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f268a4df..655f84a4 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "release:generate:beta": "eslint-generate-prerelease beta", "release:generate:rc": "eslint-generate-prerelease rc", "release:publish": "eslint-publish-release", - "test": "c8 mocha tests/**/*.test.js --timeout 30000" + "test": "c8 mocha \"tests/**/*.test.js\" --timeout 30000" }, "devDependencies": { "@eslint/core": "^0.2.0", From 610e041e1d82611b6e30d1b178b3c15633a27b7e Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Mon, 22 Jul 2024 10:48:21 -0400 Subject: [PATCH 09/10] Apply feedback --- README.md | 2 -- eslint.config.js | 5 +---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/README.md b/README.md index 21583118..43c1a44c 100644 --- a/README.md +++ b/README.md @@ -146,8 +146,6 @@ The `markdown.configs.recommended` config disables these rules in Markdown files If you are using an `eslint.config.js` file, then you can run ESLint as usual and it will pick up file patterns in your config file. The `--ext` option is not available when using flat config. -If you are using an `.eslintrc.*` file, then you can run ESLint as usual and it will pick up file extensions specified in `overrides[].files` patterns in config files. - ### Autofixing diff --git a/eslint.config.js b/eslint.config.js index 5febc486..dae8360f 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -5,10 +5,7 @@ import markdown from "./src/index.js"; export default [ ...eslintConfigESLint, - { - ...eslintConfigESLintFormatting, - files: ["**/*.js"] - }, + eslintConfigESLintFormatting, { plugins: { markdown From a0d4ba449d573e86679d05177721161308b4401c Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Mon, 22 Jul 2024 13:46:42 -0400 Subject: [PATCH 10/10] Remove ESLint 8 from CI --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3104e5ef..2545cdf9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - eslint: [9, 8] + eslint: [9] node: [22.x, 21.x, 20.x, 18.x, "18.18.0"] include: - os: windows-latest