@cookshack/eslint-config 2.0.5 → 4.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.
@@ -0,0 +1,48 @@
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: 'fnDeclBlockStart' })
22
+ count--
23
+ }
24
+
25
+ invalidCases.push({ code, errors })
26
+ }
27
+
28
+ pass('function f() { let x; function g() {} }')
29
+
30
+ pass('{ function f() {} }')
31
+
32
+ pass('{ let x; function f() {} }')
33
+
34
+ pass('{ let x; let y; function f() {}; function g() {} }')
35
+
36
+ pass('{ function f() {}; function g() {}; code() }')
37
+
38
+ fail(1, 'function main2 () { let a; a = 0; function f() { return 1 } let b }')
39
+
40
+ fail(1, '{ x; function f() {} }')
41
+
42
+ fail(1, '{ let x; code(); function f() {} }')
43
+
44
+ globalThis.describe('fn-decl-block-start',
45
+ () => ruleTester.run('fn-decl-block-start',
46
+ plugins.cookshack.rules['fn-decl-block-start'],
47
+ { valid: validCases,
48
+ invalid: invalidCases }))
@@ -0,0 +1,198 @@
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
+ if (code == undefined) {
20
+ code = count
21
+ count = 1
22
+ }
23
+ errors = []
24
+ while (count > 0) {
25
+ errors.push({ messageId: 'indentStruct' })
26
+ count--
27
+ }
28
+ invalidCases.push({ code, errors })
29
+ }
30
+
31
+ pass('let x = { a: 1, b: 2 }')
32
+
33
+ pass(`
34
+ let x = {
35
+ a: 1,
36
+ b: 2
37
+ }`)
38
+
39
+ pass(`
40
+ let x = { a: 1,
41
+ b: 2 }`)
42
+
43
+ pass(`
44
+ let x = {
45
+ a
46
+ () {}
47
+ }`)
48
+
49
+ pass(`
50
+ let x = {
51
+ a
52
+ () {},
53
+ b
54
+ () {}
55
+ }`)
56
+
57
+ pass(`
58
+ function f
59
+ () {
60
+ return { a: 1,
61
+ b: 2 }
62
+ }`)
63
+
64
+ pass(`
65
+ function f1
66
+ () {
67
+ return { f1
68
+ () {
69
+ return 1
70
+ },
71
+ b: 2 }
72
+ }`)
73
+
74
+ pass(`
75
+ function f2
76
+ () {
77
+ return { a: 1,
78
+ f2
79
+ () {
80
+ return 2
81
+ } }
82
+ }`)
83
+
84
+ pass(`
85
+ let x = { a: 1,
86
+ b: 2 }
87
+ `)
88
+
89
+ pass(`
90
+ let x = { a: 1,
91
+ b: 2 } /*stuff {, } */
92
+ `)
93
+
94
+ pass(`
95
+ let x = { a: 1,
96
+ b: 2 } /*stuff*/
97
+ `)
98
+
99
+ pass(`
100
+ let x = { a: { a: 1,
101
+ b: 2 } }
102
+ `)
103
+
104
+ pass(`
105
+ let x = { a: { a: 1,
106
+ b: 2 } } ; function f(){ return 1}
107
+ `)
108
+
109
+ pass(`function create
110
+ (context) {
111
+ return { VariableDeclaration
112
+ (node) {
113
+ if (node.kind == 'const' || node.kind == 'var')
114
+ context.report({ node, messageId: 'useLet' })
115
+ } }
116
+ }`)
117
+
118
+ pass(`function two
119
+ () {
120
+ return { 'Program:exit'
121
+ () {
122
+ // do
123
+ } }
124
+ }`)
125
+
126
+ pass(`
127
+ let x = { get a
128
+ () {
129
+ return 1
130
+ },
131
+ get b
132
+ () {
133
+ return 2
134
+ } }`)
135
+
136
+ pass(`
137
+ let x = { async f
138
+ () {
139
+ return 1
140
+ },
141
+ async g
142
+ () {
143
+ return 2
144
+ } }`)
145
+
146
+ fail(2, `
147
+ let x = {
148
+ a: 1,
149
+ b: 2
150
+ }`)
151
+
152
+ fail(1, `
153
+ let x = {
154
+ a: 1,
155
+ b: 2
156
+ }`)
157
+
158
+ fail(1, `
159
+ let x = { a: 1,
160
+ b: 2 }`)
161
+
162
+ fail(1, `
163
+ let x = { a: 1,
164
+ b: 2 }`)
165
+
166
+ fail(1, `
167
+ let x = { a: 1,
168
+ b: 2 }`)
169
+
170
+ fail(2, `
171
+ let x = { a: 1,
172
+ b: 2,
173
+ c: 3 }`)
174
+
175
+ fail(1, `
176
+ let aHasArgsOnNextLine = { a
177
+ () {} }`)
178
+
179
+ fail(1, `
180
+ let x = { a: 1,
181
+ b: 2}
182
+ `)
183
+
184
+ fail(1, `
185
+ let x = { a: 1,
186
+ b: 2 }
187
+ `)
188
+
189
+ fail(1, `
190
+ let x = { a: { a: 1,
191
+ b: 2 } }
192
+ `)
193
+
194
+ globalThis.describe('indent-struct',
195
+ () => ruleTester.run('indent-struct',
196
+ plugins.cookshack.rules['indent-struct'],
197
+ { valid: validCases,
198
+ invalid: invalidCases }))
@@ -0,0 +1,196 @@
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
27
+ (tc) {
28
+ let messages
29
+
30
+ messages = linter.verify(tc.code, config)
31
+ if (messages.length > 0)
32
+ throw new Error('unexpected errors: ' + JSON.stringify(messages, null, 2) + '\n' + tree())
33
+ }
34
+
35
+ function _fail
36
+ (tc) {
37
+ let messages
38
+
39
+ messages = linter.verify(tc.code, config)
40
+ if (messages.length == tc.errors.length)
41
+ return
42
+ throw new Error('expected ' + tc.errors.length + ' errors, got ' + messages.length + '\n' + JSON.stringify(messages, null, 2) + '\n' + tree())
43
+ }
44
+
45
+ function fail
46
+ (message, code) {
47
+ let errors
48
+
49
+ if (Array.isArray(message))
50
+ errors = message.map(m => ({ messageId: m }))
51
+ else
52
+ errors = [ { messageId: message } ]
53
+
54
+ invalidCases.push({ code, errors })
55
+ }
56
+
57
+ function pass
58
+ (code) {
59
+ validCases.push({ code })
60
+ }
61
+
62
+ pass('let x; x = 1')
63
+
64
+ pass('let x = 1; x')
65
+
66
+ pass('function f() { let x = 1; return x }')
67
+
68
+ pass('let x; function shadow() { let x = 2; return x } function shadow2() { let x = 3; return x } x = 1')
69
+
70
+ pass('for (let x in [1,2,3]) {}; let x = 1')
71
+
72
+ pass(`for (let tc of validCases)
73
+ globalThis.it(tc.code, () => _valid(tc))
74
+ `)
75
+
76
+ pass(`for (let tc of validCases)
77
+ globalThis.it(tc.code, () => _valid(tc))
78
+ for (let tc of invalidCases)
79
+ globalThis.it(tc.code, () => _invalid(tc))
80
+ `)
81
+
82
+ pass('let x; let y = { x: 1 }; x = 2')
83
+
84
+ pass('function x() { }')
85
+
86
+ pass(`function a1
87
+ () {
88
+ let p
89
+
90
+ function a2
91
+ () {
92
+ return p[p.length - 1]
93
+ }
94
+
95
+ p = []
96
+ return a2(0)
97
+ }`)
98
+
99
+ pass('let x = 1; --x')
100
+
101
+ pass('let x = 1; x++')
102
+
103
+ pass('let x = 1; x += 2')
104
+
105
+ pass("import globals from 'globals'")
106
+
107
+ pass('let x, y; y = () => { return x }; x = 1')
108
+
109
+ // it's actually an err, but we'd have to track assignments
110
+ pass('let x, y; y = () => { return x }; y(); x = 1')
111
+
112
+ pass('let i; for (i = addr; i < end; i++) {}')
113
+
114
+ pass('for (let i = 0; i < 16; i++) { }')
115
+
116
+ pass(`
117
+ for (let count = 0, i = 0; i < Ed.ctags.length; i++)
118
+ if (Ed.ctags[i].name.startsWith(word.text)) {
119
+ options.push({ label: Ed.ctags[i].name, type: Ed.ctags[i].kind })
120
+ if (count++ > 10)
121
+ break
122
+ }
123
+ `)
124
+
125
+ pass(`
126
+ function equal
127
+ () {
128
+ let two
129
+
130
+ function run
131
+ () {
132
+ console.log(two)
133
+ }
134
+
135
+ function open
136
+ () {
137
+ // the point is to test if this will accidentally be first write of two
138
+ two = 0
139
+ }
140
+
141
+ if (globalThis.x) {
142
+ two = 1
143
+ run()
144
+ }
145
+ }`)
146
+
147
+ fail('mustInit', 'let x')
148
+
149
+ fail('initBeforeUse', 'x; let x = 1')
150
+
151
+ fail('initBeforeUse', 'f(); let f = () => {}')
152
+
153
+ fail('mustInit', 'console.log(x); let x')
154
+
155
+ fail([ 'initBeforeUse', 'initBeforeUse' ], 'x; y; let x = 1; let y = 2')
156
+
157
+ fail('initBeforeUse', 'for (x in [1,2,3]) {}; let x = 1')
158
+
159
+ fail('mustInit', 'for (x in [1,2,3]) {}; let x')
160
+
161
+ fail('initBeforeUse', 'let x = f(); function f() { return x }')
162
+
163
+ fail('initBeforeUse', `function outer
164
+ (arg) {
165
+ let p
166
+
167
+ function inner
168
+ () {
169
+ p.focus()
170
+ }
171
+
172
+ if (arg) {
173
+ inner()
174
+ return
175
+ }
176
+
177
+ p = get()
178
+ inner()
179
+ }`)
180
+
181
+ fail('initBeforeUse', 'let x; x = f(x)')
182
+
183
+ 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)')
184
+
185
+ fail('initBeforeUse', 'let x; --x')
186
+
187
+ fail('initBeforeUse', 'let x; x++')
188
+
189
+ fail('initBeforeUse', 'let x; x += 2')
190
+
191
+ globalThis.describe('init-before-use', () => {
192
+ for (let tc of validCases)
193
+ globalThis.it(tc.code, () => _pass(tc))
194
+ for (let tc of invalidCases)
195
+ globalThis.it(tc.code, () => _fail(tc))
196
+ })
@@ -13,16 +13,19 @@ config = [ { languageOptions: { ecmaVersion: 2025,
13
13
  plugins,
14
14
  rules: { 'cookshack/narrowest-scope': 'error' } } ]
15
15
 
16
- function pass(code, expected) {
16
+ function pass
17
+ (code, expected) {
17
18
  validCases.push({ code, expected })
18
19
  }
19
20
 
20
- function patch(expected, output) {
21
+ function patch
22
+ (expected, output) {
21
23
  return diffLines(expected.trim(), output.trim()).flatMap(p => p.value.split('\n').filter(l => l).map(l => ({ ...p, line: l })))
22
24
  .map(p => (p.removed ? '- ' : p.added ? '+ ' : ' ') + p.line).join('\n')
23
25
  }
24
26
 
25
- function _pass(tc) {
27
+ function _pass
28
+ (tc) {
26
29
  let messages, output
27
30
 
28
31
  messages = linter.verify(tc.code, config)
@@ -34,7 +37,8 @@ function _pass(tc) {
34
37
  throw new Error('output mismatch:\n' + patch(tc.expected, output))
35
38
  }
36
39
 
37
- function _fail(tc) {
40
+ function _fail
41
+ (tc) {
38
42
  let messages, output
39
43
 
40
44
  messages = linter.verify(tc.code, config)
@@ -47,7 +51,8 @@ function _fail(tc) {
47
51
  throw new Error('expected ' + tc.errors.length + ' errors, got ' + messages.length + '\n' + JSON.stringify(messages, null, 2))
48
52
  }
49
53
 
50
- function fail(count, code, expected) {
54
+ function fail
55
+ (count, code, expected) {
51
56
  let errors
52
57
 
53
58
  errors = []
@@ -472,6 +477,30 @@ function add
472
477
  READ Map pos 75
473
478
  WRITE classCache pos 80.4`)
474
479
 
480
+ pass(`function a1
481
+ () {
482
+ let p
483
+
484
+ function a2
485
+ () {
486
+ return p[p.length - 1]
487
+ }
488
+
489
+ p = []
490
+ return a2(0)
491
+ }`,
492
+ `SCOPE 1 GLOBAL pos 0
493
+ SCOPE 1.1 MODULE pos 0
494
+ LET a1 pos 9
495
+ SCOPE 1.1.1 FUNCTION pos 11 name a1
496
+ LET p pos 23
497
+ LET a2 pos 37
498
+ SCOPE 1.1.1.1 FUNCTION pos 39 name a2
499
+ READ p pos 58
500
+ READ p pos 60
501
+ WRITE p pos 87.4
502
+ READ a2 pos 97`)
503
+
475
504
  fail(1, 'let x = 1; function foo() { return x }',
476
505
  `SCOPE 1 GLOBAL pos 0
477
506
  SCOPE 1.1 MODULE pos 0
@@ -538,12 +567,14 @@ function f
538
567
  READ b pos 115
539
568
  SCOPE 1.1.1.1.1 FUNCTION pos 125
540
569
  LET d pos 125
570
+ READ c1 pos 138
541
571
  READ d pos 144
542
572
  WRITE c1 pos 145.4
543
573
  READ c1 pos 164
544
574
  SCOPE 1.1.1.2 BLOCK pos 174
545
575
  READ ok pos 185
546
576
  WRITE c2 pos 187.4
577
+ READ c2 pos 192
547
578
  READ ok pos 198
548
579
  READ ok pos 203
549
580
  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 }))