@cookshack/eslint-config 2.0.5 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +544 -60
- package/dist/index.js +544 -60
- package/index.js +24 -465
- package/package.json +2 -2
- package/plugins/always-let.js +14 -0
- package/plugins/fn-decl-block-start.js +38 -0
- package/plugins/init-before-use.js +387 -0
- package/plugins/narrowest-scope.js +473 -0
- package/plugins/positive-vibes.js +27 -0
- package/plugins/use-risky-equal.js +11 -0
- package/plugins/var-decl-block-start.js +37 -0
- package/test/rules/always-let.js +46 -0
- package/test/rules/fn-decl-block-start.js +48 -0
- package/test/rules/init-before-use.js +192 -0
- package/test/rules/narrowest-scope.js +26 -0
- package/test/rules/use-risky-equal.js +42 -0
- package/test/rules/var-decl-block-start.js +108 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { Linter } from 'eslint'
|
|
2
|
+
import { plugins } from '../../index.js'
|
|
3
|
+
import { lastOst, ostString } from '../../plugins/init-before-use.js'
|
|
4
|
+
|
|
5
|
+
let linter, validCases, invalidCases, config
|
|
6
|
+
|
|
7
|
+
linter = new Linter()
|
|
8
|
+
validCases = []
|
|
9
|
+
invalidCases = []
|
|
10
|
+
|
|
11
|
+
config = [ { languageOptions: { ecmaVersion: 2025,
|
|
12
|
+
sourceType: 'module' },
|
|
13
|
+
plugins,
|
|
14
|
+
rules: { 'cookshack/init-before-use': 'error' } } ]
|
|
15
|
+
|
|
16
|
+
function tree
|
|
17
|
+
() {
|
|
18
|
+
let out
|
|
19
|
+
|
|
20
|
+
out = ostString(lastOst())
|
|
21
|
+
if (out.length)
|
|
22
|
+
return '=== Ordered Syntax Tree ===\n' + out
|
|
23
|
+
return ''
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function _pass(tc) {
|
|
27
|
+
let messages
|
|
28
|
+
|
|
29
|
+
messages = linter.verify(tc.code, config)
|
|
30
|
+
if (messages.length > 0)
|
|
31
|
+
throw new Error('unexpected errors: ' + JSON.stringify(messages, null, 2) + '\n' + tree())
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function _fail(tc) {
|
|
35
|
+
let messages
|
|
36
|
+
|
|
37
|
+
messages = linter.verify(tc.code, config)
|
|
38
|
+
if (messages.length == tc.errors.length)
|
|
39
|
+
return
|
|
40
|
+
throw new Error('expected ' + tc.errors.length + ' errors, got ' + messages.length + '\n' + JSON.stringify(messages, null, 2) + '\n' + tree())
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function fail(message, code) {
|
|
44
|
+
let errors
|
|
45
|
+
|
|
46
|
+
if (Array.isArray(message))
|
|
47
|
+
errors = message.map(m => ({ messageId: m }))
|
|
48
|
+
else
|
|
49
|
+
errors = [ { messageId: message } ]
|
|
50
|
+
|
|
51
|
+
invalidCases.push({ code, errors })
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function pass(code) {
|
|
55
|
+
validCases.push({ code })
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
pass('let x; x = 1')
|
|
59
|
+
|
|
60
|
+
pass('let x = 1; x')
|
|
61
|
+
|
|
62
|
+
pass('function f() { let x = 1; return x }')
|
|
63
|
+
|
|
64
|
+
pass('let x; function shadow() { let x = 2; return x } function shadow2() { let x = 3; return x } x = 1')
|
|
65
|
+
|
|
66
|
+
pass('for (let x in [1,2,3]) {}; let x = 1')
|
|
67
|
+
|
|
68
|
+
pass(`for (let tc of validCases)
|
|
69
|
+
globalThis.it(tc.code, () => _valid(tc))
|
|
70
|
+
`)
|
|
71
|
+
|
|
72
|
+
pass(`for (let tc of validCases)
|
|
73
|
+
globalThis.it(tc.code, () => _valid(tc))
|
|
74
|
+
for (let tc of invalidCases)
|
|
75
|
+
globalThis.it(tc.code, () => _invalid(tc))
|
|
76
|
+
`)
|
|
77
|
+
|
|
78
|
+
pass('let x; let y = { x: 1 }; x = 2')
|
|
79
|
+
|
|
80
|
+
pass('function x() { }')
|
|
81
|
+
|
|
82
|
+
pass(`function a1
|
|
83
|
+
() {
|
|
84
|
+
let p
|
|
85
|
+
|
|
86
|
+
function a2
|
|
87
|
+
() {
|
|
88
|
+
return p[p.length - 1]
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
p = []
|
|
92
|
+
return a2(0)
|
|
93
|
+
}`)
|
|
94
|
+
|
|
95
|
+
pass('let x = 1; --x')
|
|
96
|
+
|
|
97
|
+
pass('let x = 1; x++')
|
|
98
|
+
|
|
99
|
+
pass('let x = 1; x += 2')
|
|
100
|
+
|
|
101
|
+
pass("import globals from 'globals'")
|
|
102
|
+
|
|
103
|
+
pass('let x, y; y = () => { return x }; x = 1')
|
|
104
|
+
|
|
105
|
+
// it's actually an err, but we'd have to track assignments
|
|
106
|
+
pass('let x, y; y = () => { return x }; y(); x = 1')
|
|
107
|
+
|
|
108
|
+
pass('let i; for (i = addr; i < end; i++) {}')
|
|
109
|
+
|
|
110
|
+
pass('for (let i = 0; i < 16; i++) { }')
|
|
111
|
+
|
|
112
|
+
pass(`
|
|
113
|
+
for (let count = 0, i = 0; i < Ed.ctags.length; i++)
|
|
114
|
+
if (Ed.ctags[i].name.startsWith(word.text)) {
|
|
115
|
+
options.push({ label: Ed.ctags[i].name, type: Ed.ctags[i].kind })
|
|
116
|
+
if (count++ > 10)
|
|
117
|
+
break
|
|
118
|
+
}
|
|
119
|
+
`)
|
|
120
|
+
|
|
121
|
+
pass(`
|
|
122
|
+
function equal
|
|
123
|
+
() {
|
|
124
|
+
let two
|
|
125
|
+
|
|
126
|
+
function run
|
|
127
|
+
() {
|
|
128
|
+
console.log(two)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function open
|
|
132
|
+
() {
|
|
133
|
+
// the point is to test if this will accidentally be first write of two
|
|
134
|
+
two = 0
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (globalThis.x) {
|
|
138
|
+
two = 1
|
|
139
|
+
run()
|
|
140
|
+
}
|
|
141
|
+
}`)
|
|
142
|
+
|
|
143
|
+
fail('mustInit', 'let x')
|
|
144
|
+
|
|
145
|
+
fail('initBeforeUse', 'x; let x = 1')
|
|
146
|
+
|
|
147
|
+
fail('initBeforeUse', 'f(); let f = () => {}')
|
|
148
|
+
|
|
149
|
+
fail('mustInit', 'console.log(x); let x')
|
|
150
|
+
|
|
151
|
+
fail([ 'initBeforeUse', 'initBeforeUse' ], 'x; y; let x = 1; let y = 2')
|
|
152
|
+
|
|
153
|
+
fail('initBeforeUse', 'for (x in [1,2,3]) {}; let x = 1')
|
|
154
|
+
|
|
155
|
+
fail('mustInit', 'for (x in [1,2,3]) {}; let x')
|
|
156
|
+
|
|
157
|
+
fail('initBeforeUse', 'let x = f(); function f() { return x }')
|
|
158
|
+
|
|
159
|
+
fail('initBeforeUse', `function outer
|
|
160
|
+
(arg) {
|
|
161
|
+
let p
|
|
162
|
+
|
|
163
|
+
function inner
|
|
164
|
+
() {
|
|
165
|
+
p.focus()
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (arg) {
|
|
169
|
+
inner()
|
|
170
|
+
return
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
p = get()
|
|
174
|
+
inner()
|
|
175
|
+
}`)
|
|
176
|
+
|
|
177
|
+
fail('initBeforeUse', 'let x; x = f(x)')
|
|
178
|
+
|
|
179
|
+
fail('initBeforeUse', 'let x = 0; function shadow(y) { let x; x = shadow2(x) + y; return x } function shadow2(y) { let x = 3 + y; return x } shadow(x)')
|
|
180
|
+
|
|
181
|
+
fail('initBeforeUse', 'let x; --x')
|
|
182
|
+
|
|
183
|
+
fail('initBeforeUse', 'let x; x++')
|
|
184
|
+
|
|
185
|
+
fail('initBeforeUse', 'let x; x += 2')
|
|
186
|
+
|
|
187
|
+
globalThis.describe('init-before-use', () => {
|
|
188
|
+
for (let tc of validCases)
|
|
189
|
+
globalThis.it(tc.code, () => _pass(tc))
|
|
190
|
+
for (let tc of invalidCases)
|
|
191
|
+
globalThis.it(tc.code, () => _fail(tc))
|
|
192
|
+
})
|
|
@@ -472,6 +472,30 @@ function add
|
|
|
472
472
|
READ Map pos 75
|
|
473
473
|
WRITE classCache pos 80.4`)
|
|
474
474
|
|
|
475
|
+
pass(`function a1
|
|
476
|
+
() {
|
|
477
|
+
let p
|
|
478
|
+
|
|
479
|
+
function a2
|
|
480
|
+
() {
|
|
481
|
+
return p[p.length - 1]
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
p = []
|
|
485
|
+
return a2(0)
|
|
486
|
+
}`,
|
|
487
|
+
`SCOPE 1 GLOBAL pos 0
|
|
488
|
+
SCOPE 1.1 MODULE pos 0
|
|
489
|
+
LET a1 pos 9
|
|
490
|
+
SCOPE 1.1.1 FUNCTION pos 11 name a1
|
|
491
|
+
LET p pos 23
|
|
492
|
+
LET a2 pos 37
|
|
493
|
+
SCOPE 1.1.1.1 FUNCTION pos 39 name a2
|
|
494
|
+
READ p pos 58
|
|
495
|
+
READ p pos 60
|
|
496
|
+
WRITE p pos 87.4
|
|
497
|
+
READ a2 pos 97`)
|
|
498
|
+
|
|
475
499
|
fail(1, 'let x = 1; function foo() { return x }',
|
|
476
500
|
`SCOPE 1 GLOBAL pos 0
|
|
477
501
|
SCOPE 1.1 MODULE pos 0
|
|
@@ -538,12 +562,14 @@ function f
|
|
|
538
562
|
READ b pos 115
|
|
539
563
|
SCOPE 1.1.1.1.1 FUNCTION pos 125
|
|
540
564
|
LET d pos 125
|
|
565
|
+
READ c1 pos 138
|
|
541
566
|
READ d pos 144
|
|
542
567
|
WRITE c1 pos 145.4
|
|
543
568
|
READ c1 pos 164
|
|
544
569
|
SCOPE 1.1.1.2 BLOCK pos 174
|
|
545
570
|
READ ok pos 185
|
|
546
571
|
WRITE c2 pos 187.4
|
|
572
|
+
READ c2 pos 192
|
|
547
573
|
READ ok pos 198
|
|
548
574
|
READ ok pos 203
|
|
549
575
|
WRITE c2 pos 205.4
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { RuleTester } from 'eslint'
|
|
2
|
+
import { plugins } from '../../index.js'
|
|
3
|
+
|
|
4
|
+
let ruleTester, validCases, invalidCases
|
|
5
|
+
|
|
6
|
+
ruleTester = new RuleTester()
|
|
7
|
+
validCases = []
|
|
8
|
+
invalidCases = []
|
|
9
|
+
|
|
10
|
+
function pass
|
|
11
|
+
(code) {
|
|
12
|
+
validCases.push({ code })
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function fail
|
|
16
|
+
(count, code) {
|
|
17
|
+
let errors
|
|
18
|
+
|
|
19
|
+
errors = []
|
|
20
|
+
while (count > 0) {
|
|
21
|
+
errors.push({ messageId: 'risky' })
|
|
22
|
+
count--
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
invalidCases.push({ code, errors })
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
pass('if (x == y) { }')
|
|
29
|
+
|
|
30
|
+
pass('if (x != y) { }')
|
|
31
|
+
|
|
32
|
+
pass('if (x !== y) { }')
|
|
33
|
+
|
|
34
|
+
fail(1, 'if (x === y) { }')
|
|
35
|
+
|
|
36
|
+
fail(2, 'if (x === y || a === y || a > 4) { }')
|
|
37
|
+
|
|
38
|
+
globalThis.describe('use-risky-equal',
|
|
39
|
+
() => ruleTester.run('use-risky-equal',
|
|
40
|
+
plugins.cookshack.rules['use-risky-equal'],
|
|
41
|
+
{ valid: validCases,
|
|
42
|
+
invalid: invalidCases }))
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { RuleTester } from 'eslint'
|
|
2
|
+
import { plugins } from '../../index.js'
|
|
3
|
+
|
|
4
|
+
let ruleTester, validCases, invalidCases
|
|
5
|
+
|
|
6
|
+
ruleTester = new RuleTester()
|
|
7
|
+
validCases = []
|
|
8
|
+
invalidCases = []
|
|
9
|
+
|
|
10
|
+
function pass
|
|
11
|
+
(code) {
|
|
12
|
+
validCases.push({ code })
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function fail
|
|
16
|
+
(count, code) {
|
|
17
|
+
let errors
|
|
18
|
+
|
|
19
|
+
errors = []
|
|
20
|
+
while (count > 0) {
|
|
21
|
+
errors.push({ messageId: 'varDeclBlockStart' })
|
|
22
|
+
count--
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
invalidCases.push({ code, errors })
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
pass('let x = 1')
|
|
29
|
+
|
|
30
|
+
pass('var x = 1')
|
|
31
|
+
|
|
32
|
+
pass('const x = 1')
|
|
33
|
+
|
|
34
|
+
pass('{ let x = 1 }')
|
|
35
|
+
|
|
36
|
+
pass('{ var x = 1 }')
|
|
37
|
+
|
|
38
|
+
pass('{ const x = 1 }')
|
|
39
|
+
|
|
40
|
+
pass('{ let x = 1; let y = 2 }')
|
|
41
|
+
|
|
42
|
+
pass('{ let x, y }')
|
|
43
|
+
|
|
44
|
+
pass('{ let x; let y }')
|
|
45
|
+
|
|
46
|
+
pass('for (let i = 0; i < 10; i++) { }')
|
|
47
|
+
|
|
48
|
+
pass('for (var i = 0; i < 10; i++) { }')
|
|
49
|
+
|
|
50
|
+
pass('for (const i = 0; i < 10; i++) { }')
|
|
51
|
+
|
|
52
|
+
pass('for (let x of arr) { }')
|
|
53
|
+
|
|
54
|
+
pass('for (let x in obj) { }')
|
|
55
|
+
|
|
56
|
+
pass('for (var x in obj) { }')
|
|
57
|
+
|
|
58
|
+
pass('try { } catch (err) { }')
|
|
59
|
+
|
|
60
|
+
pass('function f() { let x }')
|
|
61
|
+
|
|
62
|
+
pass('function f() { var x }')
|
|
63
|
+
|
|
64
|
+
pass('function f() { const x = 1 }')
|
|
65
|
+
|
|
66
|
+
pass('{ { let x } }')
|
|
67
|
+
|
|
68
|
+
pass('{ { let x; let y } }')
|
|
69
|
+
|
|
70
|
+
fail(1, 'if (1) { x = 1; let y = 2 }')
|
|
71
|
+
|
|
72
|
+
fail(1, 'if (1) { x = 1; var y = 2 }')
|
|
73
|
+
|
|
74
|
+
fail(1, 'if (1) { x = 1; const y = 2 }')
|
|
75
|
+
|
|
76
|
+
fail(2, 'if (1) { x = 1; let y = 2; let z = 3 }')
|
|
77
|
+
|
|
78
|
+
fail(1, '{ x = 1; let y = 2 }')
|
|
79
|
+
|
|
80
|
+
fail(1, '{ x = 1; var y = 2 }')
|
|
81
|
+
|
|
82
|
+
fail(1, '{ x = 1; const y = 2 }')
|
|
83
|
+
|
|
84
|
+
fail(1, 'function f() { x = 1; let y = 2 }')
|
|
85
|
+
|
|
86
|
+
fail(1, 'function f() { x = 1; var y = 2 }')
|
|
87
|
+
|
|
88
|
+
fail(1, 'function f() { x = 1; const y = 2 }')
|
|
89
|
+
|
|
90
|
+
fail(1, '{ { x = 1; let y = 2 } }')
|
|
91
|
+
|
|
92
|
+
fail(1, 'if (1) { if (2) { x = 1; let y = 2 } }')
|
|
93
|
+
|
|
94
|
+
fail(1, 'while (1) { x = 1; let y = 2 }')
|
|
95
|
+
|
|
96
|
+
fail(1, 'for (let i = 0; i < 10; i++) { x = 1; let y = 2 }')
|
|
97
|
+
|
|
98
|
+
fail(1, '{ function f() {}; let x }')
|
|
99
|
+
|
|
100
|
+
fail(2, '{ function f() {}; let x; let y }')
|
|
101
|
+
|
|
102
|
+
fail(1, '{ function f() {}; function g() {}; let x }')
|
|
103
|
+
|
|
104
|
+
globalThis.describe('var-decl-block-start',
|
|
105
|
+
() => ruleTester.run('var-decl-block-start',
|
|
106
|
+
plugins.cookshack.rules['var-decl-block-start'],
|
|
107
|
+
{ valid: validCases,
|
|
108
|
+
invalid: invalidCases }))
|