@cookshack/eslint-config 3.0.0 → 5.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/AGENTS.md +12 -0
- package/dist/formatter.cjs +2 -1
- package/dist/formatter.js +2 -1
- package/dist/index.cjs +344 -199
- package/dist/index.js +344 -199
- package/formatter.js +2 -1
- package/index.js +63 -67
- package/package.json +1 -1
- package/plugins/always-let.js +5 -4
- package/plugins/fn-args-nl.js +47 -0
- package/plugins/fn-decl-block-start.js +1 -2
- package/plugins/indent-struct.js +145 -0
- package/plugins/init-before-use.js +57 -62
- package/plugins/narrowest-scope.js +24 -25
- package/plugins/positive-vibes.js +15 -15
- package/plugins/use-risky-equal.js +7 -5
- package/plugins/var-decl-block-start.js +2 -2
- package/test/rules/fn-args-nl.js +114 -0
- package/test/rules/indent-struct.js +198 -0
- package/test/rules/init-before-use.js +8 -4
- package/test/rules/narrowest-scope.js +10 -5
- package/test/rules/no-shadow.js +42 -0
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@ function print
|
|
|
11
11
|
printBuffer.push(args.join(' '));
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
function trace$
|
|
14
|
+
function trace$2
|
|
15
15
|
(...args) {
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -120,7 +120,8 @@ function getConditionalContext
|
|
|
120
120
|
return ''
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
function nodeContains
|
|
123
|
+
function nodeContains
|
|
124
|
+
(node, target) {
|
|
124
125
|
if (node == target)
|
|
125
126
|
return true
|
|
126
127
|
if (node && typeof node == 'object')
|
|
@@ -130,7 +131,8 @@ function nodeContains(node, target) {
|
|
|
130
131
|
return false
|
|
131
132
|
}
|
|
132
133
|
|
|
133
|
-
function nodeHas
|
|
134
|
+
function nodeHas
|
|
135
|
+
(value, target) {
|
|
134
136
|
if (value == target)
|
|
135
137
|
return true
|
|
136
138
|
if (Array.isArray(value))
|
|
@@ -194,7 +196,8 @@ function mayBeReadBeforeAnyWrite
|
|
|
194
196
|
}
|
|
195
197
|
}
|
|
196
198
|
|
|
197
|
-
function scopeStart
|
|
199
|
+
function scopeStart
|
|
200
|
+
(scope) {
|
|
198
201
|
if (scope.block == null)
|
|
199
202
|
return Infinity
|
|
200
203
|
if (scope.type == 'function' && scope.block.id)
|
|
@@ -222,12 +225,11 @@ function buildScopeTree
|
|
|
222
225
|
(scope, prefix, scopeToNode, astToTree) {
|
|
223
226
|
let node, siblingNum;
|
|
224
227
|
|
|
225
|
-
node = {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
};
|
|
228
|
+
node = { scope,
|
|
229
|
+
prefix,
|
|
230
|
+
items: [],
|
|
231
|
+
children: [] };
|
|
232
|
+
|
|
231
233
|
scopeToNode.set(scope, node);
|
|
232
234
|
if (scope.block && astToTree)
|
|
233
235
|
astToTree.set(scope.block, node);
|
|
@@ -329,38 +331,36 @@ function checkScopeNode
|
|
|
329
331
|
|
|
330
332
|
defScope = getDefinitionScope(variable);
|
|
331
333
|
defNodePrefix = scopeToNode.get(defScope)?.prefix ?? '?';
|
|
332
|
-
trace$
|
|
334
|
+
trace$2(indent, '1 found decl scope of', variable.name + ':', defNodePrefix + ' ' + defScope.type.toUpperCase());
|
|
333
335
|
|
|
334
336
|
narrowestScope = getNarrowestScope(variable);
|
|
335
337
|
if (narrowestScope) {
|
|
336
338
|
let narrowestPrefix;
|
|
337
339
|
|
|
338
340
|
narrowestPrefix = scopeToNode.get(narrowestScope)?.prefix ?? '?';
|
|
339
|
-
trace$
|
|
341
|
+
trace$2(indent, '2 found narrowest scope of', variable.name + ':', narrowestPrefix + ' ' + narrowestScope?.type.toUpperCase());
|
|
340
342
|
|
|
341
343
|
markConditionalRefs(variable, scopeToNode, narrowestScope);
|
|
342
344
|
|
|
343
345
|
if (defScope == narrowestScope)
|
|
344
346
|
continue
|
|
345
|
-
trace$
|
|
347
|
+
trace$2(indent, '3', variable.name, 'could be moved to a narrower scope');
|
|
346
348
|
|
|
347
349
|
if (defScope.type == 'for') {
|
|
348
|
-
trace$
|
|
350
|
+
trace$2(indent, '4 exception:', variable.name, 'is in a for loop header');
|
|
349
351
|
continue
|
|
350
352
|
}
|
|
351
353
|
if (mayBeReadBeforeAnyWrite(variable, scopeToNode, narrowestScope)) {
|
|
352
|
-
trace$
|
|
354
|
+
trace$2(indent, '4 exception:', variable.name, 'mayBeReadBeforeAnyWrite');
|
|
353
355
|
continue
|
|
354
356
|
}
|
|
355
357
|
|
|
356
|
-
trace$
|
|
358
|
+
trace$2(indent, '5', variable.name, 'is too broad');
|
|
357
359
|
|
|
358
360
|
reported.add(variable);
|
|
359
|
-
context.report({
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
data: { name: variable.name }
|
|
363
|
-
});
|
|
361
|
+
context.report({ node: defNode,
|
|
362
|
+
messageId: 'tooBroad',
|
|
363
|
+
data: { name: variable.name } });
|
|
364
364
|
}
|
|
365
365
|
}
|
|
366
366
|
}
|
|
@@ -405,17 +405,16 @@ function createNarrowestScope
|
|
|
405
405
|
clearPrintBuffer();
|
|
406
406
|
scopeManager = context.sourceCode.scopeManager;
|
|
407
407
|
if (scopeManager)
|
|
408
|
-
return {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
}
|
|
408
|
+
return { 'Program:exit'
|
|
409
|
+
() {
|
|
410
|
+
let tree, scopeToNode;
|
|
411
|
+
|
|
412
|
+
scopeToNode = new Map;
|
|
413
|
+
nextVarId = 0;
|
|
414
|
+
tree = buildScopeTree(scopeManager.scopes[0], '1', scopeToNode);
|
|
415
|
+
checkScopeNode(context, tree, null, scopeToNode);
|
|
416
|
+
printTree(tree, 0);
|
|
417
|
+
} }
|
|
419
418
|
}
|
|
420
419
|
|
|
421
420
|
var narrowestScopePlugin = { meta: { type: 'suggestion',
|
|
@@ -426,21 +425,21 @@ var narrowestScopePlugin = { meta: { type: 'suggestion',
|
|
|
426
425
|
|
|
427
426
|
function createPositiveVibes
|
|
428
427
|
(context) {
|
|
429
|
-
return {
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
428
|
+
return { UnaryExpression
|
|
429
|
+
(node) {
|
|
430
|
+
if (node.operator == '!')
|
|
431
|
+
context.report({ node,
|
|
432
|
+
messageId: 'positiveVibes' });
|
|
433
|
+
},
|
|
434
|
+
BinaryExpression
|
|
435
|
+
(node) {
|
|
436
|
+
if (node.operator == '!=')
|
|
437
|
+
context.report({ node,
|
|
438
|
+
messageId: 'equality' });
|
|
439
|
+
else if (node.operator == '!==')
|
|
440
|
+
context.report({ node,
|
|
441
|
+
messageId: 'strictEquality' });
|
|
442
|
+
} }
|
|
444
443
|
}
|
|
445
444
|
|
|
446
445
|
var positiveVibesPlugin = { meta: { type: 'problem',
|
|
@@ -455,57 +454,60 @@ var useRiskyEqualPlugin = { meta: { type: 'problem',
|
|
|
455
454
|
docs: { description: 'Enforce use of == instead of ===.' },
|
|
456
455
|
messages: { risky: 'Use ==.' },
|
|
457
456
|
schema: [] },
|
|
458
|
-
create
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
457
|
+
create
|
|
458
|
+
(context) {
|
|
459
|
+
return { BinaryExpression
|
|
460
|
+
(node) {
|
|
461
|
+
if (node.operator == '===')
|
|
462
|
+
context.report({ node, messageId: 'risky' });
|
|
463
|
+
} }
|
|
463
464
|
} };
|
|
464
465
|
|
|
465
|
-
function create$
|
|
466
|
+
function create$4
|
|
466
467
|
(context) {
|
|
467
|
-
return { VariableDeclaration
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
468
|
+
return { VariableDeclaration
|
|
469
|
+
(node) {
|
|
470
|
+
if (node.kind == 'const' || node.kind == 'var')
|
|
471
|
+
context.report({ node, messageId: 'useLet' });
|
|
472
|
+
} }
|
|
471
473
|
}
|
|
472
474
|
|
|
473
475
|
var alwaysLetPlugin = { meta: { type: 'problem',
|
|
474
476
|
docs: { description: 'Enforce use of let instead of const or var.' },
|
|
475
477
|
messages: { useLet: 'Use let.' },
|
|
476
478
|
schema: [] },
|
|
477
|
-
create: create$
|
|
479
|
+
create: create$4 };
|
|
478
480
|
|
|
479
|
-
let ostIdCounter,
|
|
481
|
+
let ostIdCounter, $lastOst;
|
|
480
482
|
|
|
481
483
|
ostIdCounter = 0;
|
|
482
|
-
|
|
484
|
+
$lastOst = 0;
|
|
483
485
|
|
|
484
|
-
function trace
|
|
486
|
+
function trace$1
|
|
485
487
|
(...args) {
|
|
486
488
|
}
|
|
487
489
|
|
|
488
|
-
function createInitBeforeUse
|
|
490
|
+
function createInitBeforeUse
|
|
491
|
+
(context) {
|
|
489
492
|
let scopeManager;
|
|
490
493
|
|
|
491
494
|
scopeManager = context.sourceCode.scopeManager;
|
|
492
495
|
if (scopeManager)
|
|
493
|
-
return {
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
496
|
+
return { 'Program:exit'
|
|
497
|
+
() {
|
|
498
|
+
let scopeToNode, astToTree, astToOst;
|
|
499
|
+
scopeToNode = new Map;
|
|
500
|
+
astToTree = new Map;
|
|
501
|
+
astToOst = new Map;
|
|
502
|
+
buildScopeTree(scopeManager.scopes[0], '1', scopeToNode, astToTree);
|
|
500
503
|
|
|
501
|
-
|
|
502
|
-
|
|
504
|
+
ostIdCounter = 0;
|
|
505
|
+
$lastOst = processAst(context.sourceCode.ast, null, astToTree, astToOst, '', new Set());
|
|
503
506
|
|
|
504
|
-
|
|
507
|
+
ostAnnotate($lastOst, astToOst, context);
|
|
505
508
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
}
|
|
509
|
+
ostCheck($lastOst, context);
|
|
510
|
+
} }
|
|
509
511
|
}
|
|
510
512
|
|
|
511
513
|
function isRegularDeclaration
|
|
@@ -518,7 +520,8 @@ function isRegularDeclaration
|
|
|
518
520
|
return 0
|
|
519
521
|
}
|
|
520
522
|
|
|
521
|
-
function processAst
|
|
523
|
+
function processAst
|
|
524
|
+
(astNode, parentOst, astToTree, astToOst, indent, visited) {
|
|
522
525
|
if (astNode) {
|
|
523
526
|
let treeNode, scopeName, lets, reads, writes, ost, children;
|
|
524
527
|
|
|
@@ -531,7 +534,7 @@ function processAst(astNode, parentOst, astToTree, astToOst, indent, visited) {
|
|
|
531
534
|
scopeName = treeNode?.scope ? `${treeNode.scope.type}` : 'no-scope';
|
|
532
535
|
if (treeNode?.scope?.block?.id?.name)
|
|
533
536
|
scopeName += `(${treeNode.scope.block.id.name})`;
|
|
534
|
-
trace(`${indent}${astNode.type}`);
|
|
537
|
+
trace$1(`${indent}${astNode.type}`);
|
|
535
538
|
|
|
536
539
|
lets = [];
|
|
537
540
|
reads = [];
|
|
@@ -544,31 +547,29 @@ function processAst(astNode, parentOst, astToTree, astToOst, indent, visited) {
|
|
|
544
547
|
scopeCreator = treeNode?.scope?.block;
|
|
545
548
|
if (scopeCreator && astNode == scopeCreator) {
|
|
546
549
|
lets.push({ item });
|
|
547
|
-
trace(`${indent} | LET ${item.name}:${item.varId}`);
|
|
550
|
+
trace$1(`${indent} | LET ${item.name}:${item.varId}`);
|
|
548
551
|
}
|
|
549
552
|
}
|
|
550
553
|
else if (item.ref)
|
|
551
554
|
if (astNode == item.ref.identifier)
|
|
552
555
|
if (item.type == 'READ') {
|
|
553
556
|
reads.push({ item });
|
|
554
|
-
trace(`${indent} | READ ${item.name}:${item.varId}`);
|
|
557
|
+
trace$1(`${indent} | READ ${item.name}:${item.varId}`);
|
|
555
558
|
}
|
|
556
559
|
else if (item.type == 'WRITE') {
|
|
557
560
|
writes.push({ item });
|
|
558
|
-
trace(`${indent} | WRITE ${item.name}:${item.varId}`);
|
|
561
|
+
trace$1(`${indent} | WRITE ${item.name}:${item.varId}`);
|
|
559
562
|
}
|
|
560
563
|
|
|
561
|
-
ost = {
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
fnDefOst: null
|
|
571
|
-
};
|
|
564
|
+
ost = { id: ostIdCounter++,
|
|
565
|
+
astNode,
|
|
566
|
+
treeNode,
|
|
567
|
+
scopeItems: treeNode?.items ?? [],
|
|
568
|
+
lets,
|
|
569
|
+
reads,
|
|
570
|
+
writes,
|
|
571
|
+
children: [],
|
|
572
|
+
fnDefOst: null };
|
|
572
573
|
|
|
573
574
|
astToOst.set(astNode, ost);
|
|
574
575
|
|
|
@@ -654,7 +655,8 @@ function processAst(astNode, parentOst, astToTree, astToOst, indent, visited) {
|
|
|
654
655
|
}
|
|
655
656
|
}
|
|
656
657
|
|
|
657
|
-
function ostAnnotate
|
|
658
|
+
function ostAnnotate
|
|
659
|
+
(ost, astToOst, context) {
|
|
658
660
|
if (ost) {
|
|
659
661
|
for (let letInfo of ost.lets) {
|
|
660
662
|
let writeOst;
|
|
@@ -665,11 +667,9 @@ function ostAnnotate(ost, astToOst, context) {
|
|
|
665
667
|
continue
|
|
666
668
|
if (letInfo.item.defType == 'ImportBinding')
|
|
667
669
|
continue
|
|
668
|
-
context.report({
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
data: { name: letInfo.item.name }
|
|
672
|
-
});
|
|
670
|
+
context.report({ node: letInfo.item.identifier,
|
|
671
|
+
messageId: 'mustInit',
|
|
672
|
+
data: { name: letInfo.item.name } });
|
|
673
673
|
}
|
|
674
674
|
|
|
675
675
|
if (ost.astNode.type == 'CallExpression' && ost.astNode.callee?.type == 'Identifier')
|
|
@@ -700,7 +700,8 @@ function ostAnnotate(ost, astToOst, context) {
|
|
|
700
700
|
}
|
|
701
701
|
}
|
|
702
702
|
|
|
703
|
-
function findFirstWrite
|
|
703
|
+
function findFirstWrite
|
|
704
|
+
(ost, letInfo) {
|
|
704
705
|
if (ost.astNode.type == 'FunctionDeclaration' || ost.astNode.type == 'ArrowFunctionExpression' || ost.astNode.type == 'FunctionExpression')
|
|
705
706
|
for (let child of ost.children)
|
|
706
707
|
if (child.astNode.type == 'BlockStatement')
|
|
@@ -708,7 +709,8 @@ function findFirstWrite(ost, letInfo) {
|
|
|
708
709
|
return findFirstWriteInSubtree(ost, letInfo)
|
|
709
710
|
}
|
|
710
711
|
|
|
711
|
-
function findFirstWriteInSubtree
|
|
712
|
+
function findFirstWriteInSubtree
|
|
713
|
+
(ost, letInfo) {
|
|
712
714
|
if (ost) {
|
|
713
715
|
if (ost.astNode.type == 'FunctionDeclaration' || ost.astNode.type == 'ArrowFunctionExpression' || ost.astNode.type == 'FunctionExpression')
|
|
714
716
|
return null
|
|
@@ -733,7 +735,8 @@ function findFirstWriteInSubtree(ost, letInfo) {
|
|
|
733
735
|
return null
|
|
734
736
|
}
|
|
735
737
|
|
|
736
|
-
function ostCheck
|
|
738
|
+
function ostCheck
|
|
739
|
+
(ost, context) {
|
|
737
740
|
if (ost) {
|
|
738
741
|
for (let letInfo of ost.lets)
|
|
739
742
|
if (letInfo.firstWrite)
|
|
@@ -744,7 +747,8 @@ function ostCheck(ost, context) {
|
|
|
744
747
|
}
|
|
745
748
|
}
|
|
746
749
|
|
|
747
|
-
function walk2Start
|
|
750
|
+
function walk2Start
|
|
751
|
+
(node, letInfo, context) {
|
|
748
752
|
if (node.astNode.type == 'FunctionDeclaration')
|
|
749
753
|
for (let child of node.children)
|
|
750
754
|
if (child.astNode.type == 'BlockStatement')
|
|
@@ -752,7 +756,8 @@ function walk2Start(node, letInfo, context) {
|
|
|
752
756
|
return walk2(node, letInfo, context, new Set())
|
|
753
757
|
}
|
|
754
758
|
|
|
755
|
-
function walk2
|
|
759
|
+
function walk2
|
|
760
|
+
(node, letInfo, context, visited) {
|
|
756
761
|
if (node) {
|
|
757
762
|
if (node.astNode.type == 'FunctionDeclaration' || node.astNode.type == 'ArrowFunctionExpression' || node.astNode.type == 'FunctionExpression')
|
|
758
763
|
return false
|
|
@@ -760,11 +765,9 @@ function walk2(node, letInfo, context, visited) {
|
|
|
760
765
|
if (node == letInfo.firstWrite) {
|
|
761
766
|
for (let readInfo of node.reads)
|
|
762
767
|
if (readInfo.item.ref.resolved == letInfo.item.variable) {
|
|
763
|
-
context.report({
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
data: { name: letInfo.item.name }
|
|
767
|
-
});
|
|
768
|
+
context.report({ node: readInfo.item.ref.identifier,
|
|
769
|
+
messageId: 'initBeforeUse',
|
|
770
|
+
data: { name: letInfo.item.name } });
|
|
768
771
|
}
|
|
769
772
|
return true
|
|
770
773
|
}
|
|
@@ -790,11 +793,9 @@ function walk2(node, letInfo, context, visited) {
|
|
|
790
793
|
|
|
791
794
|
for (let readInfo of node.reads)
|
|
792
795
|
if (readInfo.item.ref.resolved == letInfo.item.variable) {
|
|
793
|
-
context.report({
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
data: { name: letInfo.item.name }
|
|
797
|
-
});
|
|
796
|
+
context.report({ node: readInfo.item.ref.identifier,
|
|
797
|
+
messageId: 'initBeforeUse',
|
|
798
|
+
data: { name: letInfo.item.name } });
|
|
798
799
|
}
|
|
799
800
|
|
|
800
801
|
for (let child of node.children)
|
|
@@ -805,19 +806,14 @@ function walk2(node, letInfo, context, visited) {
|
|
|
805
806
|
return false
|
|
806
807
|
}
|
|
807
808
|
|
|
808
|
-
var initBeforeUsePlugin = {
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
schema: []
|
|
815
|
-
},
|
|
816
|
-
create: createInitBeforeUse
|
|
817
|
-
};
|
|
809
|
+
var initBeforeUsePlugin = { meta: { type: 'problem',
|
|
810
|
+
docs: { description: 'Warn when a variable is used before being explicitly initialized.' },
|
|
811
|
+
messages: { initBeforeUse: "'{{name}}' used before initialization.",
|
|
812
|
+
mustInit: "'{{name}}' must be initialized." },
|
|
813
|
+
schema: [] },
|
|
814
|
+
create: createInitBeforeUse };
|
|
818
815
|
|
|
819
|
-
function
|
|
820
|
-
VariableDeclaration
|
|
816
|
+
function VariableDeclaration
|
|
821
817
|
(context, node) {
|
|
822
818
|
let parent;
|
|
823
819
|
|
|
@@ -842,7 +838,8 @@ VariableDeclaration
|
|
|
842
838
|
}
|
|
843
839
|
}
|
|
844
840
|
}
|
|
845
|
-
|
|
841
|
+
|
|
842
|
+
function create$3
|
|
846
843
|
(context) {
|
|
847
844
|
return { VariableDeclaration: node => VariableDeclaration(context, node) }
|
|
848
845
|
}
|
|
@@ -851,10 +848,9 @@ var varDeclBlockStartPlugin = { meta: { type: 'suggestion',
|
|
|
851
848
|
docs: { description: 'Require variable declarations to be at the start of the block.' },
|
|
852
849
|
messages: { varDeclBlockStart: 'VarDecl must be at start of block.' },
|
|
853
850
|
schema: [] },
|
|
854
|
-
create: create$
|
|
851
|
+
create: create$3 };
|
|
855
852
|
|
|
856
|
-
function
|
|
857
|
-
FunctionDeclaration
|
|
853
|
+
function FunctionDeclaration
|
|
858
854
|
(context, node) {
|
|
859
855
|
let parent;
|
|
860
856
|
|
|
@@ -880,7 +876,7 @@ FunctionDeclaration
|
|
|
880
876
|
}
|
|
881
877
|
}
|
|
882
878
|
|
|
883
|
-
function create
|
|
879
|
+
function create$2
|
|
884
880
|
(context) {
|
|
885
881
|
return { FunctionDeclaration: node => FunctionDeclaration(context, node) }
|
|
886
882
|
}
|
|
@@ -889,7 +885,162 @@ var fnDeclBlockStartPlugin = { meta: { type: 'suggestion',
|
|
|
889
885
|
docs: { description: 'Require function declarations to be at the start of the block.' },
|
|
890
886
|
messages: { fnDeclBlockStart: 'FnDecl must be the start the block (after VarDecls).' },
|
|
891
887
|
schema: [] },
|
|
892
|
-
create };
|
|
888
|
+
create: create$2 };
|
|
889
|
+
|
|
890
|
+
function FnArgsNl
|
|
891
|
+
(node, context) {
|
|
892
|
+
let nameLine, parenLine, nameEnd, i, newlines, parent;
|
|
893
|
+
|
|
894
|
+
parent = node.parent;
|
|
895
|
+
|
|
896
|
+
if (parent?.type == 'Property' && (parent.method || parent.kind == 'get' || parent.kind == 'set')) {
|
|
897
|
+
nameLine = parent.key.loc.start.line;
|
|
898
|
+
nameEnd = parent.key.range[1];
|
|
899
|
+
}
|
|
900
|
+
else if (parent?.type == 'MethodDefinition') {
|
|
901
|
+
nameLine = parent.key.loc.start.line;
|
|
902
|
+
nameEnd = parent.key.range[1];
|
|
903
|
+
}
|
|
904
|
+
else {
|
|
905
|
+
nameLine = node.loc.start.line;
|
|
906
|
+
nameEnd = node.range[0];
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
i = nameEnd;
|
|
910
|
+
newlines = 0;
|
|
911
|
+
while (i < context.sourceCode.text.length) {
|
|
912
|
+
if (context.sourceCode.text[i] == '(')
|
|
913
|
+
break
|
|
914
|
+
if (context.sourceCode.text[i] == '\n')
|
|
915
|
+
newlines++;
|
|
916
|
+
i++;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
parenLine = nameLine + newlines;
|
|
920
|
+
|
|
921
|
+
if (parenLine - nameLine == 1)
|
|
922
|
+
return
|
|
923
|
+
context.report({ node, messageId: 'fnArgsNl' });
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
function create$1
|
|
927
|
+
(context) {
|
|
928
|
+
return { FunctionDeclaration: node => FnArgsNl(node, context),
|
|
929
|
+
FunctionExpression: node => FnArgsNl(node, context) }
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
var fnArgsNlPlugin = { meta: { type: 'suggestion',
|
|
933
|
+
docs: { description: 'Require function args on the line immediately after the function name.' },
|
|
934
|
+
messages: { fnArgsNl: 'Fn args must be on the line immediately after the function name.' },
|
|
935
|
+
schema: [] },
|
|
936
|
+
create: create$1 };
|
|
937
|
+
|
|
938
|
+
function trace
|
|
939
|
+
(...args) {
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
function unit
|
|
943
|
+
(context) {
|
|
944
|
+
return context.options[0] ?? 2
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
function checkObjectExpressionProperties
|
|
948
|
+
(properties, node, context) {
|
|
949
|
+
let firstProp, sourceCode, lastProp, lastPropEnd, closingBrace, firstPropLine, firstPropCol, afterLastProp, closingLine, lastPropValueEndLine;
|
|
950
|
+
|
|
951
|
+
sourceCode = context.sourceCode.text;
|
|
952
|
+
firstProp = properties[0];
|
|
953
|
+
lastProp = properties[properties.length - 1];
|
|
954
|
+
firstPropLine = firstProp.loc.start.line;
|
|
955
|
+
firstPropCol = firstProp.loc.start.column;
|
|
956
|
+
lastPropEnd = lastProp.range[1];
|
|
957
|
+
closingBrace = sourceCode.indexOf('}', lastPropEnd);
|
|
958
|
+
closingLine = sourceCode.slice(0, closingBrace).split('\n').length;
|
|
959
|
+
afterLastProp = sourceCode.slice(lastPropEnd, closingBrace);
|
|
960
|
+
lastPropValueEndLine = sourceCode.slice(0, lastPropEnd).split('\n').length;
|
|
961
|
+
trace('CHECK POINT 1: is single-line? firstPropLine=%d, braceLine=%d, closingLine=%d', firstPropLine, node.loc.start.line, closingLine);
|
|
962
|
+
if (firstPropLine == node.loc.start.line && closingLine == firstPropLine)
|
|
963
|
+
return
|
|
964
|
+
trace('CHECK POINT 2: is firstPropLine (%d) != braceLine (%d)?', firstPropLine, node.loc.start.line);
|
|
965
|
+
if (firstPropLine == node.loc.start.line) ;
|
|
966
|
+
else if (firstPropCol == node.loc.start.column + unit(context)) ;
|
|
967
|
+
else {
|
|
968
|
+
context.report({ node: firstProp, messageId: 'indentStruct' });
|
|
969
|
+
}
|
|
970
|
+
for (let i = 1; i < properties.length; i++) {
|
|
971
|
+
let prop;
|
|
972
|
+
|
|
973
|
+
prop = properties[i];
|
|
974
|
+
if (prop.loc.start.column == firstPropCol) ;
|
|
975
|
+
else {
|
|
976
|
+
context.report({ node: prop, messageId: 'indentStruct' });
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
if (closingLine > lastPropValueEndLine) {
|
|
980
|
+
let braceCol, closingCol;
|
|
981
|
+
|
|
982
|
+
braceCol = node.loc.start.column;
|
|
983
|
+
closingCol = node.loc.end.column - 1;
|
|
984
|
+
if (closingCol == braceCol) ;
|
|
985
|
+
else {
|
|
986
|
+
context.report({ node, messageId: 'indentStruct' });
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
if (closingLine == lastPropValueEndLine) {
|
|
990
|
+
if (afterLastProp == ' ') ;
|
|
991
|
+
else {
|
|
992
|
+
context.report({ node, messageId: 'indentStruct' });
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
for (let prop of properties)
|
|
996
|
+
if (prop.method) {
|
|
997
|
+
let keyLine, keyEnd, i, newlines, parenLine;
|
|
998
|
+
|
|
999
|
+
keyLine = prop.key.loc.start.line;
|
|
1000
|
+
keyEnd = prop.key.range[1];
|
|
1001
|
+
i = keyEnd;
|
|
1002
|
+
newlines = 0;
|
|
1003
|
+
|
|
1004
|
+
while (i < sourceCode.length) {
|
|
1005
|
+
if (sourceCode[i] == '(')
|
|
1006
|
+
break
|
|
1007
|
+
if (sourceCode[i] == '\n')
|
|
1008
|
+
newlines++;
|
|
1009
|
+
i++;
|
|
1010
|
+
}
|
|
1011
|
+
parenLine = keyLine + newlines;
|
|
1012
|
+
if (parenLine > keyLine) {
|
|
1013
|
+
let parenCol;
|
|
1014
|
+
|
|
1015
|
+
parenCol = i - sourceCode.lastIndexOf('\n', i);
|
|
1016
|
+
if (prop.value.type == 'FunctionExpression' && prop.value.async) ;
|
|
1017
|
+
else if (parenCol - 1 == prop.key.loc.start.column) ;
|
|
1018
|
+
else {
|
|
1019
|
+
context.report({ node: prop, messageId: 'indentStruct' });
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
function checkObjectExpression
|
|
1026
|
+
(node, context) {
|
|
1027
|
+
let properties;
|
|
1028
|
+
|
|
1029
|
+
properties = node.properties;
|
|
1030
|
+
if (properties.length)
|
|
1031
|
+
checkObjectExpressionProperties(properties, node, context);
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
function create
|
|
1035
|
+
(context) {
|
|
1036
|
+
return { ObjectExpression: node => checkObjectExpression(node, context) }
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
var indentStructPlugin = { meta: { type: 'suggestion',
|
|
1040
|
+
docs: { description: 'Struct alignment rules.' },
|
|
1041
|
+
messages: { indentStruct: 'Indent structure' },
|
|
1042
|
+
schema: [] },
|
|
1043
|
+
create };
|
|
893
1044
|
|
|
894
1045
|
let rules, languageOptions, plugins;
|
|
895
1046
|
|
|
@@ -899,75 +1050,69 @@ plugins = { 'cookshack': { rules: { 'positive-vibes': positiveVibesPlugin,
|
|
|
899
1050
|
'always-let': alwaysLetPlugin,
|
|
900
1051
|
'init-before-use': initBeforeUsePlugin,
|
|
901
1052
|
'var-decl-block-start': varDeclBlockStartPlugin,
|
|
902
|
-
'fn-decl-block-start': fnDeclBlockStartPlugin
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
};
|
|
961
|
-
|
|
962
|
-
languageOptions = {
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
},
|
|
966
|
-
parserOptions: {
|
|
967
|
-
ecmaVersion: 2025,
|
|
968
|
-
sourceType: 'module'
|
|
969
|
-
}
|
|
970
|
-
};
|
|
1053
|
+
'fn-decl-block-start': fnDeclBlockStartPlugin,
|
|
1054
|
+
'fn-args-nl': fnArgsNlPlugin,
|
|
1055
|
+
'indent-struct': indentStructPlugin } } };
|
|
1056
|
+
|
|
1057
|
+
rules = { 'array-bracket-newline': [ 'error', 'never' ],
|
|
1058
|
+
'array-bracket-spacing': [ 'error', 'always' ],
|
|
1059
|
+
'arrow-parens': [ 'error', 'as-needed' ],
|
|
1060
|
+
'brace-style': [ 'error', 'stroustrup' ],
|
|
1061
|
+
'comma-dangle': 'error',
|
|
1062
|
+
'curly': [ 'error', 'multi' ],
|
|
1063
|
+
'eol-last': [ 'error', 'always' ],
|
|
1064
|
+
'function-paren-newline': [ 'error', 'never' ],
|
|
1065
|
+
'indent': [ 'error', 2, { ArrayExpression: 'first',
|
|
1066
|
+
CallExpression: { arguments: 'first' },
|
|
1067
|
+
//flatTernaryExpressions: true,
|
|
1068
|
+
//offsetTernaryExpressions: true,
|
|
1069
|
+
// ternary, because overhangs strangely (eg multiline in array def)
|
|
1070
|
+
'ignoredNodes': [ 'ConditionalExpression', 'ObjectExpression *' ],
|
|
1071
|
+
FunctionDeclaration: { parameters: 'first', body: 1 },
|
|
1072
|
+
FunctionExpression: { parameters: 'first', body: 1 },
|
|
1073
|
+
ImportDeclaration: 'first',
|
|
1074
|
+
offsetTernaryExpressions: true,
|
|
1075
|
+
VariableDeclarator: 'first' } ],
|
|
1076
|
+
'init-declarations': [ 'error', 'never', { 'ignoreForLoopInit': true } ],
|
|
1077
|
+
'keyword-spacing': [ 'error', { before: true, after: true } ],
|
|
1078
|
+
'linebreak-style': [ 'error', 'unix' ],
|
|
1079
|
+
'padding-line-between-statements': [ 'error',
|
|
1080
|
+
{ blankLine: 'always', prev: 'let', next: '*' },
|
|
1081
|
+
{ blankLine: 'never', prev: 'let', next: 'let' } ],
|
|
1082
|
+
'no-case-declarations': 'error',
|
|
1083
|
+
'no-global-assign': 'error',
|
|
1084
|
+
'cookshack/positive-vibes': 'error',
|
|
1085
|
+
'cookshack/narrowest-scope': 'error',
|
|
1086
|
+
'cookshack/use-risky-equal': 'error',
|
|
1087
|
+
'cookshack/always-let': 'error',
|
|
1088
|
+
// using the implicit inititialization to undefined fits better
|
|
1089
|
+
//'cookshack/init-before-use': 'error',
|
|
1090
|
+
'cookshack/var-decl-block-start': 'error',
|
|
1091
|
+
'cookshack/fn-decl-block-start': 'error',
|
|
1092
|
+
'cookshack/fn-args-nl': 'error',
|
|
1093
|
+
'cookshack/indent-struct': 'error',
|
|
1094
|
+
'no-mixed-operators': 'error',
|
|
1095
|
+
'no-multi-spaces': 'error',
|
|
1096
|
+
'no-multiple-empty-lines': [ 'error', { max: 1, maxEOF: 0 } ],
|
|
1097
|
+
'no-negated-condition': 'error',
|
|
1098
|
+
'no-redeclare': 'error',
|
|
1099
|
+
'no-sequences': 'error',
|
|
1100
|
+
'no-shadow': [ 'error', { builtinGlobals: true } ],
|
|
1101
|
+
'no-sparse-arrays': 'error',
|
|
1102
|
+
'no-tabs': 'error',
|
|
1103
|
+
'no-trailing-spaces': 'error',
|
|
1104
|
+
'no-undef': 'error',
|
|
1105
|
+
'no-unsafe-negation': 'error',
|
|
1106
|
+
'no-unused-vars': 'error',
|
|
1107
|
+
'no-var': 'error',
|
|
1108
|
+
'object-curly-spacing': [ 'error', 'always' ],
|
|
1109
|
+
'object-shorthand': [ 'error', 'always' ],
|
|
1110
|
+
quotes: [ 'error', 'single', { avoidEscape: true } ],
|
|
1111
|
+
semi: [ 'error', 'never' ] };
|
|
1112
|
+
|
|
1113
|
+
languageOptions = { globals: { ...globals.node },
|
|
1114
|
+
parserOptions: { ecmaVersion: 2025,
|
|
1115
|
+
sourceType: 'module' } };
|
|
971
1116
|
|
|
972
1117
|
var index = [ { ignores: [ 'TAGS.mjs' ] },
|
|
973
1118
|
{ languageOptions,
|