diff --git a/.eslintrc.js b/.eslintrc.js index f2b60b54..bd916bf5 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -9,6 +9,13 @@ module.exports = { extends: ['@1stg'], overrides: [ ...overrides, + { + files: '*.md', + extends: ['plugin:mdx/recommended'], + rules: { + 'prettier/prettier': 0, // FIXME: should be supported + }, + }, { files: '*.ts', rules: { diff --git a/README.md b/README.md index a083d55d..0879d76d 100644 --- a/README.md +++ b/README.md @@ -22,9 +22,9 @@ [![lerna](https://img.shields.io/badge/maintained%20with-lerna-cc00ff.svg)](https://lerna.js.org) [![codechecks.io](https://raw.githubusercontent.com/codechecks/docs/master/images/badges/badge-default.svg?sanitize=true)](https://codechecks.io) -> [ESLint] Parser/Plugin for [MDX], helps you lint all ES syntaxes excluding `code` block of course. +> [ESLint][] Parser/Plugin for [MDX][], helps you lint all ES syntaxes excluding `code` block of course. > Work perfectly with `eslint-plugin-import`, `eslint-plugin-prettier` or any other eslint plugins. -> And also can be integrated with [remark] plugins to lint non ES syntaxes. +> And also can be integrated with [remark][] plugins to lint non ES syntaxes. ## TOC @@ -45,11 +45,11 @@ [![Visual Studio Marketplace Version](https://img.shields.io/visual-studio-marketplace/v/JounQin.vscode-mdx)](https://marketplace.visualstudio.com/items?itemName=JounQin.vscode-mdx) -[VSCode MDX]\: Integrates with [VSCode ESLint], syntaxes highlighting and error reporting. +[VSCode MDX][]\: Integrates with [VSCode ESLint][], syntaxes highlighting and error reporting. ## Packages -This repository is a monorepo managed by [Lerna] what means we actually publish several packages to npm from same codebase, including: +This repository is a monorepo managed by [Lerna][] what means we actually publish several packages to npm from same codebase, including: | Package | Description | Version | Peer Dependencies | Dependencies | | -------------------------------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -124,6 +124,8 @@ npm i -D eslint-plugin-mdx 2. `extensions` (`string | string[]`): `eslint-mdx` will only resolve `.mdx` files by default, files with other extensions will be resolved by the `parser` option. If you want to resolve other extensions as like `.mdx`, you can use this option. +3. `markdownExtensions` (`string | string[]`): `eslint-mdx` will only treat `.md` files as plain markdown by default, and will lint them via remark plugins. If you want to resolve other extensions as like `.md`, you can use this option. + ## Rules ### mdx/no-jsx-html-comments @@ -132,17 +134,17 @@ _Fixable_: HTML style comments in jsx block is invalid, this rule will help you ### mdx/no-unescaped-entities -Inline JSX like `Inline ` is supported by [MDX], but rule `react/no-unescaped-entities` from [eslint-plugin-react] is incompatible with it, `mdx/no-unescaped-entities` is the replacement. +Inline JSX like `Inline ` is supported by [MDX][], but rule `react/no-unescaped-entities` from [eslint-plugin-react][] is incompatible with it, `mdx/no-unescaped-entities` is the replacement. ### mdx/no-unused-expressions -[MDX] can render `jsx` block automatically without exporting them, but [ESLint] will report `no-unused-expressions` issue which could be unexpected, this rule is a replacement of it, so make sure that you've turned off the original `no-unused-expressions` rule. +[MDX][] can render `jsx` block automatically without exporting them, but [ESLint][] will report `no-unused-expressions` issue which could be unexpected, this rule is a replacement of it, so make sure that you've turned off the original `no-unused-expressions` rule. ### mdx/remark _possible fixable depends on your remark plugins_: -Integration with [remark] plugins without [remark-lint], it will read [remark's configuration](https://github.com/remarkjs/remark/tree/master/packages/remark-cli#remark-cli) automatically via [cosmiconfig]. But `.remarkignore` will not be respected, you should use `.eslintignore` instead. +Integration with [remark][] plugins without [remark-lint][], it will read [remark's configuration](https://github.com/remarkjs/remark/tree/master/packages/remark-cli#remark-cli) automatically via [cosmiconfig][]. But `.remarkignore` will not be respected, you should use `.eslintignore` instead. ## Changelog @@ -150,7 +152,7 @@ Detailed changes for each release are documented in [CHANGELOG.md](./CHANGELOG.m ## License -[MIT] © [JounQin]@[1stG.me] +[MIT][] © [JounQin][]@[1stG.me][] [1stg.me]: https://www.1stg.me [cosmiconfig]: https://github.com/davidtheclark/cosmiconfig @@ -160,7 +162,6 @@ Detailed changes for each release are documented in [CHANGELOG.md](./CHANGELOG.m [lerna]: https://github.com/lerna/lerna [mdx]: https://github.com/mdx-js/mdx [mit]: http://opensource.org/licenses/MIT -[markdownlint]: https://github.com/markdownlint/markdownlint [remark]: https://github.com/remarkjs/remark [remark-lint]: https://github.com/remarkjs/remark-lint [vscode eslint]: https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint diff --git a/package.json b/package.json index beb61fcf..a16bbdfe 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "scripts": { "build": "tsc -b", "test": "ts-node -T node_modules/.bin/jest", - "lint": "EFF_NO_LINK_RULES=true eslint . --ext js,mdx,ts,tsx -f friendly", + "lint": "EFF_NO_LINK_RULES=true eslint . --ext js,md,mdx,ts,tsx -f friendly", "type-coverage": "type-coverage --cache --ignore-catch --detail --ignore-files *.d.ts --strict" }, "devDependencies": { @@ -58,7 +58,9 @@ ] }, "eslintIgnore": [ + "**/fixtures/**/*.md", "**/fixtures/**/*.mdx", + "CHANGELOG.md", "coverage", "lib", "node_modules" @@ -80,13 +82,29 @@ }, "prettier": "@1stg/prettier-config", "remarkConfig": { - "settings": { - "emphasis": "*", - "strong": "*" - }, "plugins": [ "preset-lint-recommended", - "preset-lint-markdown-style-guide" + "preset-lint-markdown-style-guide", + [ + "lint-list-item-spacing", + false + ], + [ + "lint-list-item-indent", + false + ], + [ + "lint-ordered-list-marker-value", + false + ], + [ + "lint-emphasis-marker", + "_" + ], + [ + "lint-maximum-line-length", + false + ] ] }, "renovate": { diff --git a/packages/eslint-mdx/README.md b/packages/eslint-mdx/README.md index a083d55d..0879d76d 100644 --- a/packages/eslint-mdx/README.md +++ b/packages/eslint-mdx/README.md @@ -22,9 +22,9 @@ [![lerna](https://img.shields.io/badge/maintained%20with-lerna-cc00ff.svg)](https://lerna.js.org) [![codechecks.io](https://raw.githubusercontent.com/codechecks/docs/master/images/badges/badge-default.svg?sanitize=true)](https://codechecks.io) -> [ESLint] Parser/Plugin for [MDX], helps you lint all ES syntaxes excluding `code` block of course. +> [ESLint][] Parser/Plugin for [MDX][], helps you lint all ES syntaxes excluding `code` block of course. > Work perfectly with `eslint-plugin-import`, `eslint-plugin-prettier` or any other eslint plugins. -> And also can be integrated with [remark] plugins to lint non ES syntaxes. +> And also can be integrated with [remark][] plugins to lint non ES syntaxes. ## TOC @@ -45,11 +45,11 @@ [![Visual Studio Marketplace Version](https://img.shields.io/visual-studio-marketplace/v/JounQin.vscode-mdx)](https://marketplace.visualstudio.com/items?itemName=JounQin.vscode-mdx) -[VSCode MDX]\: Integrates with [VSCode ESLint], syntaxes highlighting and error reporting. +[VSCode MDX][]\: Integrates with [VSCode ESLint][], syntaxes highlighting and error reporting. ## Packages -This repository is a monorepo managed by [Lerna] what means we actually publish several packages to npm from same codebase, including: +This repository is a monorepo managed by [Lerna][] what means we actually publish several packages to npm from same codebase, including: | Package | Description | Version | Peer Dependencies | Dependencies | | -------------------------------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -124,6 +124,8 @@ npm i -D eslint-plugin-mdx 2. `extensions` (`string | string[]`): `eslint-mdx` will only resolve `.mdx` files by default, files with other extensions will be resolved by the `parser` option. If you want to resolve other extensions as like `.mdx`, you can use this option. +3. `markdownExtensions` (`string | string[]`): `eslint-mdx` will only treat `.md` files as plain markdown by default, and will lint them via remark plugins. If you want to resolve other extensions as like `.md`, you can use this option. + ## Rules ### mdx/no-jsx-html-comments @@ -132,17 +134,17 @@ _Fixable_: HTML style comments in jsx block is invalid, this rule will help you ### mdx/no-unescaped-entities -Inline JSX like `Inline ` is supported by [MDX], but rule `react/no-unescaped-entities` from [eslint-plugin-react] is incompatible with it, `mdx/no-unescaped-entities` is the replacement. +Inline JSX like `Inline ` is supported by [MDX][], but rule `react/no-unescaped-entities` from [eslint-plugin-react][] is incompatible with it, `mdx/no-unescaped-entities` is the replacement. ### mdx/no-unused-expressions -[MDX] can render `jsx` block automatically without exporting them, but [ESLint] will report `no-unused-expressions` issue which could be unexpected, this rule is a replacement of it, so make sure that you've turned off the original `no-unused-expressions` rule. +[MDX][] can render `jsx` block automatically without exporting them, but [ESLint][] will report `no-unused-expressions` issue which could be unexpected, this rule is a replacement of it, so make sure that you've turned off the original `no-unused-expressions` rule. ### mdx/remark _possible fixable depends on your remark plugins_: -Integration with [remark] plugins without [remark-lint], it will read [remark's configuration](https://github.com/remarkjs/remark/tree/master/packages/remark-cli#remark-cli) automatically via [cosmiconfig]. But `.remarkignore` will not be respected, you should use `.eslintignore` instead. +Integration with [remark][] plugins without [remark-lint][], it will read [remark's configuration](https://github.com/remarkjs/remark/tree/master/packages/remark-cli#remark-cli) automatically via [cosmiconfig][]. But `.remarkignore` will not be respected, you should use `.eslintignore` instead. ## Changelog @@ -150,7 +152,7 @@ Detailed changes for each release are documented in [CHANGELOG.md](./CHANGELOG.m ## License -[MIT] © [JounQin]@[1stG.me] +[MIT][] © [JounQin][]@[1stG.me][] [1stg.me]: https://www.1stg.me [cosmiconfig]: https://github.com/davidtheclark/cosmiconfig @@ -160,7 +162,6 @@ Detailed changes for each release are documented in [CHANGELOG.md](./CHANGELOG.m [lerna]: https://github.com/lerna/lerna [mdx]: https://github.com/mdx-js/mdx [mit]: http://opensource.org/licenses/MIT -[markdownlint]: https://github.com/markdownlint/markdownlint [remark]: https://github.com/remarkjs/remark [remark-lint]: https://github.com/remarkjs/remark-lint [vscode eslint]: https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint diff --git a/packages/eslint-mdx/src/parser.ts b/packages/eslint-mdx/src/parser.ts index 74a1ccf0..7a3ea047 100644 --- a/packages/eslint-mdx/src/parser.ts +++ b/packages/eslint-mdx/src/parser.ts @@ -31,6 +31,7 @@ export const ES_NODE_TYPES: readonly string[] = ['export', 'import', 'jsx'] export const LOC_ERROR_PROPERTIES = ['column', 'index', 'lineNumber'] as const export const DEFAULT_EXTENSIONS: readonly string[] = ['.mdx'] +export const MARKDOWN_EXTENSIONS: readonly string[] = ['.md'] export const DEFAULT_PARSER_OPTIONS: ParserOptions = { comment: true, @@ -140,11 +141,14 @@ export class Parser { } parseForESLint(code: string, options: ParserOptions) { - if ( - !DEFAULT_EXTENSIONS.concat(options.extensions || []).includes( - path.extname(options.filePath), - ) - ) { + const extname = path.extname(options.filePath) + const isMdx = DEFAULT_EXTENSIONS.concat(options.extensions || []).includes( + extname, + ) + const isMarkdown = MARKDOWN_EXTENSIONS.concat( + options.markdownExtensions || [], + ).includes(extname) + if (!isMdx && !isMarkdown) { return this._eslintParse(code, options) } @@ -163,17 +167,19 @@ export class Parser { JSXElementsWithHTMLComments: [], } - traverse(root, { - enter: (node, parent) => { - if (!ES_NODE_TYPES.includes(node.type)) { - return - } + if (isMdx) { + traverse(root, { + enter: (node, parent) => { + if (!ES_NODE_TYPES.includes(node.type)) { + return + } - let normalized = this.normalizeJsxNode(node, parent) - normalized = Array.isArray(normalized) ? normalized : [normalized] - normalized.forEach(node => this._nodeToAst(node, options)) - }, - }) + let normalized = this.normalizeJsxNode(node, parent) + normalized = Array.isArray(normalized) ? normalized : [normalized] + normalized.forEach(node => this._nodeToAst(node, options)) + }, + }) + } return { ast: this._ast, diff --git a/packages/eslint-mdx/src/types.ts b/packages/eslint-mdx/src/types.ts index c76571cd..ea064d1c 100644 --- a/packages/eslint-mdx/src/types.ts +++ b/packages/eslint-mdx/src/types.ts @@ -35,6 +35,7 @@ export interface LocationError { export interface ParserOptions extends Linter.ParserOptions { extensions?: string | string[] + markdownExtensions?: string | string[] filePath?: string parser?: string | ParserConfig | ParserFn } diff --git a/packages/eslint-plugin-mdx/README.md b/packages/eslint-plugin-mdx/README.md index a083d55d..0879d76d 100644 --- a/packages/eslint-plugin-mdx/README.md +++ b/packages/eslint-plugin-mdx/README.md @@ -22,9 +22,9 @@ [![lerna](https://img.shields.io/badge/maintained%20with-lerna-cc00ff.svg)](https://lerna.js.org) [![codechecks.io](https://raw.githubusercontent.com/codechecks/docs/master/images/badges/badge-default.svg?sanitize=true)](https://codechecks.io) -> [ESLint] Parser/Plugin for [MDX], helps you lint all ES syntaxes excluding `code` block of course. +> [ESLint][] Parser/Plugin for [MDX][], helps you lint all ES syntaxes excluding `code` block of course. > Work perfectly with `eslint-plugin-import`, `eslint-plugin-prettier` or any other eslint plugins. -> And also can be integrated with [remark] plugins to lint non ES syntaxes. +> And also can be integrated with [remark][] plugins to lint non ES syntaxes. ## TOC @@ -45,11 +45,11 @@ [![Visual Studio Marketplace Version](https://img.shields.io/visual-studio-marketplace/v/JounQin.vscode-mdx)](https://marketplace.visualstudio.com/items?itemName=JounQin.vscode-mdx) -[VSCode MDX]\: Integrates with [VSCode ESLint], syntaxes highlighting and error reporting. +[VSCode MDX][]\: Integrates with [VSCode ESLint][], syntaxes highlighting and error reporting. ## Packages -This repository is a monorepo managed by [Lerna] what means we actually publish several packages to npm from same codebase, including: +This repository is a monorepo managed by [Lerna][] what means we actually publish several packages to npm from same codebase, including: | Package | Description | Version | Peer Dependencies | Dependencies | | -------------------------------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -124,6 +124,8 @@ npm i -D eslint-plugin-mdx 2. `extensions` (`string | string[]`): `eslint-mdx` will only resolve `.mdx` files by default, files with other extensions will be resolved by the `parser` option. If you want to resolve other extensions as like `.mdx`, you can use this option. +3. `markdownExtensions` (`string | string[]`): `eslint-mdx` will only treat `.md` files as plain markdown by default, and will lint them via remark plugins. If you want to resolve other extensions as like `.md`, you can use this option. + ## Rules ### mdx/no-jsx-html-comments @@ -132,17 +134,17 @@ _Fixable_: HTML style comments in jsx block is invalid, this rule will help you ### mdx/no-unescaped-entities -Inline JSX like `Inline ` is supported by [MDX], but rule `react/no-unescaped-entities` from [eslint-plugin-react] is incompatible with it, `mdx/no-unescaped-entities` is the replacement. +Inline JSX like `Inline ` is supported by [MDX][], but rule `react/no-unescaped-entities` from [eslint-plugin-react][] is incompatible with it, `mdx/no-unescaped-entities` is the replacement. ### mdx/no-unused-expressions -[MDX] can render `jsx` block automatically without exporting them, but [ESLint] will report `no-unused-expressions` issue which could be unexpected, this rule is a replacement of it, so make sure that you've turned off the original `no-unused-expressions` rule. +[MDX][] can render `jsx` block automatically without exporting them, but [ESLint][] will report `no-unused-expressions` issue which could be unexpected, this rule is a replacement of it, so make sure that you've turned off the original `no-unused-expressions` rule. ### mdx/remark _possible fixable depends on your remark plugins_: -Integration with [remark] plugins without [remark-lint], it will read [remark's configuration](https://github.com/remarkjs/remark/tree/master/packages/remark-cli#remark-cli) automatically via [cosmiconfig]. But `.remarkignore` will not be respected, you should use `.eslintignore` instead. +Integration with [remark][] plugins without [remark-lint][], it will read [remark's configuration](https://github.com/remarkjs/remark/tree/master/packages/remark-cli#remark-cli) automatically via [cosmiconfig][]. But `.remarkignore` will not be respected, you should use `.eslintignore` instead. ## Changelog @@ -150,7 +152,7 @@ Detailed changes for each release are documented in [CHANGELOG.md](./CHANGELOG.m ## License -[MIT] © [JounQin]@[1stG.me] +[MIT][] © [JounQin][]@[1stG.me][] [1stg.me]: https://www.1stg.me [cosmiconfig]: https://github.com/davidtheclark/cosmiconfig @@ -160,7 +162,6 @@ Detailed changes for each release are documented in [CHANGELOG.md](./CHANGELOG.m [lerna]: https://github.com/lerna/lerna [mdx]: https://github.com/mdx-js/mdx [mit]: http://opensource.org/licenses/MIT -[markdownlint]: https://github.com/markdownlint/markdownlint [remark]: https://github.com/remarkjs/remark [remark-lint]: https://github.com/remarkjs/remark-lint [vscode eslint]: https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint diff --git a/packages/eslint-plugin-mdx/src/rules/remark.ts b/packages/eslint-plugin-mdx/src/rules/remark.ts index 08e259fc..a82ca4f4 100644 --- a/packages/eslint-plugin-mdx/src/rules/remark.ts +++ b/packages/eslint-plugin-mdx/src/rules/remark.ts @@ -1,6 +1,6 @@ import path from 'path' -import { DEFAULT_EXTENSIONS } from 'eslint-mdx' +import { DEFAULT_EXTENSIONS, MARKDOWN_EXTENSIONS } from 'eslint-mdx' import vfile from 'vfile' import { getRemarkProcessor } from './helper' @@ -27,6 +27,8 @@ export const remark: Rule.RuleModule = { const sourceCode = context.getSourceCode() const extensions = DEFAULT_EXTENSIONS.concat( context.parserOptions.extensions || [], + MARKDOWN_EXTENSIONS, + context.parserOptions.markdownExtensions || [], ) return { Program(node) { diff --git a/test/__snapshots__/fixtures.test.ts.snap b/test/__snapshots__/fixtures.test.ts.snap index 93ad306b..a39fc167 100644 --- a/test/__snapshots__/fixtures.test.ts.snap +++ b/test/__snapshots__/fixtures.test.ts.snap @@ -72,6 +72,8 @@ Here's a YouTube shortcode: " `; +exports[`fixtures should match all snapshots: markdown.md 1`] = `undefined`; + exports[`fixtures should match all snapshots: no-jsx-html-comments.mdx 1`] = ` "# Title @@ -105,7 +107,4 @@ Header
" `; -exports[`fixtures should match all snapshots: remark.mdx 1`] = ` -"_Hello_, **world**! -" -`; +exports[`fixtures should match all snapshots: remark.mdx 1`] = `undefined`; diff --git a/test/fixtures.test.ts b/test/fixtures.test.ts index c650d058..27e04257 100644 --- a/test/fixtures.test.ts +++ b/test/fixtures.test.ts @@ -10,7 +10,7 @@ export const cli = new CLIEngine({ describe('fixtures', () => { it('should match all snapshots', () => { cli - .executeOnFiles(['test/fixtures/*.mdx']) + .executeOnFiles(['test/fixtures/*.{md,mdx}']) .results.forEach(({ filePath, output, source }) => expect(output || source).toMatchSnapshot(basename(filePath)), ) diff --git a/test/fixtures/markdown.md b/test/fixtures/markdown.md new file mode 100644 index 00000000..0ca25d9f --- /dev/null +++ b/test/fixtures/markdown.md @@ -0,0 +1 @@ +
diff --git a/test/parser.test.ts b/test/parser.test.ts index 2623c9af..70c765a4 100644 --- a/test/parser.test.ts +++ b/test/parser.test.ts @@ -205,4 +205,12 @@ describe('parser', () => { }), ).not.toThrow() }) + + it('should work with plain markdown file', () => + expect(() => + parser.parse('
', { + ...parserOptions, + filePath: 'test.md', + }), + ).not.toThrow()) })