Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions packages/eslint-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,20 @@
},
"license": "MIT",
"scripts": {
"build": "tsc"
"build": "tsc",
"watch": "tsc --watch"
},
"dependencies": {
"@typescript-eslint/utils": "^5.62.0",
"@typescript-eslint/utils": "^8.59.3",
"@typescript-eslint/types": "^8.59.3",
"tslib": "^2.6.0"
},
"devDependencies": {
"eslint-plugin-eslint-plugin": "^5.1.0"
"@typescript-eslint/rule-tester": "^8.59.3",
"eslint-plugin-eslint-plugin": "^6.5.0"
},
"peerDependencies": {
"eslint": ">=6"
"eslint": ">=8.57.0"
},
"engines": {
"node": ">=24.14"
Expand Down
53 changes: 41 additions & 12 deletions packages/eslint-plugin/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,57 @@
* LICENSE file in the root directory of this source tree.
*/

import {name, version} from '../package.json';

import rules from './rules';

// @ts-expect-error: TODO try to remove later
export = {
const plugin = {
meta: {name, version, namespace: '@docusaurus'},
rules,
};

const rulesRecommended = {
'@docusaurus/string-literal-i18n-messages': 'error',
'@docusaurus/no-html-links': 'warn',
'@docusaurus/prefer-docusaurus-heading': 'warn',
};

const rulesAll = {
'@docusaurus/string-literal-i18n-messages': 'error',
'@docusaurus/no-untranslated-text': 'warn',
'@docusaurus/no-html-links': 'warn',
'@docusaurus/prefer-docusaurus-heading': 'warn',
};

// Supports both legacy/flat configs:
// https://eslint.org/docs/latest/extend/plugins#backwards-compatibility-for-legacy-configs
const compatPlugin = {
...plugin,
configs: {
recommended: {
plugins: ['@docusaurus'],
rules: {
'@docusaurus/string-literal-i18n-messages': 'error',
'@docusaurus/no-html-links': 'warn',
'@docusaurus/prefer-docusaurus-heading': 'warn',
},
rules: rulesRecommended,
},
all: {
plugins: ['@docusaurus'],
rules: {
'@docusaurus/string-literal-i18n-messages': 'error',
'@docusaurus/no-untranslated-text': 'warn',
'@docusaurus/no-html-links': 'warn',
'@docusaurus/prefer-docusaurus-heading': 'warn',
rules: rulesAll,
},
flat: {
recommended: {
plugins: {
'@docusaurus': plugin,
},
rules: rulesRecommended,
},
all: {
plugins: {
'@docusaurus': plugin,
},
rules: rulesAll,
},
},
},
};

// @ts-expect-error: TODO try to remove later
export = compatPlugin;
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,10 @@
*/

import rule from '../no-html-links';
import {RuleTester} from './testUtils';
import {ruleTester} from './testUtils';

const errorsJSX = [{messageId: 'link'}] as const;

const ruleTester = new RuleTester({
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
});

ruleTester.run('prefer-docusaurus-link', rule, {
valid: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,10 @@
*/

import rule from '../no-untranslated-text';
import {getCommonValidTests, RuleTester} from './testUtils';
import {getCommonValidTests, ruleTester} from './testUtils';

const errorsJSX = [{messageId: 'translateChildren'}] as const;

const ruleTester = new RuleTester({
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
});

ruleTester.run('no-untranslated-text', rule, {
valid: [
...getCommonValidTests(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,10 @@
*/

import rule from '../prefer-docusaurus-heading';
import {RuleTester} from './testUtils';
import {ruleTester} from './testUtils';

const errorsJSX = [{messageId: 'headings'}] as const;

const ruleTester = new RuleTester({
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
});

ruleTester.run('prefer-docusaurus-heading', rule, {
valid: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,11 @@
*/

import rule from '../string-literal-i18n-messages';
import {getCommonValidTests, RuleTester} from './testUtils';
import {getCommonValidTests, ruleTester} from './testUtils';

const errorsJSX = [{messageId: 'translateChildren'}] as const;
const errorsFunc = [{messageId: 'translateArg'}] as const;

const ruleTester = new RuleTester({
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
});

ruleTester.run('string-literal-i18n-messages', rule, {
valid: [...getCommonValidTests()],

Expand Down
14 changes: 10 additions & 4 deletions packages/eslint-plugin/src/rules/__tests__/testUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
*/

import {afterAll, describe, it} from 'vitest';
import {ESLintUtils} from '@typescript-eslint/utils';

const {RuleTester} = ESLintUtils;
import {RuleTester} from '@typescript-eslint/rule-tester';

// `RuleTester` defers to globals when these are unset; we run with
// `globals: false`, so wire it to Vitest's test-framework functions instead.
Expand All @@ -17,7 +15,15 @@ RuleTester.describe = describe;
RuleTester.it = it;
RuleTester.itOnly = it.only;

export {RuleTester};
export const ruleTester = new RuleTester({
languageOptions: {
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
},
});

export const getCommonValidTests = (): {code: string}[] => [
{
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin/src/rules/no-html-links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import {createRule} from '../util';
import type {TSESTree} from '@typescript-eslint/types/dist/ts-estree';
import type {TSESTree} from '@typescript-eslint/types';

const docsUrl = 'https://docusaurus.io/docs/docusaurus-core#link';

Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin/src/rules/no-untranslated-text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import {isTextLabelChild, createRule} from '../util';
import type {TSESTree} from '@typescript-eslint/types/dist/ts-estree';
import type {TSESTree} from '@typescript-eslint/types';

type Options = [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import {createRule} from '../util';
import type {TSESTree} from '@typescript-eslint/types/dist/ts-estree';
import type {TSESTree} from '@typescript-eslint/types';

type Options = [];
type MessageIds = 'headings';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
isStringWithoutExpressions,
createRule,
} from '../util';
import type {TSESTree} from '@typescript-eslint/types/dist/ts-estree';
import type {TSESTree} from '@typescript-eslint/types';

type Options = [];
type MessageIds = 'translateChildren' | 'translateArg';
Expand Down
12 changes: 9 additions & 3 deletions packages/eslint-plugin/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/

import {ESLintUtils} from '@typescript-eslint/utils';
import type {TSESTree} from '@typescript-eslint/types/dist/ts-estree';
import {ESLintUtils, type TSESTree} from '@typescript-eslint/utils';

type CheckTranslateChildOptions = {
ignoredStrings?: string[];
Expand Down Expand Up @@ -61,7 +60,14 @@ export function isTextLabelChild(
}
}

export const createRule = ESLintUtils.RuleCreator(
// Not sure if we really need this
// See https://typescript-eslint.io/blog/announcing-typescript-eslint-v8/#custom-rule-metadocs-types
// See https://github.com/typescript-eslint/typescript-eslint/pull/9025
export interface PluginDocs {
recommended: boolean | 'error';
}

export const createRule = ESLintUtils.RuleCreator<PluginDocs>(
(name) =>
`https://docusaurus.io/docs/api/misc/@docusaurus/eslint-plugin/${name}`,
);
102 changes: 66 additions & 36 deletions website/docs/api/misc/eslint-plugin/README.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,77 @@ slug: /api/misc/@docusaurus/eslint-plugin

[ESLint](https://eslint.org/) is a tool that statically analyzes your code and reports problems or suggests best practices through editor hints and command line. Docusaurus provides an ESLint plugin to enforce best Docusaurus practices.

This ESLint plugin supports ESLint `>= 8.57.0`, flat configs and legacy configs.

## Installation {/* #installation */}

```bash npm2yarn
npm install --save-dev @docusaurus/eslint-plugin
```

## Usage {/* #usage */}
## Supported configs {/* #supported-configs */}

Both built-in configs exist in flat and legacy variants:

- Recommended: recommended rule set for most Docusaurus sites that should be extended from.
- All: **all** rules enabled. This will change between minor versions, so you should not use this if you want to avoid unexpected breaking changes.

## Supported rules {/* #supported-rules */}

| Name | Description | |
| --- | --- | --- |
| [`@docusaurus/no-untranslated-text`](./no-untranslated-text.mdx) | Enforce text labels in JSX to be wrapped by translate calls | |
| [`@docusaurus/string-literal-i18n-messages`](./string-literal-i18n-messages.mdx) | Enforce translate APIs to be called on plain text labels | ✅ |
| [`@docusaurus/no-html-links`](./no-html-links.mdx) | Ensures @docusaurus/Link is used instead of `<a>` tags | ✅ |
| [`@docusaurus/prefer-docusaurus-heading`](./prefer-docusaurus-heading.mdx) | Ensures @theme/Heading is used instead of `<hn>` tags for headings | ✅ |

✅ = recommended

## Usage - Flat {/* #usage-flat */}

### Recommended config {/* #recommended-config-flat */}

Import `@docusaurus/eslint-plugin` and add `docusaurus.configs.flat.recommended` to your flat config array:

```js title="eslint.config.js"
import {defineConfig} from 'eslint/config';
// highlight-next-line
import docusaurus from '@docusaurus/eslint-plugin';

export default defineConfig(
// highlight-next-line
docusaurus.configs.flat.recommended,
{
// Other config
},
);
```

This will enable the `@docusaurus` eslint plugin and use the `recommended` config. See [Supported rules](#supported-rules) above for a list of rules that this will enable.

### Manual config {/* #manual-config-flat */}

For more fine-grained control, you can also enable the plugin manually and configure the rules you want to use directly:

```js title="eslint.config.js"
import {defineConfig} from 'eslint/config';
// highlight-next-line
import docusaurus from '@docusaurus/eslint-plugin';

export default defineConfig({
// highlight-start
plugins: {docusaurus},
rules: {
'@docusaurus/string-literal-i18n-messages': 'error',
'@docusaurus/no-untranslated-text': 'warn',
},
// highlight-end
});
```

## Usage - Legacy {/* #usage-legacy */}

### Recommended config {/* #recommended-config */}
### Recommended config {/* #recommended-config-legacy */}

Add `plugin:@docusaurus/recommended` to the `extends` section of your `.eslintrc` configuration file:

Expand All @@ -25,9 +87,9 @@ Add `plugin:@docusaurus/recommended` to the `extends` section of your `.eslintrc
}
```

This will enable the `@docusaurus` eslint plugin and use the `recommended` config. See [Supported rules](#supported-rules) below for a list of rules that this will enable.
This will enable the `@docusaurus` eslint plugin and use the `recommended` config. See [Supported rules](#supported-rules) above for a list of rules that this will enable.

### Manual config {/* #manual-config */}
### Manual config {/* #manual-config-legacy */}

For more fine-grained control, you can also enable the plugin manually and configure the rules you want to use directly:

Expand All @@ -40,35 +102,3 @@ For more fine-grained control, you can also enable the plugin manually and confi
}
}
```

## Supported configs {/* #supported-configs */}

- Recommended: recommended rule set for most Docusaurus sites that should be extended from.
- All: **all** rules enabled. This will change between minor versions, so you should not use this if you want to avoid unexpected breaking changes.

## Supported rules {/* #supported-rules */}

| Name | Description | |
| --- | --- | --- |
| [`@docusaurus/no-untranslated-text`](./no-untranslated-text.mdx) | Enforce text labels in JSX to be wrapped by translate calls | |
| [`@docusaurus/string-literal-i18n-messages`](./string-literal-i18n-messages.mdx) | Enforce translate APIs to be called on plain text labels | ✅ |
| [`@docusaurus/no-html-links`](./no-html-links.mdx) | Ensures @docusaurus/Link is used instead of `<a>` tags | ✅ |
| [`@docusaurus/prefer-docusaurus-heading`](./prefer-docusaurus-heading.mdx) | Ensures @theme/Heading is used instead of `<hn>` tags for headings | ✅ |

✅ = recommended

## Example configuration {/* #example-configuration */}

Here's an example configuration:

```js title=".eslintrc.js"
module.exports = {
extends: ['plugin:@docusaurus/recommended'],
rules: {
'@docusaurus/no-untranslated-text': [
'warn',
{ignoredStrings: ['·', '—', '×']},
],
},
};
```
Loading
Loading