flatlint 1.11.0 β 1.13.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 +11 -0
- package/README.md +27 -0
- package/lib/compare/collect-array.js +21 -0
- package/lib/compare/compare.js +21 -52
- package/lib/compare/equal.js +45 -0
- package/lib/plugins/add-missing-quote/index.js +5 -9
- package/lib/plugins/add-missing-square-brace/index.js +1 -4
- package/lib/plugins/convert-from-to-require/index.js +5 -0
- package/lib/plugins/remove-useless-round-brace/index.js +6 -10
- package/lib/plugins.js +4 -0
- package/lib/runner/replacer.js +33 -2
- package/lib/runner/runner.js +15 -7
- package/lib/types/types.js +8 -1
- package/package.json +1 -1
package/ChangeLog
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
2025.01.01, v1.13.0
|
|
2
|
+
|
|
3
|
+
feature:
|
|
4
|
+
- f24e4d3 flatlint: add support of __array
|
|
5
|
+
- 0b2d275 flatlint: compare: __array: add support
|
|
6
|
+
|
|
7
|
+
2024.12.31, v1.12.0
|
|
8
|
+
|
|
9
|
+
feature:
|
|
10
|
+
- dedb945 flatlint: add-missing-quote: improve
|
|
11
|
+
|
|
1
12
|
2024.12.31, v1.11.0
|
|
2
13
|
|
|
3
14
|
feature:
|
package/README.md
CHANGED
|
@@ -28,6 +28,15 @@ npm i flatlint
|
|
|
28
28
|
|
|
29
29
|
</details>
|
|
30
30
|
|
|
31
|
+
<details><summary>Convert <code>from</code> to <code>require</code></summary>
|
|
32
|
+
|
|
33
|
+
```diff
|
|
34
|
+
-const a = from 'a';
|
|
35
|
+
+const a = require('a');
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
</details>
|
|
39
|
+
|
|
31
40
|
<details><summary>add missing round braces in if statement</summary>
|
|
32
41
|
|
|
33
42
|
```diff
|
|
@@ -81,6 +90,24 @@ npm i flatlint
|
|
|
81
90
|
|
|
82
91
|
</details>
|
|
83
92
|
|
|
93
|
+
## Template literals
|
|
94
|
+
|
|
95
|
+
**FlatLint** uses language similar to π[**PutoutScript**](https://github.com/coderaiser/putout/blob/master/docs/putout-script.md#-putoutscript).
|
|
96
|
+
|
|
97
|
+
It can look similar, but has a couple differences:
|
|
98
|
+
- β
it may not be valid **JavaScript**, it can be couple tokens that can be fixed;
|
|
99
|
+
- β
it counts each symbol as a token;
|
|
100
|
+
|
|
101
|
+
### `__a`
|
|
102
|
+
|
|
103
|
+
From `__a` to `__z` is usually identifiers, but can also be strings if used with quotes `'__a'` they can be single or double,
|
|
104
|
+
it can be only one quote `'__a` - this is valid, since **FlatLint** is tokens based.
|
|
105
|
+
|
|
106
|
+
### `__array`
|
|
107
|
+
|
|
108
|
+
Collects everything that looks like array elements, it can start from squire brace `[__array;`, but that's not important
|
|
109
|
+
to end with it, since it used to fix error patterns.
|
|
110
|
+
|
|
84
111
|
## API
|
|
85
112
|
|
|
86
113
|
```js
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {Punctuator} from '#types';
|
|
2
|
+
import {equal} from './equal.js';
|
|
3
|
+
|
|
4
|
+
export const collectArray = ({currentTokenIndex, tokens, nextTemplateToken}) => {
|
|
5
|
+
const n = tokens.length;
|
|
6
|
+
const brace = Punctuator(']');
|
|
7
|
+
let index = currentTokenIndex;
|
|
8
|
+
|
|
9
|
+
for (; index < n; index++) {
|
|
10
|
+
const token = tokens[index];
|
|
11
|
+
|
|
12
|
+
if (equal(token, nextTemplateToken))
|
|
13
|
+
break;
|
|
14
|
+
|
|
15
|
+
if (equal(token, brace))
|
|
16
|
+
break;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return --index;
|
|
20
|
+
};
|
|
21
|
+
|
package/lib/compare/compare.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import {prepare} from '#parser';
|
|
2
|
+
import {isTemplateArrayToken} from '#types';
|
|
3
|
+
import {collectArray} from './collect-array.js';
|
|
2
4
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from '
|
|
5
|
+
equal,
|
|
6
|
+
equalAny,
|
|
7
|
+
equalId,
|
|
8
|
+
equalQuote,
|
|
9
|
+
equalStr,
|
|
10
|
+
} from './equal.js';
|
|
9
11
|
|
|
10
12
|
export const compare = (source, template) => {
|
|
11
13
|
const templateTokens = prepare(template);
|
|
@@ -16,26 +18,31 @@ export const compare = (source, template) => {
|
|
|
16
18
|
let isEqual = false;
|
|
17
19
|
let start = 0;
|
|
18
20
|
let end = 0;
|
|
21
|
+
let delta = 0;
|
|
19
22
|
|
|
20
23
|
for (let index = 0; index < n; index++) {
|
|
21
24
|
for (let templateIndex = 0; templateIndex < templateTokensLength; templateIndex++) {
|
|
22
25
|
const currentTokenIndex = index + templateIndex;
|
|
23
|
-
|
|
24
|
-
if (currentTokenIndex > n) {
|
|
25
|
-
isEqual = false;
|
|
26
|
-
break;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
26
|
const templateToken = templateTokens[templateIndex];
|
|
30
27
|
const currentToken = tokens[currentTokenIndex];
|
|
31
28
|
|
|
32
|
-
if (
|
|
29
|
+
if (isTemplateArrayToken(templateToken)) {
|
|
30
|
+
const indexOfArrayEnd = collectArray({
|
|
31
|
+
currentTokenIndex,
|
|
32
|
+
tokens,
|
|
33
|
+
templateToken,
|
|
34
|
+
nextTemplateToken: templateTokens[templateIndex + 1],
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
delta = indexOfArrayEnd - currentTokenIndex;
|
|
38
|
+
index = indexOfArrayEnd - templateIndex;
|
|
39
|
+
} else if (!compareAll(currentToken, templateToken)) {
|
|
33
40
|
isEqual = false;
|
|
34
41
|
break;
|
|
35
42
|
}
|
|
36
43
|
|
|
37
44
|
isEqual = true;
|
|
38
|
-
start = index;
|
|
45
|
+
start = index - delta;
|
|
39
46
|
end = currentTokenIndex;
|
|
40
47
|
}
|
|
41
48
|
|
|
@@ -62,41 +69,3 @@ function compareAll(a, b) {
|
|
|
62
69
|
|
|
63
70
|
return false;
|
|
64
71
|
}
|
|
65
|
-
|
|
66
|
-
function equal(a, b) {
|
|
67
|
-
return a.type === b.type && a.value === b.value;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function equalAny(a, b) {
|
|
71
|
-
if (!isIdentifier(b))
|
|
72
|
-
return false;
|
|
73
|
-
|
|
74
|
-
if (isPunctuator(a))
|
|
75
|
-
return false;
|
|
76
|
-
|
|
77
|
-
return b.value === '__';
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function equalQuote(a, b) {
|
|
81
|
-
if (!isPunctuator(a))
|
|
82
|
-
return false;
|
|
83
|
-
|
|
84
|
-
return isQuote(b.value);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function equalStr(a, b) {
|
|
88
|
-
if (!isStringLiteral(a))
|
|
89
|
-
return false;
|
|
90
|
-
|
|
91
|
-
return isId(b.value);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function equalId(a, b) {
|
|
95
|
-
if (!isIdentifier(b))
|
|
96
|
-
return false;
|
|
97
|
-
|
|
98
|
-
if (isPunctuator(a))
|
|
99
|
-
return false;
|
|
100
|
-
|
|
101
|
-
return isId(b.value);
|
|
102
|
-
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isId,
|
|
3
|
+
isIdentifier,
|
|
4
|
+
isPunctuator,
|
|
5
|
+
isQuote,
|
|
6
|
+
isStringLiteral,
|
|
7
|
+
} from '#types';
|
|
8
|
+
|
|
9
|
+
export function equal(a, b) {
|
|
10
|
+
return a.type === b.type && a.value === b.value;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function equalAny(a, b) {
|
|
14
|
+
if (!isIdentifier(b))
|
|
15
|
+
return false;
|
|
16
|
+
|
|
17
|
+
if (isPunctuator(a))
|
|
18
|
+
return false;
|
|
19
|
+
|
|
20
|
+
return b.value === '__';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function equalQuote(a, b) {
|
|
24
|
+
if (!isPunctuator(a))
|
|
25
|
+
return false;
|
|
26
|
+
|
|
27
|
+
return isQuote(b.value);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function equalStr(a, b) {
|
|
31
|
+
if (!isStringLiteral(a))
|
|
32
|
+
return false;
|
|
33
|
+
|
|
34
|
+
return isId(b.value);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function equalId(a, b) {
|
|
38
|
+
if (!isIdentifier(b))
|
|
39
|
+
return false;
|
|
40
|
+
|
|
41
|
+
if (isPunctuator(a))
|
|
42
|
+
return false;
|
|
43
|
+
|
|
44
|
+
return isId(b.value);
|
|
45
|
+
}
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
export
|
|
2
|
-
return 'Add missing quote';
|
|
3
|
-
}
|
|
1
|
+
export const report = () => 'Add missing quote';
|
|
4
2
|
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
};
|
|
10
|
-
}
|
|
3
|
+
export const replace = () => ({
|
|
4
|
+
'const __a = "__b;': 'const __a = "__b";',
|
|
5
|
+
'__a("__b)': '__a("__b")',
|
|
6
|
+
});
|
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
export
|
|
2
|
-
return 'Remove useless round brace';
|
|
3
|
-
}
|
|
1
|
+
export const report = () => 'Remove useless round brace';
|
|
4
2
|
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
};
|
|
11
|
-
}
|
|
3
|
+
export const replace = () => ({
|
|
4
|
+
'const __a = __b)': 'const __a = __b',
|
|
5
|
+
'const __a = "__b")': 'const __a = "__b"',
|
|
6
|
+
'from "__b")': 'from "__b"',
|
|
7
|
+
});
|
package/lib/plugins.js
CHANGED
|
@@ -3,13 +3,17 @@ import * as addMissingRoundBraces from './plugins/add-missing-round-braces/index
|
|
|
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
5
|
import * as convertCommaToSemicolon from './plugins/convert-comma-to-semicolon/index.js';
|
|
6
|
+
import * as convertFromToRequire from './plugins/convert-from-to-require/index.js';
|
|
6
7
|
import * as removeUselessRoundBrace from './plugins/remove-useless-round-brace/index.js';
|
|
8
|
+
import * as addConstToExport from './plugins/add-const-to-export/index.js';
|
|
7
9
|
|
|
8
10
|
export const plugins = [
|
|
9
11
|
['wrap-assignment-in-parens', wrapAssignmentInParens],
|
|
10
12
|
['add-missing-round-braces', addMissingRoundBraces],
|
|
11
13
|
['add-missing-squire-brace', addMissingSquireBrace],
|
|
12
14
|
['add-missing-quote', addMissingQuote],
|
|
15
|
+
['add-const-to-export', addConstToExport],
|
|
13
16
|
['convert-comma-to-semicolon', convertCommaToSemicolon],
|
|
17
|
+
['convert-from-to-require', convertFromToRequire],
|
|
14
18
|
['remove-useless-round-brace', removeUselessRoundBrace],
|
|
15
19
|
];
|
package/lib/runner/replacer.js
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
is,
|
|
3
|
+
isTemplateArray,
|
|
4
|
+
Punctuator,
|
|
5
|
+
} from '#types';
|
|
2
6
|
import {prepare} from '#parser';
|
|
3
7
|
import {compare} from '#compare';
|
|
4
8
|
import {traverse} from '#traverser';
|
|
9
|
+
import {collectArray} from '../compare/collect-array.js';
|
|
5
10
|
|
|
11
|
+
const {isArray} = Array;
|
|
6
12
|
const {entries} = Object;
|
|
7
13
|
|
|
8
14
|
export const replace = (tokens, {fix, rule, plugin}) => {
|
|
@@ -79,6 +85,23 @@ function getValues(tokens, waysFrom) {
|
|
|
79
85
|
const values = {};
|
|
80
86
|
|
|
81
87
|
for (const [name, index] of entries(waysFrom)) {
|
|
88
|
+
if (isTemplateArray(name)) {
|
|
89
|
+
debugger;
|
|
90
|
+
const endOfArray = collectArray({
|
|
91
|
+
currentTokenIndex: index,
|
|
92
|
+
tokens,
|
|
93
|
+
nextTemplateToken: Punctuator(';'),
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
if (index === endOfArray) {
|
|
97
|
+
values[name] = tokens[index];
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
values[name] = tokens.slice(index, endOfArray + 1);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
|
|
82
105
|
values[name] = tokens[index];
|
|
83
106
|
}
|
|
84
107
|
|
|
@@ -87,6 +110,14 @@ function getValues(tokens, waysFrom) {
|
|
|
87
110
|
|
|
88
111
|
function setValues({to, waysTo, values}) {
|
|
89
112
|
for (const [name, index] of entries(waysTo)) {
|
|
90
|
-
|
|
113
|
+
const current = values[name];
|
|
114
|
+
|
|
115
|
+
if (!isArray(current)) {
|
|
116
|
+
to[index] = values[name];
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
to.splice(index, 1, ...values[name]);
|
|
91
121
|
}
|
|
92
122
|
}
|
|
123
|
+
|
package/lib/runner/runner.js
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import {replace} from './replacer.js';
|
|
2
2
|
|
|
3
|
-
export const run = (tokens, {fix, plugins}) => {
|
|
3
|
+
export const run = (tokens, {fix, fixCount = 10, plugins}) => {
|
|
4
|
+
debugger;
|
|
4
5
|
const places = [];
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
while (--fixCount >= 0) {
|
|
8
|
+
for (const {rule, plugin} of plugins) {
|
|
9
|
+
places.push(...replace(tokens, {
|
|
10
|
+
fix,
|
|
11
|
+
rule,
|
|
12
|
+
plugin,
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
if (!fix || places.length) {
|
|
16
|
+
fixCount = 0;
|
|
17
|
+
break;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
12
20
|
}
|
|
13
21
|
|
|
14
22
|
return [places];
|
package/lib/types/types.js
CHANGED
|
@@ -30,8 +30,13 @@ export const is = (str, array = ALL) => {
|
|
|
30
30
|
const LINKED_NODE = /^__[a-z]$/;
|
|
31
31
|
const ANY = '__';
|
|
32
32
|
const QUOTE = /^['"]$/;
|
|
33
|
+
const ARRAY = '__array';
|
|
33
34
|
|
|
34
|
-
const ALL = [
|
|
35
|
+
const ALL = [
|
|
36
|
+
ANY,
|
|
37
|
+
LINKED_NODE,
|
|
38
|
+
ARRAY,
|
|
39
|
+
];
|
|
35
40
|
|
|
36
41
|
function check(str, item) {
|
|
37
42
|
if (isString(item))
|
|
@@ -42,3 +47,5 @@ function check(str, item) {
|
|
|
42
47
|
|
|
43
48
|
export const isId = (a) => LINKED_NODE.test(a);
|
|
44
49
|
export const isQuote = (a) => QUOTE.test(a);
|
|
50
|
+
export const isTemplateArray = (a) => a === ARRAY;
|
|
51
|
+
export const isTemplateArrayToken = (a) => isIdentifier(a) && isTemplateArray(a.value);
|