@so1ve/eslint-plugin 0.43.1 → 0.45.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 CHANGED
@@ -1,13 +1,27 @@
1
1
  'use strict';
2
2
 
3
3
  const utils = require('@typescript-eslint/utils');
4
+ const util = require('@typescript-eslint/utils/dist/ast-utils');
4
5
  const reactivity = require('@vue/reactivity');
5
6
 
7
+ function _interopNamespaceDefault(e) {
8
+ const n = Object.create(null);
9
+ if (e) {
10
+ for (const k in e) {
11
+ n[k] = e[k];
12
+ }
13
+ }
14
+ n.default = e;
15
+ return n;
16
+ }
17
+
18
+ const util__namespace = /*#__PURE__*/_interopNamespaceDefault(util);
19
+
6
20
  const createEslintRule = utils.ESLintUtils.RuleCreator((ruleName) => ruleName);
7
21
 
8
- const RULE_NAME$6 = "generic-spacing";
22
+ const RULE_NAME$7 = "generic-spacing";
9
23
  const genericSpacing = createEslintRule({
10
- name: RULE_NAME$6,
24
+ name: RULE_NAME$7,
11
25
  meta: {
12
26
  type: "layout",
13
27
  docs: {
@@ -29,18 +43,17 @@ const genericSpacing = createEslintRule({
29
43
  const params = node.params;
30
44
  for (let i = 0; i < params.length; i++) {
31
45
  const param = params[i];
32
- const pre = sourceCode.text.slice(0, param.range[0]);
33
- const preSpace = pre.match(/(\s+)$/)?.[0];
34
- const preComma = pre.match(/(,)\s+$/)?.[0];
35
- const post = sourceCode.text.slice(param.range[1]);
36
- const postSpace = post.match(/^(\s*)/)?.[0];
37
- if (preSpace && preSpace.length && !preComma && param.loc.start.line === node.loc.start.line) {
46
+ const leftToken = sourceCode.getTokenBefore(param);
47
+ const rightToken = sourceCode.getTokenAfter(param);
48
+ const hasSpacingBeforeParam = sourceCode.isSpaceBetween(leftToken, param);
49
+ const hasSpacingAfterParam = sourceCode.isSpaceBetween(param, rightToken);
50
+ if (hasSpacingBeforeParam && param.loc.start.line === node.loc.start.line && leftToken.value === "<") {
38
51
  context.report({
39
52
  node,
40
53
  loc: {
41
54
  start: {
42
- line: param.loc.start.line,
43
- column: param.loc.start.column + 1 - preSpace.length
55
+ line: leftToken.loc.end.line,
56
+ column: leftToken.loc.end.column
44
57
  },
45
58
  end: {
46
59
  line: param.loc.start.line,
@@ -49,11 +62,11 @@ const genericSpacing = createEslintRule({
49
62
  },
50
63
  messageId: "genericSpacingMismatch",
51
64
  *fix(fixer) {
52
- yield fixer.removeRange([param.range[0] - preSpace.length, param.range[0]]);
65
+ yield fixer.removeRange([leftToken.range[1], param.range[0]]);
53
66
  }
54
67
  });
55
68
  }
56
- if (postSpace && postSpace.length && param.loc.end.line === node.loc.end.line) {
69
+ if (hasSpacingAfterParam && param.loc.end.line === node.loc.end.line) {
57
70
  context.report({
58
71
  loc: {
59
72
  start: {
@@ -61,59 +74,60 @@ const genericSpacing = createEslintRule({
61
74
  column: param.loc.end.column
62
75
  },
63
76
  end: {
64
- line: param.loc.end.line,
65
- column: param.loc.end.column + postSpace.length
77
+ line: rightToken.loc.start.line,
78
+ column: rightToken.loc.start.column
66
79
  }
67
80
  },
68
81
  node,
69
82
  messageId: "genericSpacingMismatch",
70
83
  *fix(fixer) {
71
- yield fixer.replaceTextRange([param.range[1], param.range[1] + postSpace.length], "");
84
+ yield fixer.removeRange([param.range[1], rightToken.range[0]]);
72
85
  }
73
86
  });
74
87
  }
75
- }
76
- if (!["TSCallSignatureDeclaration", "ArrowFunctionExpression"].includes(node.parent.type)) {
77
- const pre = sourceCode.text.slice(0, node.range[0]);
78
- const preSpace = pre.match(/(\s+)$/)?.[0];
79
- const post = sourceCode.text.slice(node.range[1]);
80
- const postBracket = post.match(/^(\s*)\(/)?.[0];
81
- if (preSpace && preSpace.length && !postBracket) {
88
+ if (!hasSpacingBeforeParam && leftToken.value === ",") {
82
89
  context.report({
83
90
  node,
91
+ loc: {
92
+ start: {
93
+ line: leftToken.loc.end.line,
94
+ column: leftToken.loc.end.column
95
+ },
96
+ end: {
97
+ line: param.loc.start.line,
98
+ column: param.loc.start.column - 1
99
+ }
100
+ },
84
101
  messageId: "genericSpacingMismatch",
85
102
  *fix(fixer) {
86
- yield fixer.removeRange([node.range[0] - preSpace.length, node.range[0]]);
103
+ yield fixer.replaceTextRange([leftToken.range[1], param.range[0]], " ");
87
104
  }
88
105
  });
89
106
  }
90
- if (postBracket && postBracket.length > 1) {
107
+ }
108
+ if (!["TSCallSignatureDeclaration", "ArrowFunctionExpression"].includes(node.parent.type)) {
109
+ const leftToken = sourceCode.getTokenBefore(node);
110
+ const hasSpacingBeforeNode = sourceCode.isSpaceBetween(leftToken, node);
111
+ const lastParam = params[params.length - 1];
112
+ const endBracket = sourceCode.getTokenAfter(lastParam);
113
+ const rightToken = sourceCode.getTokenAfter(endBracket, util__namespace.isOpeningParenToken);
114
+ const hasSpacingAfterParam = sourceCode.isSpaceBetween(endBracket, rightToken);
115
+ if (hasSpacingBeforeNode && node.parent.type !== utils.AST_NODE_TYPES.TSFunctionType) {
91
116
  context.report({
92
117
  node,
93
118
  messageId: "genericSpacingMismatch",
94
119
  *fix(fixer) {
95
- yield fixer.removeRange([node.range[1], node.range[1] + postBracket.length - 1]);
120
+ yield fixer.removeRange([leftToken.range[1], node.range[0]]);
96
121
  }
97
122
  });
98
123
  }
99
- }
100
- for (let i = 1; i < params.length; i++) {
101
- const prev = params[i - 1];
102
- const current = params[i];
103
- const from = prev.range[1];
104
- const to = current.range[0];
105
- const span = sourceCode.text.slice(from, to);
106
- if (span !== ", " && !span.match(/,\n/)) {
124
+ if (hasSpacingAfterParam && node.parent.type === utils.AST_NODE_TYPES.TSFunctionType) {
107
125
  context.report({
108
- *fix(fixer) {
109
- yield fixer.replaceTextRange([from, to], ", ");
110
- },
111
- loc: {
112
- start: prev.loc.end,
113
- end: current.loc.start
114
- },
126
+ node,
115
127
  messageId: "genericSpacingMismatch",
116
- node
128
+ *fix(fixer) {
129
+ yield fixer.removeRange([endBracket.range[1], rightToken.range[0]]);
130
+ }
117
131
  });
118
132
  }
119
133
  }
@@ -174,46 +188,25 @@ const genericSpacing = createEslintRule({
174
188
  const params = node.params;
175
189
  for (let i = 0; i < params.length; i++) {
176
190
  const param = params[i];
177
- const pre = sourceCode.text.slice(0, param.range[0]);
178
- const preSpace = pre.match(/(\s+)$/)?.[0];
179
- const preComma = pre.match(/(,)\s+$/)?.[0];
180
- const post = sourceCode.text.slice(param.range[1]);
181
- const postSpace = post.match(/^(\s*)/)?.[0];
182
- if (preSpace && preSpace.length && !preComma && param.loc.start.line === node.loc.start.line) {
191
+ const leftToken = sourceCode.getTokenBefore(param);
192
+ const rightToken = sourceCode.getTokenAfter(param);
193
+ const hasSpacingBeforeParam = leftToken.value === "<" ? sourceCode.isSpaceBetween(leftToken, param) : false;
194
+ const hasSpacingAfterParam = rightToken.value === ">" ? sourceCode.isSpaceBetween(param, rightToken) : false;
195
+ if (hasSpacingBeforeParam) {
183
196
  context.report({
184
197
  node,
185
- loc: {
186
- start: {
187
- line: param.loc.start.line,
188
- column: param.loc.start.column + 1 - preSpace.length
189
- },
190
- end: {
191
- line: param.loc.start.line,
192
- column: param.loc.start.column - 1
193
- }
194
- },
195
198
  messageId: "genericSpacingMismatch",
196
199
  *fix(fixer) {
197
- yield fixer.replaceTextRange([param.range[0] - preSpace.length, param.range[0]], "");
200
+ yield fixer.removeRange([leftToken.range[1], param.range[0]]);
198
201
  }
199
202
  });
200
203
  }
201
- if (postSpace && postSpace.length && param.loc.end.line === node.loc.end.line) {
204
+ if (hasSpacingAfterParam) {
202
205
  context.report({
203
- loc: {
204
- start: {
205
- line: param.loc.end.line,
206
- column: param.loc.end.column
207
- },
208
- end: {
209
- line: param.loc.end.line,
210
- column: param.loc.end.column + postSpace.length
211
- }
212
- },
213
206
  node,
214
207
  messageId: "genericSpacingMismatch",
215
208
  *fix(fixer) {
216
- yield fixer.replaceTextRange([param.range[1], param.range[1] + postSpace.length], "");
209
+ yield fixer.removeRange([param.range[1], rightToken.range[0]]);
217
210
  }
218
211
  });
219
212
  }
@@ -255,9 +248,9 @@ const genericSpacing = createEslintRule({
255
248
  }
256
249
  });
257
250
 
258
- const RULE_NAME$5 = "import-dedupe";
251
+ const RULE_NAME$6 = "import-dedupe";
259
252
  const importDedupe = createEslintRule({
260
- name: RULE_NAME$5,
253
+ name: RULE_NAME$6,
261
254
  meta: {
262
255
  type: "problem",
263
256
  docs: {
@@ -306,9 +299,9 @@ const importDedupe = createEslintRule({
306
299
  });
307
300
 
308
301
  const operatorOrAnyBracketOrKeywordRE = /^(\||&|\*|\+|\-|\/|%|<|>|<=|>=|==|!=|===|!==|\[|\(|\{|as|extends|implements|keyof|new|readonly|typeof|unique|unknown)/;
309
- const RULE_NAME$4 = "space-between-generic-and-paren";
302
+ const RULE_NAME$5 = "space-between-generic-and-paren";
310
303
  const spaceBetweenGenericAndParen = createEslintRule({
311
- name: RULE_NAME$4,
304
+ name: RULE_NAME$5,
312
305
  meta: {
313
306
  type: "layout",
314
307
  docs: {
@@ -334,7 +327,7 @@ const spaceBetweenGenericAndParen = createEslintRule({
334
327
  const postComma = text.slice(node.range[1]).match(/^(,)/)?.[0];
335
328
  const postQuestionMark = text.slice(spaceStartRange + postSpace.length).match(/^(\?)/)?.[0];
336
329
  const postOperatorOrAnyBracketOrKeyword = text.slice(spaceStartRange + postSpace.length).match(operatorOrAnyBracketOrKeywordRE)?.[0];
337
- if (postSpace && postSpace.length && !postEqual && !postComma && !postQuestionMark && !postOperatorOrAnyBracketOrKeyword && node.parent.type !== "TSInferType") {
330
+ if (postSpace && postSpace.length && !postEqual && !postComma && !postQuestionMark && !postOperatorOrAnyBracketOrKeyword && node.parent.type !== utils.AST_NODE_TYPES.TSInferType) {
338
331
  context.report({
339
332
  loc: {
340
333
  start: {
@@ -353,7 +346,7 @@ const spaceBetweenGenericAndParen = createEslintRule({
353
346
  }
354
347
  });
355
348
  }
356
- if (node.parent?.parent.type === "FunctionDeclaration") {
349
+ if (node.parent?.parent.type === utils.AST_NODE_TYPES.FunctionDeclaration) {
357
350
  const spaceEndRange = node.range[0] - 1;
358
351
  const pre = sourceCode.text.slice(0, spaceEndRange);
359
352
  const preSpace = pre.match(/(\s+)$/)?.[0];
@@ -382,9 +375,9 @@ const spaceBetweenGenericAndParen = createEslintRule({
382
375
  }
383
376
  });
384
377
 
385
- const RULE_NAME$3 = "no-spaces-before-paren";
378
+ const RULE_NAME$4 = "no-spaces-before-paren";
386
379
  const noSpacesBeforeParen = createEslintRule({
387
- name: RULE_NAME$3,
380
+ name: RULE_NAME$4,
388
381
  meta: {
389
382
  type: "layout",
390
383
  docs: {
@@ -420,7 +413,7 @@ const noSpacesBeforeParen = createEslintRule({
420
413
  },
421
414
  CallExpression(node) {
422
415
  let caller = "property" in node.callee ? node.callee.property : node.callee;
423
- if (caller.type === "TSInstantiationExpression" && "property" in caller.expression) {
416
+ if (caller.type === utils.AST_NODE_TYPES.TSInstantiationExpression && "property" in caller.expression) {
424
417
  caller = caller.expression.property;
425
418
  }
426
419
  const callerEnd = reactivity.ref(caller.range[1]);
@@ -483,9 +476,9 @@ const noSpacesBeforeParen = createEslintRule({
483
476
  }
484
477
  });
485
478
 
486
- const RULE_NAME$2 = "space-in-empty-block";
479
+ const RULE_NAME$3 = "space-in-empty-block";
487
480
  const spaceInEmptyBlock = createEslintRule({
488
- name: RULE_NAME$2,
481
+ name: RULE_NAME$3,
489
482
  meta: {
490
483
  type: "layout",
491
484
  docs: {
@@ -550,6 +543,113 @@ const spaceInEmptyBlock = createEslintRule({
550
543
  }
551
544
  });
552
545
 
546
+ const RULE_NAME$2 = "space-before-function-paren";
547
+ const spaceBeforeFunctionParen = createEslintRule({
548
+ name: RULE_NAME$2,
549
+ meta: {
550
+ type: "layout",
551
+ docs: {
552
+ description: "Enforce consistent spacing before function parenthesis",
553
+ recommended: false,
554
+ extendsBaseRule: true
555
+ },
556
+ fixable: "whitespace",
557
+ schema: [
558
+ {
559
+ oneOf: [
560
+ {
561
+ enum: ["always", "never"]
562
+ },
563
+ {
564
+ type: "object",
565
+ properties: {
566
+ anonymous: {
567
+ enum: ["always", "never", "ignore"]
568
+ },
569
+ named: {
570
+ enum: ["always", "never", "ignore"]
571
+ },
572
+ asyncArrow: {
573
+ enum: ["always", "never", "ignore"]
574
+ }
575
+ },
576
+ additionalProperties: false
577
+ }
578
+ ]
579
+ }
580
+ ],
581
+ messages: {
582
+ unexpected: "Unexpected space before function parentheses.",
583
+ missing: "Missing space before function parentheses."
584
+ }
585
+ },
586
+ defaultOptions: ["always"],
587
+ create(context, [firstOption]) {
588
+ const sourceCode = context.getSourceCode();
589
+ const baseConfig = typeof firstOption === "string" ? firstOption : "always";
590
+ const overrideConfig = typeof firstOption === "object" ? firstOption : {};
591
+ function isNamedFunction(node) {
592
+ if (node.id != null) {
593
+ return true;
594
+ }
595
+ const parent = node.parent;
596
+ return parent.type === utils.AST_NODE_TYPES.MethodDefinition || parent.type === utils.AST_NODE_TYPES.TSAbstractMethodDefinition || parent.type === utils.AST_NODE_TYPES.Property && (parent.kind === "get" || parent.kind === "set" || parent.method);
597
+ }
598
+ function getConfigForFunction(node) {
599
+ if (node.type === utils.AST_NODE_TYPES.ArrowFunctionExpression) {
600
+ if (node.async && util__namespace.isOpeningParenToken(sourceCode.getFirstToken(node, { skip: 1 }))) {
601
+ return overrideConfig.asyncArrow ?? baseConfig;
602
+ }
603
+ } else if (isNamedFunction(node)) {
604
+ return overrideConfig.named ?? baseConfig;
605
+ } else if (!node.generator) {
606
+ return overrideConfig.anonymous ?? baseConfig;
607
+ }
608
+ return "ignore";
609
+ }
610
+ function checkFunction(node) {
611
+ const functionConfig = getConfigForFunction(node);
612
+ if (functionConfig === "ignore") {
613
+ return;
614
+ }
615
+ let leftToken, rightToken;
616
+ if (node.typeParameters) {
617
+ leftToken = sourceCode.getLastToken(node.typeParameters);
618
+ rightToken = sourceCode.getTokenAfter(leftToken);
619
+ } else {
620
+ rightToken = sourceCode.getFirstToken(node, util__namespace.isOpeningParenToken);
621
+ leftToken = sourceCode.getTokenBefore(rightToken);
622
+ }
623
+ const hasSpacing = sourceCode.isSpaceBetween(leftToken, rightToken);
624
+ if (hasSpacing && functionConfig === "never") {
625
+ context.report({
626
+ node,
627
+ loc: {
628
+ start: leftToken.loc.end,
629
+ end: rightToken.loc.start
630
+ },
631
+ messageId: "unexpected",
632
+ fix: (fixer) => fixer.removeRange([leftToken.range[1], rightToken.range[0]])
633
+ });
634
+ } else if (!hasSpacing && functionConfig === "always" && !node.typeParameters) {
635
+ context.report({
636
+ node,
637
+ loc: rightToken.loc,
638
+ messageId: "missing",
639
+ fix: (fixer) => fixer.insertTextAfter(leftToken, " ")
640
+ });
641
+ }
642
+ }
643
+ return {
644
+ ArrowFunctionExpression: checkFunction,
645
+ FunctionDeclaration: checkFunction,
646
+ FunctionExpression: checkFunction,
647
+ TSEmptyBodyFunctionExpression: checkFunction,
648
+ TSDeclareFunction: checkFunction
649
+ };
650
+ }
651
+ });
652
+
553
653
  const RULE_NAME$1 = "semi-spacing";
554
654
  const semiSpacing = createEslintRule({
555
655
  name: RULE_NAME$1,
@@ -568,29 +668,30 @@ const semiSpacing = createEslintRule({
568
668
  defaultOptions: [],
569
669
  create: (context) => {
570
670
  const sourceCode = context.getSourceCode();
571
- const text = sourceCode.text;
572
671
  return {
573
672
  TSTypeAliasDeclaration(node) {
574
- const sourceLine = text.slice(node.range[0], node.range[1]);
575
- const preSemiSpace = sourceLine.match(/(\s+);$/)?.[0];
576
- if (preSemiSpace) {
577
- const spaceStart = node.range[0] + sourceLine.length - preSemiSpace.length;
578
- const spaceEnd = node.range[0] + sourceLine.length - 1;
673
+ const leftToken = node.typeAnnotation;
674
+ const rightToken = sourceCode.getTokenAfter(node.typeAnnotation);
675
+ if (rightToken.type !== utils.AST_TOKEN_TYPES.Punctuator) {
676
+ return;
677
+ }
678
+ const hasSpacing = sourceCode.isSpaceBetween(leftToken, rightToken);
679
+ if (hasSpacing) {
579
680
  context.report({
580
681
  loc: {
581
682
  start: {
582
- line: node.loc.start.line,
583
- column: node.loc.start.column + sourceLine.length - preSemiSpace.length
683
+ line: leftToken.loc.end.line,
684
+ column: leftToken.loc.end.column
584
685
  },
585
686
  end: {
586
- line: node.loc.start.line,
587
- column: node.loc.start.column + sourceLine.length - 1
687
+ line: rightToken.loc.start.line,
688
+ column: rightToken.loc.start.column
588
689
  }
589
690
  },
590
691
  node,
591
692
  messageId: "noSpaceBeforeSemi",
592
693
  *fix(fixer) {
593
- yield fixer.removeRange([spaceStart, spaceEnd]);
694
+ yield fixer.removeRange([leftToken.range[1], rightToken.range[0]]);
594
695
  }
595
696
  });
596
697
  }
@@ -656,7 +757,8 @@ const index = {
656
757
  "space-in-empty-block": spaceInEmptyBlock,
657
758
  "semi-spacing": semiSpacing,
658
759
  "no-inline-type-import": noInlineTypeImport,
659
- "no-spaces-before-paren": noSpacesBeforeParen
760
+ "no-spaces-before-paren": noSpacesBeforeParen,
761
+ "space-before-function-paren": spaceBeforeFunctionParen
660
762
  }
661
763
  };
662
764
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,16 @@
1
1
  import * as _typescript_eslint_utils_dist_ts_eslint_Rule from '@typescript-eslint/utils/dist/ts-eslint/Rule';
2
2
 
3
+ type Option = "never" | "always";
4
+ type FuncOption = Option | "ignore";
5
+ type Options = [
6
+ Option | {
7
+ anonymous?: FuncOption;
8
+ named?: FuncOption;
9
+ asyncArrow?: FuncOption;
10
+ }
11
+ ];
12
+ type MessageIds = "unexpected" | "missing";
13
+
3
14
  declare const _default: {
4
15
  rules: {
5
16
  "import-dedupe": _typescript_eslint_utils_dist_ts_eslint_Rule.RuleModule<"importDedupe", [], _typescript_eslint_utils_dist_ts_eslint_Rule.RuleListener>;
@@ -9,6 +20,7 @@ declare const _default: {
9
20
  "semi-spacing": _typescript_eslint_utils_dist_ts_eslint_Rule.RuleModule<"noSpaceBeforeSemi", [], _typescript_eslint_utils_dist_ts_eslint_Rule.RuleListener>;
10
21
  "no-inline-type-import": _typescript_eslint_utils_dist_ts_eslint_Rule.RuleModule<"noInlineTypeImport", [], _typescript_eslint_utils_dist_ts_eslint_Rule.RuleListener>;
11
22
  "no-spaces-before-paren": _typescript_eslint_utils_dist_ts_eslint_Rule.RuleModule<"noSpacesBeforeParen", [], _typescript_eslint_utils_dist_ts_eslint_Rule.RuleListener>;
23
+ "space-before-function-paren": _typescript_eslint_utils_dist_ts_eslint_Rule.RuleModule<MessageIds, Options, _typescript_eslint_utils_dist_ts_eslint_Rule.RuleListener>;
12
24
  };
13
25
  };
14
26
 
package/dist/index.mjs CHANGED
@@ -1,11 +1,12 @@
1
- import { ESLintUtils } from '@typescript-eslint/utils';
1
+ import { ESLintUtils, AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint/utils';
2
+ import * as util from '@typescript-eslint/utils/dist/ast-utils';
2
3
  import { ref, computed } from '@vue/reactivity';
3
4
 
4
5
  const createEslintRule = ESLintUtils.RuleCreator((ruleName) => ruleName);
5
6
 
6
- const RULE_NAME$6 = "generic-spacing";
7
+ const RULE_NAME$7 = "generic-spacing";
7
8
  const genericSpacing = createEslintRule({
8
- name: RULE_NAME$6,
9
+ name: RULE_NAME$7,
9
10
  meta: {
10
11
  type: "layout",
11
12
  docs: {
@@ -27,18 +28,17 @@ const genericSpacing = createEslintRule({
27
28
  const params = node.params;
28
29
  for (let i = 0; i < params.length; i++) {
29
30
  const param = params[i];
30
- const pre = sourceCode.text.slice(0, param.range[0]);
31
- const preSpace = pre.match(/(\s+)$/)?.[0];
32
- const preComma = pre.match(/(,)\s+$/)?.[0];
33
- const post = sourceCode.text.slice(param.range[1]);
34
- const postSpace = post.match(/^(\s*)/)?.[0];
35
- if (preSpace && preSpace.length && !preComma && param.loc.start.line === node.loc.start.line) {
31
+ const leftToken = sourceCode.getTokenBefore(param);
32
+ const rightToken = sourceCode.getTokenAfter(param);
33
+ const hasSpacingBeforeParam = sourceCode.isSpaceBetween(leftToken, param);
34
+ const hasSpacingAfterParam = sourceCode.isSpaceBetween(param, rightToken);
35
+ if (hasSpacingBeforeParam && param.loc.start.line === node.loc.start.line && leftToken.value === "<") {
36
36
  context.report({
37
37
  node,
38
38
  loc: {
39
39
  start: {
40
- line: param.loc.start.line,
41
- column: param.loc.start.column + 1 - preSpace.length
40
+ line: leftToken.loc.end.line,
41
+ column: leftToken.loc.end.column
42
42
  },
43
43
  end: {
44
44
  line: param.loc.start.line,
@@ -47,11 +47,11 @@ const genericSpacing = createEslintRule({
47
47
  },
48
48
  messageId: "genericSpacingMismatch",
49
49
  *fix(fixer) {
50
- yield fixer.removeRange([param.range[0] - preSpace.length, param.range[0]]);
50
+ yield fixer.removeRange([leftToken.range[1], param.range[0]]);
51
51
  }
52
52
  });
53
53
  }
54
- if (postSpace && postSpace.length && param.loc.end.line === node.loc.end.line) {
54
+ if (hasSpacingAfterParam && param.loc.end.line === node.loc.end.line) {
55
55
  context.report({
56
56
  loc: {
57
57
  start: {
@@ -59,59 +59,60 @@ const genericSpacing = createEslintRule({
59
59
  column: param.loc.end.column
60
60
  },
61
61
  end: {
62
- line: param.loc.end.line,
63
- column: param.loc.end.column + postSpace.length
62
+ line: rightToken.loc.start.line,
63
+ column: rightToken.loc.start.column
64
64
  }
65
65
  },
66
66
  node,
67
67
  messageId: "genericSpacingMismatch",
68
68
  *fix(fixer) {
69
- yield fixer.replaceTextRange([param.range[1], param.range[1] + postSpace.length], "");
69
+ yield fixer.removeRange([param.range[1], rightToken.range[0]]);
70
70
  }
71
71
  });
72
72
  }
73
- }
74
- if (!["TSCallSignatureDeclaration", "ArrowFunctionExpression"].includes(node.parent.type)) {
75
- const pre = sourceCode.text.slice(0, node.range[0]);
76
- const preSpace = pre.match(/(\s+)$/)?.[0];
77
- const post = sourceCode.text.slice(node.range[1]);
78
- const postBracket = post.match(/^(\s*)\(/)?.[0];
79
- if (preSpace && preSpace.length && !postBracket) {
73
+ if (!hasSpacingBeforeParam && leftToken.value === ",") {
80
74
  context.report({
81
75
  node,
76
+ loc: {
77
+ start: {
78
+ line: leftToken.loc.end.line,
79
+ column: leftToken.loc.end.column
80
+ },
81
+ end: {
82
+ line: param.loc.start.line,
83
+ column: param.loc.start.column - 1
84
+ }
85
+ },
82
86
  messageId: "genericSpacingMismatch",
83
87
  *fix(fixer) {
84
- yield fixer.removeRange([node.range[0] - preSpace.length, node.range[0]]);
88
+ yield fixer.replaceTextRange([leftToken.range[1], param.range[0]], " ");
85
89
  }
86
90
  });
87
91
  }
88
- if (postBracket && postBracket.length > 1) {
92
+ }
93
+ if (!["TSCallSignatureDeclaration", "ArrowFunctionExpression"].includes(node.parent.type)) {
94
+ const leftToken = sourceCode.getTokenBefore(node);
95
+ const hasSpacingBeforeNode = sourceCode.isSpaceBetween(leftToken, node);
96
+ const lastParam = params[params.length - 1];
97
+ const endBracket = sourceCode.getTokenAfter(lastParam);
98
+ const rightToken = sourceCode.getTokenAfter(endBracket, util.isOpeningParenToken);
99
+ const hasSpacingAfterParam = sourceCode.isSpaceBetween(endBracket, rightToken);
100
+ if (hasSpacingBeforeNode && node.parent.type !== AST_NODE_TYPES.TSFunctionType) {
89
101
  context.report({
90
102
  node,
91
103
  messageId: "genericSpacingMismatch",
92
104
  *fix(fixer) {
93
- yield fixer.removeRange([node.range[1], node.range[1] + postBracket.length - 1]);
105
+ yield fixer.removeRange([leftToken.range[1], node.range[0]]);
94
106
  }
95
107
  });
96
108
  }
97
- }
98
- for (let i = 1; i < params.length; i++) {
99
- const prev = params[i - 1];
100
- const current = params[i];
101
- const from = prev.range[1];
102
- const to = current.range[0];
103
- const span = sourceCode.text.slice(from, to);
104
- if (span !== ", " && !span.match(/,\n/)) {
109
+ if (hasSpacingAfterParam && node.parent.type === AST_NODE_TYPES.TSFunctionType) {
105
110
  context.report({
106
- *fix(fixer) {
107
- yield fixer.replaceTextRange([from, to], ", ");
108
- },
109
- loc: {
110
- start: prev.loc.end,
111
- end: current.loc.start
112
- },
111
+ node,
113
112
  messageId: "genericSpacingMismatch",
114
- node
113
+ *fix(fixer) {
114
+ yield fixer.removeRange([endBracket.range[1], rightToken.range[0]]);
115
+ }
115
116
  });
116
117
  }
117
118
  }
@@ -172,46 +173,25 @@ const genericSpacing = createEslintRule({
172
173
  const params = node.params;
173
174
  for (let i = 0; i < params.length; i++) {
174
175
  const param = params[i];
175
- const pre = sourceCode.text.slice(0, param.range[0]);
176
- const preSpace = pre.match(/(\s+)$/)?.[0];
177
- const preComma = pre.match(/(,)\s+$/)?.[0];
178
- const post = sourceCode.text.slice(param.range[1]);
179
- const postSpace = post.match(/^(\s*)/)?.[0];
180
- if (preSpace && preSpace.length && !preComma && param.loc.start.line === node.loc.start.line) {
176
+ const leftToken = sourceCode.getTokenBefore(param);
177
+ const rightToken = sourceCode.getTokenAfter(param);
178
+ const hasSpacingBeforeParam = leftToken.value === "<" ? sourceCode.isSpaceBetween(leftToken, param) : false;
179
+ const hasSpacingAfterParam = rightToken.value === ">" ? sourceCode.isSpaceBetween(param, rightToken) : false;
180
+ if (hasSpacingBeforeParam) {
181
181
  context.report({
182
182
  node,
183
- loc: {
184
- start: {
185
- line: param.loc.start.line,
186
- column: param.loc.start.column + 1 - preSpace.length
187
- },
188
- end: {
189
- line: param.loc.start.line,
190
- column: param.loc.start.column - 1
191
- }
192
- },
193
183
  messageId: "genericSpacingMismatch",
194
184
  *fix(fixer) {
195
- yield fixer.replaceTextRange([param.range[0] - preSpace.length, param.range[0]], "");
185
+ yield fixer.removeRange([leftToken.range[1], param.range[0]]);
196
186
  }
197
187
  });
198
188
  }
199
- if (postSpace && postSpace.length && param.loc.end.line === node.loc.end.line) {
189
+ if (hasSpacingAfterParam) {
200
190
  context.report({
201
- loc: {
202
- start: {
203
- line: param.loc.end.line,
204
- column: param.loc.end.column
205
- },
206
- end: {
207
- line: param.loc.end.line,
208
- column: param.loc.end.column + postSpace.length
209
- }
210
- },
211
191
  node,
212
192
  messageId: "genericSpacingMismatch",
213
193
  *fix(fixer) {
214
- yield fixer.replaceTextRange([param.range[1], param.range[1] + postSpace.length], "");
194
+ yield fixer.removeRange([param.range[1], rightToken.range[0]]);
215
195
  }
216
196
  });
217
197
  }
@@ -253,9 +233,9 @@ const genericSpacing = createEslintRule({
253
233
  }
254
234
  });
255
235
 
256
- const RULE_NAME$5 = "import-dedupe";
236
+ const RULE_NAME$6 = "import-dedupe";
257
237
  const importDedupe = createEslintRule({
258
- name: RULE_NAME$5,
238
+ name: RULE_NAME$6,
259
239
  meta: {
260
240
  type: "problem",
261
241
  docs: {
@@ -304,9 +284,9 @@ const importDedupe = createEslintRule({
304
284
  });
305
285
 
306
286
  const operatorOrAnyBracketOrKeywordRE = /^(\||&|\*|\+|\-|\/|%|<|>|<=|>=|==|!=|===|!==|\[|\(|\{|as|extends|implements|keyof|new|readonly|typeof|unique|unknown)/;
307
- const RULE_NAME$4 = "space-between-generic-and-paren";
287
+ const RULE_NAME$5 = "space-between-generic-and-paren";
308
288
  const spaceBetweenGenericAndParen = createEslintRule({
309
- name: RULE_NAME$4,
289
+ name: RULE_NAME$5,
310
290
  meta: {
311
291
  type: "layout",
312
292
  docs: {
@@ -332,7 +312,7 @@ const spaceBetweenGenericAndParen = createEslintRule({
332
312
  const postComma = text.slice(node.range[1]).match(/^(,)/)?.[0];
333
313
  const postQuestionMark = text.slice(spaceStartRange + postSpace.length).match(/^(\?)/)?.[0];
334
314
  const postOperatorOrAnyBracketOrKeyword = text.slice(spaceStartRange + postSpace.length).match(operatorOrAnyBracketOrKeywordRE)?.[0];
335
- if (postSpace && postSpace.length && !postEqual && !postComma && !postQuestionMark && !postOperatorOrAnyBracketOrKeyword && node.parent.type !== "TSInferType") {
315
+ if (postSpace && postSpace.length && !postEqual && !postComma && !postQuestionMark && !postOperatorOrAnyBracketOrKeyword && node.parent.type !== AST_NODE_TYPES.TSInferType) {
336
316
  context.report({
337
317
  loc: {
338
318
  start: {
@@ -351,7 +331,7 @@ const spaceBetweenGenericAndParen = createEslintRule({
351
331
  }
352
332
  });
353
333
  }
354
- if (node.parent?.parent.type === "FunctionDeclaration") {
334
+ if (node.parent?.parent.type === AST_NODE_TYPES.FunctionDeclaration) {
355
335
  const spaceEndRange = node.range[0] - 1;
356
336
  const pre = sourceCode.text.slice(0, spaceEndRange);
357
337
  const preSpace = pre.match(/(\s+)$/)?.[0];
@@ -380,9 +360,9 @@ const spaceBetweenGenericAndParen = createEslintRule({
380
360
  }
381
361
  });
382
362
 
383
- const RULE_NAME$3 = "no-spaces-before-paren";
363
+ const RULE_NAME$4 = "no-spaces-before-paren";
384
364
  const noSpacesBeforeParen = createEslintRule({
385
- name: RULE_NAME$3,
365
+ name: RULE_NAME$4,
386
366
  meta: {
387
367
  type: "layout",
388
368
  docs: {
@@ -418,7 +398,7 @@ const noSpacesBeforeParen = createEslintRule({
418
398
  },
419
399
  CallExpression(node) {
420
400
  let caller = "property" in node.callee ? node.callee.property : node.callee;
421
- if (caller.type === "TSInstantiationExpression" && "property" in caller.expression) {
401
+ if (caller.type === AST_NODE_TYPES.TSInstantiationExpression && "property" in caller.expression) {
422
402
  caller = caller.expression.property;
423
403
  }
424
404
  const callerEnd = ref(caller.range[1]);
@@ -481,9 +461,9 @@ const noSpacesBeforeParen = createEslintRule({
481
461
  }
482
462
  });
483
463
 
484
- const RULE_NAME$2 = "space-in-empty-block";
464
+ const RULE_NAME$3 = "space-in-empty-block";
485
465
  const spaceInEmptyBlock = createEslintRule({
486
- name: RULE_NAME$2,
466
+ name: RULE_NAME$3,
487
467
  meta: {
488
468
  type: "layout",
489
469
  docs: {
@@ -548,6 +528,113 @@ const spaceInEmptyBlock = createEslintRule({
548
528
  }
549
529
  });
550
530
 
531
+ const RULE_NAME$2 = "space-before-function-paren";
532
+ const spaceBeforeFunctionParen = createEslintRule({
533
+ name: RULE_NAME$2,
534
+ meta: {
535
+ type: "layout",
536
+ docs: {
537
+ description: "Enforce consistent spacing before function parenthesis",
538
+ recommended: false,
539
+ extendsBaseRule: true
540
+ },
541
+ fixable: "whitespace",
542
+ schema: [
543
+ {
544
+ oneOf: [
545
+ {
546
+ enum: ["always", "never"]
547
+ },
548
+ {
549
+ type: "object",
550
+ properties: {
551
+ anonymous: {
552
+ enum: ["always", "never", "ignore"]
553
+ },
554
+ named: {
555
+ enum: ["always", "never", "ignore"]
556
+ },
557
+ asyncArrow: {
558
+ enum: ["always", "never", "ignore"]
559
+ }
560
+ },
561
+ additionalProperties: false
562
+ }
563
+ ]
564
+ }
565
+ ],
566
+ messages: {
567
+ unexpected: "Unexpected space before function parentheses.",
568
+ missing: "Missing space before function parentheses."
569
+ }
570
+ },
571
+ defaultOptions: ["always"],
572
+ create(context, [firstOption]) {
573
+ const sourceCode = context.getSourceCode();
574
+ const baseConfig = typeof firstOption === "string" ? firstOption : "always";
575
+ const overrideConfig = typeof firstOption === "object" ? firstOption : {};
576
+ function isNamedFunction(node) {
577
+ if (node.id != null) {
578
+ return true;
579
+ }
580
+ const parent = node.parent;
581
+ return parent.type === AST_NODE_TYPES.MethodDefinition || parent.type === AST_NODE_TYPES.TSAbstractMethodDefinition || parent.type === AST_NODE_TYPES.Property && (parent.kind === "get" || parent.kind === "set" || parent.method);
582
+ }
583
+ function getConfigForFunction(node) {
584
+ if (node.type === AST_NODE_TYPES.ArrowFunctionExpression) {
585
+ if (node.async && util.isOpeningParenToken(sourceCode.getFirstToken(node, { skip: 1 }))) {
586
+ return overrideConfig.asyncArrow ?? baseConfig;
587
+ }
588
+ } else if (isNamedFunction(node)) {
589
+ return overrideConfig.named ?? baseConfig;
590
+ } else if (!node.generator) {
591
+ return overrideConfig.anonymous ?? baseConfig;
592
+ }
593
+ return "ignore";
594
+ }
595
+ function checkFunction(node) {
596
+ const functionConfig = getConfigForFunction(node);
597
+ if (functionConfig === "ignore") {
598
+ return;
599
+ }
600
+ let leftToken, rightToken;
601
+ if (node.typeParameters) {
602
+ leftToken = sourceCode.getLastToken(node.typeParameters);
603
+ rightToken = sourceCode.getTokenAfter(leftToken);
604
+ } else {
605
+ rightToken = sourceCode.getFirstToken(node, util.isOpeningParenToken);
606
+ leftToken = sourceCode.getTokenBefore(rightToken);
607
+ }
608
+ const hasSpacing = sourceCode.isSpaceBetween(leftToken, rightToken);
609
+ if (hasSpacing && functionConfig === "never") {
610
+ context.report({
611
+ node,
612
+ loc: {
613
+ start: leftToken.loc.end,
614
+ end: rightToken.loc.start
615
+ },
616
+ messageId: "unexpected",
617
+ fix: (fixer) => fixer.removeRange([leftToken.range[1], rightToken.range[0]])
618
+ });
619
+ } else if (!hasSpacing && functionConfig === "always" && !node.typeParameters) {
620
+ context.report({
621
+ node,
622
+ loc: rightToken.loc,
623
+ messageId: "missing",
624
+ fix: (fixer) => fixer.insertTextAfter(leftToken, " ")
625
+ });
626
+ }
627
+ }
628
+ return {
629
+ ArrowFunctionExpression: checkFunction,
630
+ FunctionDeclaration: checkFunction,
631
+ FunctionExpression: checkFunction,
632
+ TSEmptyBodyFunctionExpression: checkFunction,
633
+ TSDeclareFunction: checkFunction
634
+ };
635
+ }
636
+ });
637
+
551
638
  const RULE_NAME$1 = "semi-spacing";
552
639
  const semiSpacing = createEslintRule({
553
640
  name: RULE_NAME$1,
@@ -566,29 +653,30 @@ const semiSpacing = createEslintRule({
566
653
  defaultOptions: [],
567
654
  create: (context) => {
568
655
  const sourceCode = context.getSourceCode();
569
- const text = sourceCode.text;
570
656
  return {
571
657
  TSTypeAliasDeclaration(node) {
572
- const sourceLine = text.slice(node.range[0], node.range[1]);
573
- const preSemiSpace = sourceLine.match(/(\s+);$/)?.[0];
574
- if (preSemiSpace) {
575
- const spaceStart = node.range[0] + sourceLine.length - preSemiSpace.length;
576
- const spaceEnd = node.range[0] + sourceLine.length - 1;
658
+ const leftToken = node.typeAnnotation;
659
+ const rightToken = sourceCode.getTokenAfter(node.typeAnnotation);
660
+ if (rightToken.type !== AST_TOKEN_TYPES.Punctuator) {
661
+ return;
662
+ }
663
+ const hasSpacing = sourceCode.isSpaceBetween(leftToken, rightToken);
664
+ if (hasSpacing) {
577
665
  context.report({
578
666
  loc: {
579
667
  start: {
580
- line: node.loc.start.line,
581
- column: node.loc.start.column + sourceLine.length - preSemiSpace.length
668
+ line: leftToken.loc.end.line,
669
+ column: leftToken.loc.end.column
582
670
  },
583
671
  end: {
584
- line: node.loc.start.line,
585
- column: node.loc.start.column + sourceLine.length - 1
672
+ line: rightToken.loc.start.line,
673
+ column: rightToken.loc.start.column
586
674
  }
587
675
  },
588
676
  node,
589
677
  messageId: "noSpaceBeforeSemi",
590
678
  *fix(fixer) {
591
- yield fixer.removeRange([spaceStart, spaceEnd]);
679
+ yield fixer.removeRange([leftToken.range[1], rightToken.range[0]]);
592
680
  }
593
681
  });
594
682
  }
@@ -654,7 +742,8 @@ const index = {
654
742
  "space-in-empty-block": spaceInEmptyBlock,
655
743
  "semi-spacing": semiSpacing,
656
744
  "no-inline-type-import": noInlineTypeImport,
657
- "no-spaces-before-paren": noSpacesBeforeParen
745
+ "no-spaces-before-paren": noSpacesBeforeParen,
746
+ "space-before-function-paren": spaceBeforeFunctionParen
658
747
  }
659
748
  };
660
749
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@so1ve/eslint-plugin",
3
- "version": "0.43.1",
3
+ "version": "0.45.0",
4
4
  "author": "Anthony Fu <anthonyfu117@hotmail.com> (https://github.com/antfu/)",
5
5
  "contributors": [
6
6
  {