flatlint 1.27.0 → 1.28.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/ChangeLog CHANGED
@@ -1,3 +1,9 @@
1
+ 2025.01.08, v1.28.0
2
+
3
+ feature:
4
+ - b1e6b43 remove-useless-comma: improve
5
+ - 3ebb93d add-missing-semicolon: improve
6
+
1
7
  2025.01.08, v1.27.0
2
8
 
3
9
  feature:
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  closeRoundBrace,
3
+ comma,
3
4
  openRoundBrace,
4
5
  semicolon,
5
6
  } from '#types';
@@ -15,6 +16,9 @@ export const collectExpression = ({currentTokenIndex, tokens, nextTemplateToken
15
16
  if (equal(token, semicolon))
16
17
  break;
17
18
 
19
+ if (equal(token, comma))
20
+ break;
21
+
18
22
  if (equal(token, nextTemplateToken))
19
23
  break;
20
24
 
@@ -3,6 +3,8 @@ import {
3
3
  isTemplateArgsToken,
4
4
  isTemplateArrayToken,
5
5
  isTemplateExpressionToken,
6
+ OK,
7
+ NOT_OK,
6
8
  } from '#types';
7
9
  import {collectArray} from './collect-array.js';
8
10
  import {collectExpression} from './collect-expression.js';
@@ -25,9 +27,10 @@ export const compare = (source, template, {index = 0} = {}) => {
25
27
  let start = 0;
26
28
  let end = 0;
27
29
  let delta = 0;
28
- let skip = 0;
29
30
 
30
31
  for (; index < n; index++) {
32
+ let skip = 0;
33
+
31
34
  for (let templateIndex = 0; templateIndex < templateTokensLength; templateIndex++) {
32
35
  let currentTokenIndex = index + templateIndex - skip;
33
36
 
@@ -58,7 +61,7 @@ export const compare = (source, template, {index = 0} = {}) => {
58
61
  nextTemplateToken: templateTokens[templateIndex + 1],
59
62
  });
60
63
 
61
- if (n === indexOfExpressionEnd) {
64
+ if (indexOfExpressionEnd >= n - 1) {
62
65
  end = indexOfExpressionEnd;
63
66
  continue;
64
67
  }
@@ -90,10 +93,14 @@ export const compare = (source, template, {index = 0} = {}) => {
90
93
  }
91
94
 
92
95
  if (isEqual)
93
- return [true, start, ++end];
96
+ return [
97
+ OK,
98
+ start,
99
+ ++end,
100
+ ];
94
101
  }
95
102
 
96
- return [false];
103
+ return [NOT_OK];
97
104
  };
98
105
 
99
106
  const comparators = [
@@ -0,0 +1,77 @@
1
+ import {traverse} from '#traverser';
2
+ import {prepare} from '#parser';
3
+ import {
4
+ is,
5
+ isTemplateArgs,
6
+ isTemplateArray,
7
+ isTemplateExpression,
8
+ } from '#types';
9
+ import {collectArray} from './collect-array.js';
10
+ import {collectExpression} from './collect-expression.js';
11
+ import {collectArgs} from './collect-args.js';
12
+
13
+ const {entries} = Object;
14
+
15
+ export function findVarsWays(tokens) {
16
+ const ways = {};
17
+
18
+ traverse(tokens, {
19
+ Identifier({value, index}) {
20
+ if (is(value))
21
+ ways[value] = index;
22
+ },
23
+ StringLiteral({value, index}) {
24
+ if (is(value))
25
+ ways[value] = index;
26
+ },
27
+ });
28
+
29
+ return ways;
30
+ }
31
+
32
+ export function getValues(tokens, waysFrom) {
33
+ const values = {};
34
+
35
+ for (const [name, index] of entries(waysFrom)) {
36
+ let end = index;
37
+ let ok = true;
38
+
39
+ if (isTemplateArray(name))
40
+ [ok, end] = collectArray({
41
+ currentTokenIndex: index,
42
+ tokens,
43
+ });
44
+ else if (isTemplateExpression(name))
45
+ end = collectExpression({
46
+ currentTokenIndex: index,
47
+ tokens,
48
+ });
49
+ else if (isTemplateArgs(name))
50
+ [ok, end] = collectArgs({
51
+ currentTokenIndex: index,
52
+ tokens,
53
+ });
54
+
55
+ if (!ok) {
56
+ values[name] = [];
57
+ continue;
58
+ }
59
+
60
+ values[name] = tokens.slice(index, end + 1);
61
+ }
62
+
63
+ return values;
64
+ }
65
+
66
+ export function setValues({to, waysTo, values}) {
67
+ for (const [name, index] of entries(waysTo)) {
68
+ to.splice(index, 1, ...values[name]);
69
+ }
70
+ }
71
+
72
+ export function getCurrentValues({from, start, end, tokens}) {
73
+ const current = tokens.slice(start, end);
74
+ const waysFrom = findVarsWays(prepare(from));
75
+
76
+ return getValues(current, waysFrom);
77
+ }
@@ -1,9 +1,22 @@
1
- import {closeRoundBrace} from '#types';
1
+ import {
2
+ closeRoundBrace,
3
+ isPunctuator,
4
+ } from '#types';
2
5
 
3
6
  export const report = () => 'Add missing round braces';
4
7
 
5
8
  export const match = () => ({
6
- '__a(__args': (vars, path) => !path.isNextPunctuator(closeRoundBrace),
9
+ '__a(__args': (vars, path) => {
10
+ if (path.isCurrentPunctuator(closeRoundBrace))
11
+ return false;
12
+
13
+ for (const token of path.getAllNext()) {
14
+ if (isPunctuator(token, closeRoundBrace))
15
+ return false;
16
+ }
17
+
18
+ return true;
19
+ },
7
20
  });
8
21
 
9
22
  export const replace = () => ({
@@ -17,7 +17,10 @@ export const replace = () => ({
17
17
  });
18
18
 
19
19
  function check(vars, path) {
20
- if (path.isEndsWithPunctuator(comma))
20
+ if (path.isNextPunctuator(comma))
21
+ return false;
22
+
23
+ if (path.isNextPunctuator(semicolon))
21
24
  return false;
22
25
 
23
26
  if (path.isPrevIdentifier('function'))
@@ -1,4 +1,18 @@
1
+ import {colon, isPunctuator} from '#types';
2
+
1
3
  export const report = () => 'Use semicolon instead of trailing comma';
4
+ export const match = () => ({
5
+ '__a(__args),': (vars, path) => {
6
+ for (const token of path.getAllPrev()) {
7
+ if (isPunctuator(token, colon))
8
+ return false;
9
+ }
10
+
11
+ return true;
12
+ },
13
+ });
14
+
2
15
  export const replace = () => ({
3
16
  'const __a = __b,': 'const __a = __b;',
17
+ '__a(__args),': '__a(__args);',
4
18
  });
@@ -15,4 +15,5 @@ export const match = () => ({
15
15
 
16
16
  export const replace = () => ({
17
17
  '__a(__args) {},': '__a(__args) {}',
18
+ '__a(),': '__a()',
18
19
  });
package/lib/plugins.js CHANGED
@@ -2,20 +2,22 @@ import * as wrapAssignmentInParens from './plugins/wrap-assignment-in-parens/ind
2
2
  import * as addMissingRoundBraces from './plugins/add-missing-round-braces/index.js';
3
3
  import * as addMissingSquireBrace from './plugins/add-missing-square-brace/index.js';
4
4
  import * as addMissingQuote from './plugins/add-missing-quote/index.js';
5
+ import * as addMissingSemicolon from './plugins/add-missing-semicolon/index.js';
5
6
  import * as convertCommaToSemicolon from './plugins/convert-comma-to-semicolon/index.js';
6
7
  import * as convertFromToRequire from './plugins/convert-from-to-require/index.js';
7
8
  import * as removeUselessRoundBrace from './plugins/remove-useless-round-brace/index.js';
9
+ import * as removeUselessComma from './plugins/remove-useless-comma/index.js';
8
10
  import * as addConstToExport from './plugins/add-const-to-export/index.js';
9
- import * as addMissingSemicolon from './plugins/add-missing-semicolon/index.js';
10
11
 
11
12
  export const plugins = [
12
13
  ['wrap-assignment-in-parens', wrapAssignmentInParens],
13
14
  ['add-missing-round-braces', addMissingRoundBraces],
14
15
  ['add-missing-squire-brace', addMissingSquireBrace],
15
- ['add-missing-quote', addMissingQuote],
16
16
  ['add-missing-semicolon', addMissingSemicolon],
17
+ ['add-missing-quote', addMissingQuote],
17
18
  ['add-const-to-export', addConstToExport],
18
19
  ['convert-comma-to-semicolon', convertCommaToSemicolon],
19
20
  ['convert-from-to-require', convertFromToRequire],
20
21
  ['remove-useless-round-brace', removeUselessRoundBrace],
22
+ ['remove-useless-comma', removeUselessComma],
21
23
  ];
@@ -1,10 +1,6 @@
1
- const isString = (a) => typeof a === 'string';
2
1
  const getValue = (token) => token.value;
3
2
 
4
3
  export const print = (tokens) => {
5
- if (isString(tokens))
6
- return tokens;
7
-
8
4
  return tokens
9
5
  .map(getValue)
10
6
  .join('');
@@ -5,6 +5,9 @@ import {
5
5
  } from '#types';
6
6
 
7
7
  export const createPath = ({tokens, start, end}) => ({
8
+ tokens,
9
+ start,
10
+ end,
8
11
  getAllPrev: createGetAllPrev({
9
12
  tokens,
10
13
  start,
@@ -21,22 +24,12 @@ export const createPath = ({tokens, start, end}) => ({
21
24
  tokens,
22
25
  start,
23
26
  }),
24
- isEndsWithPunctuator: createIsCurrentPunctuator({
27
+ isCurrentPunctuator: createIsNextPunctuator({
25
28
  tokens,
26
- end,
27
- }),
28
- isCurrentPunctuator: createIsCurrentPunctuator({
29
- tokens,
30
- end,
29
+ end: end - 1,
31
30
  }),
32
31
  });
33
32
 
34
- const createIsCurrentPunctuator = ({tokens, end}) => (punctuator) => {
35
- const current = tokens[end - 1];
36
-
37
- return isPunctuator(current, punctuator);
38
- };
39
-
40
33
  const createIsNextPunctuator = ({tokens, end}) => (punctuator) => {
41
34
  const current = tokens[end];
42
35
 
@@ -1,17 +1,12 @@
1
1
  import debug from 'debug';
2
2
  import {compare} from '#compare';
3
3
  import {prepare} from '#parser';
4
- import {traverse} from '#traverser';
5
4
  import {
6
- is,
7
- isTemplateArgs,
8
- isTemplateArray,
9
- isTemplateExpression,
10
- } from '#types';
11
- import {collectArray} from '../compare/collect-array.js';
12
- import {collectExpression} from '../compare/collect-expression.js';
5
+ findVarsWays,
6
+ getCurrentValues,
7
+ setValues,
8
+ } from '#compare/values';
13
9
  import {createPath} from './path.js';
14
- import {collectArgs} from '../compare/collect-args.js';
15
10
 
16
11
  const returns = (a) => () => a;
17
12
  const {entries} = Object;
@@ -20,6 +15,7 @@ const log = debug('flatlint');
20
15
  export const replace = (tokens, {fix, rule, plugin}) => {
21
16
  const places = [];
22
17
  let isFixed = false;
18
+
23
19
  const match = plugin.match?.() ?? returns({});
24
20
 
25
21
  for (const [from, to] of entries(plugin.replace())) {
@@ -91,68 +87,3 @@ export const replace = (tokens, {fix, rule, plugin}) => {
91
87
 
92
88
  return [isFixed, places];
93
89
  };
94
-
95
- function findVarsWays(tokens) {
96
- const ways = {};
97
-
98
- traverse(tokens, {
99
- Identifier({value, index}) {
100
- if (is(value))
101
- ways[value] = index;
102
- },
103
- StringLiteral({value, index}) {
104
- if (is(value))
105
- ways[value] = index;
106
- },
107
- });
108
-
109
- return ways;
110
- }
111
-
112
- function getValues(tokens, waysFrom) {
113
- const values = {};
114
-
115
- for (const [name, index] of entries(waysFrom)) {
116
- let end = index;
117
- let ok = true;
118
-
119
- if (isTemplateArray(name))
120
- [ok, end] = collectArray({
121
- currentTokenIndex: index,
122
- tokens,
123
- });
124
- else if (isTemplateExpression(name))
125
- end = collectExpression({
126
- currentTokenIndex: index,
127
- tokens,
128
- });
129
- else if (isTemplateArgs(name))
130
- [ok, end] = collectArgs({
131
- currentTokenIndex: index,
132
- tokens,
133
- });
134
-
135
- if (!ok) {
136
- values[name] = [];
137
- continue;
138
- }
139
-
140
- values[name] = tokens.slice(index, end + 1);
141
- }
142
-
143
- return values;
144
- }
145
-
146
- function setValues({to, waysTo, values}) {
147
- for (const [name, index] of entries(waysTo)) {
148
- to.splice(index, 1, ...values[name]);
149
- }
150
- }
151
-
152
- function getCurrentValues({from, start, end, tokens}) {
153
- const current = tokens.slice(start, end);
154
-
155
- const waysFrom = findVarsWays(prepare(from));
156
-
157
- return getValues(current, waysFrom);
158
- }
@@ -82,6 +82,7 @@ export const closeRoundBrace = Punctuator(')');
82
82
  export const closeSquareBrace = Punctuator(']');
83
83
  export const semicolon = Punctuator(';');
84
84
  export const comma = Punctuator(',');
85
+ export const colon = Punctuator(':');
85
86
 
86
87
  export const OK = true;
87
88
  export const NOT_OK = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flatlint",
3
- "version": "1.27.0",
3
+ "version": "1.28.0",
4
4
  "description": "JavaScript tokens-based linter",
5
5
  "main": "lib/flatlint.js",
6
6
  "type": "module",
@@ -26,6 +26,9 @@
26
26
  "#compare": {
27
27
  "default": "./lib/compare/compare.js"
28
28
  },
29
+ "#compare/values": {
30
+ "default": "./lib/compare/values.js"
31
+ },
29
32
  "#runner": {
30
33
  "default": "./lib/runner/runner.js"
31
34
  },