Skip to content

Commit 4a70f1e

Browse files
authored
Chores: Replace CLIEngine with ESLint class. (#218)
* Chores: Replace CLIEngine with ESLint class. * fix * fix
1 parent c16156b commit 4a70f1e

File tree

13 files changed

+282
-115
lines changed

13 files changed

+282
-115
lines changed

docs/rules/README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,3 @@
3535
| Rule ID | Description | |
3636
|:--------|:------------|:---|
3737
| [@intlify/vue-i18n/<wbr>prefer-linked-key-with-paren](./prefer-linked-key-with-paren.html) | enforce linked key to be enclosed in parentheses | :black_nib: |
38-

lib/rules/no-unused-keys.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,7 @@ export = {
560560
recommended: false
561561
},
562562
fixable: 'code',
563+
hasSuggestions: true,
563564
schema: [
564565
{
565566
type: 'object',

lib/utils/collect-keys.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ function getParser(
9797
* Collect the used keys from source code text.
9898
* @param {string} text
9999
* @param {string} filename
100-
* @param {CLIEngine} cliEngine
101100
* @returns {string[]}
102101
*/
103102
function collectKeysFromText(

scripts/lib/eslint-compat.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// @ts-check
2+
import * as eslint from 'eslint'
3+
4+
// eslint-disable-next-line @typescript-eslint/no-namespace -- ignore
5+
export namespace ESLint {
6+
export type LintResult = eslint.ESLint.LintResult
7+
}
8+
export const ESLint = eslint.ESLint || getESLintClassForV6()
9+
10+
function getESLintClassForV6(): typeof eslint.ESLint {
11+
class ESLintForV6 {
12+
private engine: eslint.CLIEngine
13+
static get version() {
14+
return eslint.CLIEngine.version
15+
}
16+
17+
constructor(options?: eslint.ESLint.Options) {
18+
const {
19+
overrideConfig: { plugins, globals, rules, ...overrideConfig } = {
20+
plugins: [],
21+
globals: {},
22+
rules: {}
23+
},
24+
fix,
25+
reportUnusedDisableDirectives,
26+
plugins: pluginsMap,
27+
...otherOptions
28+
} = options || {}
29+
const newOptions: eslint.CLIEngine.Options = {
30+
fix: Boolean(fix),
31+
reportUnusedDisableDirectives: reportUnusedDisableDirectives
32+
? reportUnusedDisableDirectives !== 'off'
33+
: undefined,
34+
...otherOptions,
35+
36+
globals: globals
37+
? Object.keys(globals).filter(n => globals[n])
38+
: undefined,
39+
plugins: plugins || [],
40+
rules: rules
41+
? Object.entries(rules).reduce((o, [ruleId, opt]) => {
42+
if (opt) {
43+
o[ruleId] = opt
44+
}
45+
return o
46+
}, {} as NonNullable<eslint.CLIEngine.Options['rules']>)
47+
: undefined,
48+
...overrideConfig
49+
}
50+
this.engine = new eslint.CLIEngine(newOptions)
51+
52+
for (const [name, plugin] of Object.entries(pluginsMap || {})) {
53+
this.engine.addPlugin(name, plugin)
54+
}
55+
}
56+
57+
async lintText(
58+
...params: Parameters<eslint.ESLint['lintText']>
59+
): ReturnType<eslint.ESLint['lintText']> {
60+
const result = this.engine.executeOnText(params[0], params[1]?.filePath)
61+
return result.results
62+
}
63+
64+
async lintFiles(
65+
...params: Parameters<eslint.ESLint['lintFiles']>
66+
): ReturnType<eslint.ESLint['lintFiles']> {
67+
const result = this.engine.executeOnFiles(
68+
Array.isArray(params[0]) ? params[0] : [params[0]]
69+
)
70+
return result.results
71+
}
72+
}
73+
74+
const eslintClass = ESLintForV6 as never
75+
return eslintClass
76+
}

scripts/lib/utils.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
*/
66
import { readdirSync, existsSync } from 'fs'
77
import { basename, extname, join } from 'path'
8-
import { CLIEngine } from 'eslint'
9-
const linter = new CLIEngine({ fix: true })
8+
import { ESLint } from '../lib/eslint-compat'
9+
const eslint = new ESLint({ fix: true })
1010

11-
function format(text: string, filename: string): string {
12-
const lintResult = linter.executeOnText(text, filename)
13-
return lintResult.results[0].output || text
11+
async function format(text: string, filename: string): Promise<string> {
12+
const lintResults = await eslint.lintText(text, { filePath: filename })
13+
return lintResults[0].output || text
1414
}
1515

1616
/**
@@ -20,7 +20,11 @@ function camelCase(str: string) {
2020
return str.replace(/[-_](\w)/gu, (_, c) => (c ? c.toUpperCase() : ''))
2121
}
2222

23-
function createIndex(dirPath: string, prefix = '', all = false): string {
23+
async function createIndex(
24+
dirPath: string,
25+
prefix = '',
26+
all = false
27+
): Promise<string> {
2428
const dirName = basename(dirPath)
2529
const tsFiles = readdirSync(dirPath)
2630
.filter(

scripts/update-recommended-rules.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@ import { resolve } from 'path'
88
import rules from './lib/rules'
99
import { format } from './lib/utils'
1010

11-
// recommended.ts
12-
writeFileSync(
13-
resolve(__dirname, '../lib/configs/recommended.ts'),
14-
format(
15-
`/** DON'T EDIT THIS FILE; was created by scripts. */
11+
main()
12+
13+
async function main() {
14+
// recommended.ts
15+
writeFileSync(
16+
resolve(__dirname, '../lib/configs/recommended.ts'),
17+
await format(
18+
`/** DON'T EDIT THIS FILE; was created by scripts. */
1619
export = {
1720
extends: [require.resolve('./base')],
1821
parserOptions: {
@@ -33,6 +36,7 @@ export = {
3336
.join('\n ')}
3437
},
3538
}`,
36-
resolve(__dirname, '../lib/configs/recommended.ts')
39+
resolve(__dirname, '../lib/configs/recommended.ts')
40+
)
3741
)
38-
)
42+
}

scripts/update.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,16 @@ import './update-docs-index'
1515
// recommended rules.
1616
import './update-recommended-rules'
1717

18-
// indices.
19-
for (const pairs of [
20-
[resolve(__dirname, '../lib/configs')],
21-
[resolve(__dirname, '../lib/rules')],
22-
[resolve(__dirname, '../lib/utils'), '', true]
23-
] as const) {
24-
const [dirPath, prefix, all] = pairs
25-
writeFileSync(`${dirPath}.ts`, createIndex(dirPath, prefix, all))
18+
main()
19+
20+
async function main() {
21+
// indices.
22+
for (const pairs of [
23+
[resolve(__dirname, '../lib/configs')],
24+
[resolve(__dirname, '../lib/rules')],
25+
[resolve(__dirname, '../lib/utils'), '', true]
26+
] as const) {
27+
const [dirPath, prefix, all] = pairs
28+
writeFileSync(`${dirPath}.ts`, await createIndex(dirPath, prefix, all))
29+
}
2630
}

tests-integrations/config-recommended.js

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,20 @@ describe('Integration with "plugin:@intlify/vue-i18n/recommended"', () => {
1818
process.chdir(originalCwd)
1919
})
2020

21-
it('should work with shareable config', () => {
22-
const CLIEngine = require('./config-recommended/node_modules/eslint')
23-
.CLIEngine
24-
const engine = new CLIEngine({
21+
it('should work with shareable config', async () => {
22+
const ESLint = require('./config-recommended/node_modules/eslint').ESLint
23+
const engine = new ESLint({
2524
cwd: TEST_CWD,
2625
extensions: ['.js', '.vue', '.json']
2726
})
28-
const result = engine.executeOnFiles(['./src'])
29-
const enJson = result.results.find(
30-
r => path.basename(r.filePath) === 'en.json'
31-
)
27+
const results = await engine.lintFiles(['./src'])
28+
const enJson = results.find(r => path.basename(r.filePath) === 'en.json')
3229
assert.strictEqual(enJson.messages.length, 1)
3330
assert.strictEqual(
3431
enJson.messages[0].ruleId,
3532
'@intlify/vue-i18n/no-html-messages'
3633
)
37-
const aVue = result.results.find(r => path.basename(r.filePath) === 'a.vue')
34+
const aVue = results.find(r => path.basename(r.filePath) === 'a.vue')
3835
assert.strictEqual(aVue.messages.length, 1)
3936
assert.strictEqual(
4037
aVue.messages[0].ruleId,

0 commit comments

Comments
 (0)