Skip to content

Commit 8d094f9

Browse files
authored
Add support for eslint v8(beta) (#221)
* Add test for eslint v8 * fix test for eslint 6 * update ci * fix * fix test for eslint 5 * fix test for eslint 5 * revert peer dep * add eslint 8.0.0-0 to peer deps
1 parent 0ced952 commit 8d094f9

File tree

7 files changed

+397
-73
lines changed

7 files changed

+397
-73
lines changed

.github/workflows/test.yml

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,29 @@ env:
88
CI: true
99

1010
jobs:
11+
lint:
12+
name: 'Lint'
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v2
17+
- name: Setup Node.js
18+
uses: actions/setup-node@v2
19+
with:
20+
node-version: 14
21+
- name: Install
22+
run: yarn install
23+
- name: Lint
24+
run: yarn lint
25+
- name: Lint docs
26+
run: yarn lint:docs
1127
test:
12-
name: 'Test on Node.js ${{ matrix.node }} OS: ${{matrix.os}}'
28+
name: 'Test for ESLint 7 on Node.js ${{ matrix.node }} OS: ${{matrix.os}}'
1329
runs-on: ${{ matrix.os }}
1430
strategy:
1531
matrix:
1632
os: [ubuntu-latest]
17-
node: [10, 12, 14]
33+
node: [10, 12, 14, 16]
1834
steps:
1935
- name: Checkout
2036
uses: actions/checkout@v2
@@ -24,13 +40,28 @@ jobs:
2440
node-version: ${{ matrix.node }}
2541
- name: Install
2642
run: yarn install
27-
- name: Lint
28-
run: yarn lint
29-
- name: Lint docs
30-
run: yarn lint:docs
3143
- name: Test
3244
run: yarn test
3345
- name: Integration Test
3446
run: |
3547
yarn build
3648
yarn test:integrations
49+
test-for-eslint:
50+
name: 'Test for ESLint ${{ matrix.eslint }} on ${{ matrix.node }} OS: ${{matrix.os}}'
51+
runs-on: ${{ matrix.os }}
52+
strategy:
53+
matrix:
54+
os: [ubuntu-latest]
55+
eslint: [5, 6, ^8.0.0-0]
56+
node: [14]
57+
steps:
58+
- name: Checkout
59+
uses: actions/checkout@v2
60+
- name: Setup Node.js ${{ matrix.node }}
61+
uses: actions/setup-node@v2
62+
with:
63+
node-version: ${{ matrix.node }}
64+
- name: Install
65+
run: yarn add eslint@${{ matrix.eslint }}
66+
- name: Test
67+
run: yarn test

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
"eslint-config-prettier": "^8.0.0",
5757
"eslint-plugin-markdown": "^2.0.0",
5858
"eslint-plugin-prettier": "^3.1.4",
59+
"eslint-plugin-vue": "^7.16.0",
5960
"eslint-plugin-vue-libs": "^3.0.0 || ^4.0.0",
6061
"eslint4b": "^7.16.0",
6162
"lerna-changelog": "^1.0.1",
@@ -94,7 +95,7 @@
9495
"license": "MIT",
9596
"main": "dist/index.js",
9697
"peerDependencies": {
97-
"eslint": "^5.0.0 || ^6.0.0 || ^7.0.0"
98+
"eslint": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0"
9899
},
99100
"repository": {
100101
"type": "git",

tests/lib/rules/no-unused-keys.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { RuleTester } from 'eslint'
55
import { join } from 'path'
66
import rule = require('../../../lib/rules/no-unused-keys')
77
import { testOnFixtures } from '../test-utils'
8+
import semver from 'semver'
89

910
new RuleTester({
1011
parser: require.resolve('vue-eslint-parser'),
@@ -1003,6 +1004,10 @@ describe('no-unused-keys with fixtures', () => {
10031004

10041005
describe('valid', () => {
10051006
it('should be not detected unsued keys', async () => {
1007+
// eslint-disable-next-line @typescript-eslint/no-var-requires -- ignore
1008+
if (!semver.satisfies(require('eslint/package.json').version, '>=6')) {
1009+
return
1010+
}
10061011
await testOnFixtures(
10071012
{
10081013
cwd: join(cwdRoot, './valid/vue-cli-format'),
@@ -1019,6 +1024,10 @@ describe('no-unused-keys with fixtures', () => {
10191024
})
10201025

10211026
it('should be not detected unsued keys for constructor-option-format', async () => {
1027+
// eslint-disable-next-line @typescript-eslint/no-var-requires -- ignore
1028+
if (!semver.satisfies(require('eslint/package.json').version, '>=6')) {
1029+
return
1030+
}
10221031
await testOnFixtures(
10231032
{
10241033
cwd: join(cwdRoot, './valid/constructor-option-format'),
@@ -1038,6 +1047,10 @@ describe('no-unused-keys with fixtures', () => {
10381047
})
10391048

10401049
it('should be not detected unsued keys for multiple-locales', async () => {
1050+
// eslint-disable-next-line @typescript-eslint/no-var-requires -- ignore
1051+
if (!semver.satisfies(require('eslint/package.json').version, '>=6')) {
1052+
return
1053+
}
10411054
await testOnFixtures(
10421055
{
10431056
cwd: join(cwdRoot, './valid/multiple-locales'),
@@ -1066,6 +1079,10 @@ describe('no-unused-keys with fixtures', () => {
10661079

10671080
describe('invalid', () => {
10681081
it('should be detected unsued keys', async () => {
1082+
// eslint-disable-next-line @typescript-eslint/no-var-requires -- ignore
1083+
if (!semver.satisfies(require('eslint/package.json').version, '>=6')) {
1084+
return
1085+
}
10691086
const fixallEn = `{
10701087
"hello": "hello world",
10711088
"messages": {
@@ -1251,6 +1268,10 @@ hello_dio: "こんにちは、アンダースコア DIO!"
12511268
})
12521269

12531270
it('should be detected unsued keys for constructor-option-format', async () => {
1271+
// eslint-disable-next-line @typescript-eslint/no-var-requires -- ignore
1272+
if (!semver.satisfies(require('eslint/package.json').version, '>=6')) {
1273+
return
1274+
}
12541275
const fixall = `{
12551276
"en": {
12561277
"hello": "hello world",
@@ -1541,6 +1562,10 @@ hello_dio: "こんにちは、アンダースコア DIO!"
15411562
})
15421563

15431564
it('should be detected unsued keys for multiple-locales', async () => {
1565+
// eslint-disable-next-line @typescript-eslint/no-var-requires -- ignore
1566+
if (!semver.satisfies(require('eslint/package.json').version, '>=6')) {
1567+
return
1568+
}
15441569
await testOnFixtures(
15451570
{
15461571
cwd: join(cwdRoot, './invalid/multiple-locales'),
@@ -1799,6 +1824,10 @@ hello_dio: "こんにちは、アンダースコア DIO!"
17991824
})
18001825

18011826
it('should be detected unsued keys with typescript', async () => {
1827+
// eslint-disable-next-line @typescript-eslint/no-var-requires -- ignore
1828+
if (!semver.satisfies(require('eslint/package.json').version, '>=6')) {
1829+
return
1830+
}
18021831
await testOnFixtures(
18031832
{
18041833
cwd: join(cwdRoot, './invalid/typescript'),

tests/lib/source-code-fixer.ts

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
/**
2+
* Copy from https://github.com/eslint/eslint/blob/master/lib/linter/source-code-fixer.js
3+
* @see https://github.com/eslint/eslint/issues/14936
4+
*/
5+
/**
6+
* @fileoverview An object that caches and applies source code fixes.
7+
* @author Nicholas C. Zakas
8+
*/
9+
10+
import type { Linter } from 'eslint'
11+
12+
// ------------------------------------------------------------------------------
13+
// Requirements
14+
// ------------------------------------------------------------------------------
15+
16+
// const debug = require("debug")("eslint:source-code-fixer");
17+
type Message = {
18+
fix?: Linter.LintMessage['fix']
19+
}
20+
21+
type HasFixMessage = Message & {
22+
fix: NonNullable<Message['fix']>
23+
}
24+
25+
function hasFixMessage(m: Message): m is HasFixMessage {
26+
return !!m.fix
27+
}
28+
// ------------------------------------------------------------------------------
29+
// Helpers
30+
// ------------------------------------------------------------------------------
31+
32+
const BOM = '\uFEFF'
33+
34+
/**
35+
* Compares items in a messages array by range.
36+
* @param {Message} a The first message.
37+
* @param {Message} b The second message.
38+
* @returns {int} -1 if a comes before b, 1 if a comes after b, 0 if equal.
39+
* @private
40+
*/
41+
function compareMessagesByFixRange(a: HasFixMessage, b: HasFixMessage) {
42+
return a.fix.range[0] - b.fix.range[0] || a.fix.range[1] - b.fix.range[1]
43+
}
44+
45+
/**
46+
* Compares items in a messages array by line and column.
47+
* @param {Message} a The first message.
48+
* @param {Message} b The second message.
49+
* @returns {int} -1 if a comes before b, 1 if a comes after b, 0 if equal.
50+
* @private
51+
*/
52+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- ignore
53+
function compareMessagesByLocation(a: any, b: any) {
54+
return a.line - b.line || a.column - b.column
55+
}
56+
57+
// ------------------------------------------------------------------------------
58+
// Public Interface
59+
// ------------------------------------------------------------------------------
60+
61+
/**
62+
* Utility for apply fixes to source code.
63+
* @constructor
64+
*/
65+
export class SourceCodeFixer {
66+
/**
67+
* Applies the fixes specified by the messages to the given text. Tries to be
68+
* smart about the fixes and won't apply fixes over the same area in the text.
69+
* @param {string} sourceText The text to apply the changes to.
70+
* @param {Message[]} messages The array of messages reported by ESLint.
71+
* @param {boolean|Function} [shouldFix=true] Determines whether each message should be fixed
72+
* @returns {Object} An object containing the fixed text and any unfixed messages.
73+
*/
74+
static applyFixes<M extends Message>(
75+
sourceText: string,
76+
messages: M[],
77+
shouldFix: boolean | ((m: M) => boolean) = true
78+
): {
79+
fixed: boolean
80+
messages: M[]
81+
output: string
82+
} {
83+
// debug("Applying fixes");
84+
85+
if (shouldFix === false) {
86+
// debug("shouldFix parameter was false, not attempting fixes");
87+
return {
88+
fixed: false,
89+
messages,
90+
output: sourceText
91+
}
92+
}
93+
94+
// clone the array
95+
const remainingMessages = []
96+
const fixes: (HasFixMessage & M)[] = []
97+
const bom = sourceText.startsWith(BOM) ? BOM : ''
98+
const text = bom ? sourceText.slice(1) : sourceText
99+
let lastPos = Number.NEGATIVE_INFINITY
100+
let output = bom
101+
102+
/**
103+
* Try to use the 'fix' from a problem.
104+
* @param {Message} problem The message object to apply fixes from
105+
* @returns {boolean} Whether fix was successfully applied
106+
*/
107+
function attemptFix(problem: HasFixMessage) {
108+
const fix = problem.fix
109+
const start = fix.range[0]
110+
const end = fix.range[1]
111+
112+
// Remain it as a problem if it's overlapped or it's a negative range
113+
if (lastPos >= start || start > end) {
114+
remainingMessages.push(problem)
115+
return false
116+
}
117+
118+
// Remove BOM.
119+
if (
120+
(start < 0 && end >= 0) ||
121+
(start === 0 && fix.text.startsWith(BOM))
122+
) {
123+
output = ''
124+
}
125+
126+
// Make output to this fix.
127+
output += text.slice(Math.max(0, lastPos), Math.max(0, start))
128+
output += fix.text
129+
lastPos = end
130+
return true
131+
}
132+
133+
messages.forEach(problem => {
134+
if (hasFixMessage(problem)) {
135+
fixes.push(problem)
136+
} else {
137+
remainingMessages.push(problem)
138+
}
139+
})
140+
141+
if (fixes.length) {
142+
// debug("Found fixes to apply");
143+
let fixesWereApplied = false
144+
145+
for (const problem of fixes.sort(compareMessagesByFixRange)) {
146+
if (typeof shouldFix !== 'function' || shouldFix(problem)) {
147+
attemptFix(problem)
148+
149+
/*
150+
* The only time attemptFix will fail is if a previous fix was
151+
* applied which conflicts with it. So we can mark this as true.
152+
*/
153+
fixesWereApplied = true
154+
} else {
155+
remainingMessages.push(problem)
156+
}
157+
}
158+
output += text.slice(Math.max(0, lastPos))
159+
160+
return {
161+
fixed: fixesWereApplied,
162+
messages: remainingMessages.sort(compareMessagesByLocation),
163+
output
164+
}
165+
}
166+
167+
// debug("No fixes to apply");
168+
return {
169+
fixed: false,
170+
messages,
171+
output: bom + text
172+
}
173+
}
174+
}

0 commit comments

Comments
 (0)