Skip to content

Commit

Permalink
feat: Support ESLint flat config (#5270)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jason3S authored Feb 18, 2024
1 parent 6008e95 commit ac583af
Show file tree
Hide file tree
Showing 48 changed files with 2,609 additions and 33 deletions.
3 changes: 1 addition & 2 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ const config = {
'packages/*/fixtures/**',
'packages/*/esm/**',
'test-fixtures/**',
'test-packages/*/test-cspell-eslint-plugin',
'test-packages/*/test-cspell-eslint-plugin/**',
'test-packages/*/test-cspell-eslint-plugin*/**',
'test-packages/yarn/**',
'website',
'**/lib-bundled/**',
Expand Down
2 changes: 1 addition & 1 deletion cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
"packages/cspell-lib/fixtures/**",
"temp",
"test-fixtures/**",
"test-packages/*/test-cspell-eslint-plugin/**",
"test-packages/*/test-cspell-eslint-plugin*/**",
"test-packages/examples/example-cspell-lib-single-doc/samples/**",
"test-packages/*/test-cspell-tools/src/*.txt"
],
Expand Down
102 changes: 98 additions & 4 deletions packages/cspell-eslint-plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,68 @@ This plugin is still in active development as part of the CSpell suite of tools
npm install --save-dev @cspell/eslint-plugin
```

- Add to it to `.eslintrc.json`
- Add the plugin to the ESLint configuration (see below:)
- [Configuration (new: `eslint.config.js`)](#configuration-new-eslintconfigjs)
- [Configuration (Legacy: `.eslintrc`)](#configuration-legacy-eslintrc)

```json
### Configuration (new: `eslint.config.js`)

**`eslint.config.js` using recommended.**

```js
import cspellESLintPluginRecommended from '@cspell/eslint-plugin/recommended';

export default [
// other config imports
cspellESLintPluginRecommended
// other configs
];
```

**Or**

**`eslint.config.js` using configs.**

```js
import cspellConfigs from '@cspell/eslint-plugin/configs';

export default [
// other config imports
cspellConfigs.recommended
// other configs
];
```

**Or**

**`eslint.config.js` using `plugins`**

```js
import cspellPlugin from '@cspell/eslint-plugin';

export default [
// other config imports
{
plugins: { '@cspell': cspellPlugin },
rules: {
'@cspell/spellchecker': ['warn', {}]
}
}
// other configs
];
```

### Configuration (Legacy: `.eslintrc`)

Add `"plugin:@cspell/recommended"` to the `extends` section of the configuration.

**`.eslintrc`**

```json
{
"extends": ["plugin:@cspell/recommended"]
```
}
```

## Options

Expand Down Expand Up @@ -87,6 +144,11 @@ interface Options {
* Some CSpell Settings
*/
cspell?: {
/**
* The language locale to use, i.e. `en-US,en-GB` to enable both
* American and British English.
*/
language?: string;
/** List of words to be considered correct. */
words?: string[];
/**
Expand Down Expand Up @@ -141,7 +203,39 @@ interface Options {
}
````

Example:
Examples:

**`eslint.config.js`**

```js
import cspellPlugin from '@cspell/eslint-plugin';

export default [
{
plugins: { '@cspell': cspellPlugin },
rules: {
'@cspell/spellchecker': ['warn', { checkComments: false, autoFix: true }]
}
}
];
```

**`eslint.config.js`**

```js
import cspellConfigs from '@cspell/eslint-plugin/configs';

export default [
cspellConfigs.recommended,
{
rules: {
'@cspell/spellchecker': ['warn', { checkComments: false, autoFix: true }]
}
}
];
```

**`.eslintrc.json`**

```json
{
Expand Down
12 changes: 12 additions & 0 deletions packages/cspell-eslint-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@
"require": "./dist/plugin/index.cjs",
"import": "./dist/plugin/index.cjs",
"default": "./dist/plugin/index.cjs"
},
"./configs": {
"types": "./dist/plugin/configs.d.cts",
"require": "./dist/plugin/configs.cjs",
"import": "./dist/plugin/configs.cjs",
"default": "./dist/plugin/configs.cjs"
},
"./recommended": {
"types": "./dist/plugin/recommended.d.cts",
"require": "./dist/plugin/recommended.cjs",
"import": "./dist/plugin/recommended.cjs",
"default": "./dist/plugin/recommended.cjs"
}
},
"type": "module",
Expand Down
13 changes: 13 additions & 0 deletions packages/cspell-eslint-plugin/src/plugin/configs.cts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { Linter } from 'eslint';

import { plugin } from './cspell-eslint-plugin.cjs';
export * as recommended from './recommended.cjs';

export const debug: Linter.FlatConfig = {
plugins: {
'@cspell': plugin,
},
rules: {
'@cspell/spellchecker': ['warn', { debugMode: true }],
},
};
54 changes: 32 additions & 22 deletions packages/cspell-eslint-plugin/src/plugin/cspell-eslint-plugin.cts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// cspell:ignore TSESTree
import type { Rule } from 'eslint';
import type { ESLint, Rule } from 'eslint';
import { readFileSync } from 'fs';
import { join as pathJoin } from 'path';
import { createSyncFn } from 'synckit';
Expand All @@ -8,6 +8,8 @@ import { getDefaultLogger } from '../common/logger.cjs';
import type { Issue, SpellCheckFn } from '../worker/types.cjs';
import { normalizeOptions } from './defaultCheckOptions.cjs';

type ESlintPlugin = ESLint.Plugin;

const optionsSchema = JSON.parse(readFileSync(pathJoin(__dirname, '../../assets/options.schema.json'), 'utf8'));

const schema = optionsSchema as unknown as Rule.RuleMetaData['schema'];
Expand All @@ -29,10 +31,6 @@ interface ExtendedSuggestion {
wordAdjustedToMatchCase?: string;
}

interface PluginRules {
['spellchecker']: Rule.RuleModule;
}

const messages = {
wordUnknown: 'Unknown word: "{{word}}"',
wordForbidden: 'Forbidden word: "{{word}}"',
Expand All @@ -42,7 +40,7 @@ const messages = {
type Messages = typeof messages;
type MessageIds = keyof Messages;

const meta: Rule.RuleMetaData = {
const ruleMeta: Rule.RuleMetaData = {
docs: {
description: 'CSpell spellchecker',
category: 'Possible Errors',
Expand Down Expand Up @@ -136,13 +134,15 @@ function create(context: Rule.RuleContext): Rule.RuleListener {
return { Program: checkProgram };
}

export const rules: PluginRules = {
spellchecker: {
meta,
create,
},
const spellchecker: Rule.RuleModule = {
meta: ruleMeta,
create,
};

export const rules: { spellchecker: Rule.RuleModule } = {
spellchecker,
} satisfies ESlintPlugin['rules'];

function logContext(log: typeof console.log, context: Rule.RuleContext) {
log('context: %o', {
id: context.id,
Expand All @@ -154,17 +154,27 @@ function logContext(log: typeof console.log, context: Rule.RuleContext) {
});
}

export const configs = {
recommended: {
plugins: ['@cspell'],
rules: {
'@cspell/spellchecker': ['warn', {}],
},
export const meta = { name: '@cspell' } as const;

const recommended: ESLint.ConfigData = {
plugins: ['@cspell'],
rules: {
'@cspell/spellchecker': ['warn', {}],
},
debug: {
plugins: ['@cspell'],
rules: {
'@cspell/spellchecker': ['warn', { debugMode: true }],
},
};

const debugConfig: ESLint.ConfigData = {
plugins: ['@cspell'],
rules: {
'@cspell/spellchecker': ['warn', { debugMode: true }],
},
};

export const configs: ESlintPlugin['configs'] = {
debug: debugConfig,
'debug-legacy': debugConfig,
recommended,
'recommended-legacy': recommended,
};

export const plugin = { rules, configs, meta } satisfies ESlintPlugin;
4 changes: 3 additions & 1 deletion packages/cspell-eslint-plugin/src/plugin/index.cts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export type { Options } from '../common/options.cjs';
export { configs, rules } from './cspell-eslint-plugin.cjs';
import { plugin } from './cspell-eslint-plugin.cjs';
export { configs, meta, rules } from './cspell-eslint-plugin.cjs';
export default plugin;
7 changes: 4 additions & 3 deletions packages/cspell-eslint-plugin/src/plugin/index.test.cts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { RuleTester } from 'eslint';
import * as fs from 'fs';
import * as path from 'path';

import * as Rule from './index.cjs';
import type { Options as RuleOptions } from './index.cjs';
import Rule from './index.cjs';

const root = path.resolve(__dirname, '../..');
const fixturesDir = path.join(root, 'fixtures');
Expand All @@ -13,15 +14,15 @@ const parsers: Record<string, string | undefined> = {
};

type ValidTestCase = RuleTester.ValidTestCase;
type Options = Partial<Rule.Options>;
type Options = Partial<RuleOptions>;

const ruleTester = new RuleTester({
env: {
es6: true,
},

parserOptions: {
ecmaVersion: 2020,
ecmaVersion: 2022,
sourceType: 'module',
ecmaFeatures: {
modules: true,
Expand Down
15 changes: 15 additions & 0 deletions packages/cspell-eslint-plugin/src/plugin/recommended.cts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { Linter } from 'eslint';

import { plugin } from './cspell-eslint-plugin.cjs';

const config: Linter.FlatConfig = {
plugins: {
'@cspell': plugin,
},
rules: {
'@cspell/spellchecker': ['warn', {}],
},
};

export const plugins = config.plugins;
export const rules = config.rules;
Loading

0 comments on commit ac583af

Please sign in to comment.