flatlint 1.12.0 β 1.14.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 +23 -0
- package/lib/compare/collect-array.js +20 -0
- package/lib/compare/collect-expression.js +28 -0
- package/lib/compare/compare.js +34 -51
- package/lib/compare/equal.js +45 -0
- package/lib/plugins/add-missing-square-brace/index.js +1 -4
- package/lib/plugins/remove-useless-round-brace/index.js +1 -2
- package/lib/runner/replacer.js +50 -3
- package/lib/runner/runner.js +5 -3
- package/lib/types/types.js +12 -1
- package/package.json +1 -1
package/ChangeLog
CHANGED
package/README.md
CHANGED
|
@@ -90,6 +90,29 @@ npm i flatlint
|
|
|
90
90
|
|
|
91
91
|
</details>
|
|
92
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
|
+
|
|
99
|
+
- β
it may not be valid **JavaScript**, it can be couple tokens that can be fixed;
|
|
100
|
+
- β
it counts each symbol as a token;
|
|
101
|
+
|
|
102
|
+
### `__a`
|
|
103
|
+
|
|
104
|
+
From `__a` to `__z` is usually identifiers, but can also be strings if used with quotes `'__a'` they can be single or double,
|
|
105
|
+
it can be only one quote `'__a` - this is valid, since **FlatLint** is tokens based.
|
|
106
|
+
|
|
107
|
+
### `__array`
|
|
108
|
+
|
|
109
|
+
Collects everything that looks like array elements, it can start from squire brace `[__array;`, but that's not important
|
|
110
|
+
to end with it, since it used to fix error patterns.
|
|
111
|
+
|
|
112
|
+
### `__expr`
|
|
113
|
+
|
|
114
|
+
Collects everything that looks like expression.
|
|
115
|
+
|
|
93
116
|
## API
|
|
94
117
|
|
|
95
118
|
```js
|
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {Punctuator} from '#types';
|
|
2
|
+
import {equal} from './equal.js';
|
|
3
|
+
|
|
4
|
+
export const collectExpression = ({currentTokenIndex, tokens, nextTemplateToken}) => {
|
|
5
|
+
const n = tokens.length;
|
|
6
|
+
const closeBrace = Punctuator(')');
|
|
7
|
+
const openBrace = Punctuator('(');
|
|
8
|
+
const semicolon = Punctuator(';');
|
|
9
|
+
let index = currentTokenIndex;
|
|
10
|
+
|
|
11
|
+
for (; index < n; index++) {
|
|
12
|
+
const token = tokens[index];
|
|
13
|
+
|
|
14
|
+
if (equal(token, semicolon))
|
|
15
|
+
break;
|
|
16
|
+
|
|
17
|
+
if (equal(token, nextTemplateToken))
|
|
18
|
+
break;
|
|
19
|
+
|
|
20
|
+
if (equal(token, openBrace))
|
|
21
|
+
break;
|
|
22
|
+
|
|
23
|
+
if (equal(token, closeBrace))
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return --index;
|
|
28
|
+
};
|
package/lib/compare/compare.js
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import {prepare} from '#parser';
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
isPunctuator,
|
|
6
|
-
isQuote,
|
|
7
|
-
isStringLiteral,
|
|
3
|
+
isTemplateArrayToken,
|
|
4
|
+
isTemplateExpressionToken,
|
|
8
5
|
} from '#types';
|
|
6
|
+
import {collectArray} from './collect-array.js';
|
|
7
|
+
import {collectExpression} from './collect-expression.js';
|
|
8
|
+
import {
|
|
9
|
+
equal,
|
|
10
|
+
equalAny,
|
|
11
|
+
equalId,
|
|
12
|
+
equalQuote,
|
|
13
|
+
equalStr,
|
|
14
|
+
} from './equal.js';
|
|
9
15
|
|
|
10
16
|
export const compare = (source, template) => {
|
|
11
17
|
const templateTokens = prepare(template);
|
|
@@ -16,26 +22,41 @@ export const compare = (source, template) => {
|
|
|
16
22
|
let isEqual = false;
|
|
17
23
|
let start = 0;
|
|
18
24
|
let end = 0;
|
|
25
|
+
let delta = 0;
|
|
19
26
|
|
|
20
27
|
for (let index = 0; index < n; index++) {
|
|
21
28
|
for (let templateIndex = 0; templateIndex < templateTokensLength; templateIndex++) {
|
|
22
29
|
const currentTokenIndex = index + templateIndex;
|
|
23
|
-
|
|
24
|
-
if (currentTokenIndex > n) {
|
|
25
|
-
isEqual = false;
|
|
26
|
-
break;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
30
|
const templateToken = templateTokens[templateIndex];
|
|
30
31
|
const currentToken = tokens[currentTokenIndex];
|
|
31
32
|
|
|
32
|
-
if (
|
|
33
|
+
if (isTemplateExpressionToken(templateToken)) {
|
|
34
|
+
const indexOfExpressionEnd = collectExpression({
|
|
35
|
+
currentTokenIndex,
|
|
36
|
+
tokens,
|
|
37
|
+
templateToken,
|
|
38
|
+
nextTemplateToken: templateTokens[templateIndex + 1],
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
delta = indexOfExpressionEnd - currentTokenIndex;
|
|
42
|
+
index = indexOfExpressionEnd - templateIndex;
|
|
43
|
+
} else if (isTemplateArrayToken(templateToken)) {
|
|
44
|
+
const indexOfArrayEnd = collectArray({
|
|
45
|
+
currentTokenIndex,
|
|
46
|
+
tokens,
|
|
47
|
+
templateToken,
|
|
48
|
+
nextTemplateToken: templateTokens[templateIndex + 1],
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
delta = indexOfArrayEnd - currentTokenIndex;
|
|
52
|
+
index = indexOfArrayEnd - templateIndex;
|
|
53
|
+
} else if (!compareAll(currentToken, templateToken)) {
|
|
33
54
|
isEqual = false;
|
|
34
55
|
break;
|
|
35
56
|
}
|
|
36
57
|
|
|
37
58
|
isEqual = true;
|
|
38
|
-
start = index;
|
|
59
|
+
start = index - delta;
|
|
39
60
|
end = currentTokenIndex;
|
|
40
61
|
}
|
|
41
62
|
|
|
@@ -62,41 +83,3 @@ function compareAll(a, b) {
|
|
|
62
83
|
|
|
63
84
|
return false;
|
|
64
85
|
}
|
|
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
|
+
}
|
package/lib/runner/replacer.js
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
|
-
import {is} from '#types';
|
|
2
|
-
import {prepare} from '#parser';
|
|
3
1
|
import {compare} from '#compare';
|
|
2
|
+
import {prepare} from '#parser';
|
|
4
3
|
import {traverse} from '#traverser';
|
|
4
|
+
import {
|
|
5
|
+
is,
|
|
6
|
+
isTemplateArray,
|
|
7
|
+
isTemplateExpression,
|
|
8
|
+
Punctuator,
|
|
9
|
+
} from '#types';
|
|
10
|
+
import {collectArray} from '../compare/collect-array.js';
|
|
11
|
+
import {collectExpression} from '../compare/collect-expression.js';
|
|
5
12
|
|
|
13
|
+
const {isArray} = Array;
|
|
6
14
|
const {entries} = Object;
|
|
7
15
|
|
|
8
16
|
export const replace = (tokens, {fix, rule, plugin}) => {
|
|
@@ -79,6 +87,38 @@ function getValues(tokens, waysFrom) {
|
|
|
79
87
|
const values = {};
|
|
80
88
|
|
|
81
89
|
for (const [name, index] of entries(waysFrom)) {
|
|
90
|
+
if (isTemplateArray(name)) {
|
|
91
|
+
const endOfArray = collectArray({
|
|
92
|
+
currentTokenIndex: index,
|
|
93
|
+
tokens,
|
|
94
|
+
nextTemplateToken: Punctuator(';'),
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
if (index === endOfArray) {
|
|
98
|
+
values[name] = tokens[index];
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
values[name] = tokens.slice(index, endOfArray + 1);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (isTemplateExpression(name)) {
|
|
107
|
+
const endOfArray = collectExpression({
|
|
108
|
+
currentTokenIndex: index,
|
|
109
|
+
tokens,
|
|
110
|
+
nextTemplateToken: Punctuator(';'),
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
if (index === endOfArray) {
|
|
114
|
+
values[name] = tokens[index];
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
values[name] = tokens.slice(index, endOfArray + 1);
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
|
|
82
122
|
values[name] = tokens[index];
|
|
83
123
|
}
|
|
84
124
|
|
|
@@ -87,6 +127,13 @@ function getValues(tokens, waysFrom) {
|
|
|
87
127
|
|
|
88
128
|
function setValues({to, waysTo, values}) {
|
|
89
129
|
for (const [name, index] of entries(waysTo)) {
|
|
90
|
-
|
|
130
|
+
const current = values[name];
|
|
131
|
+
|
|
132
|
+
if (!isArray(current)) {
|
|
133
|
+
to[index] = values[name];
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
to.splice(index, 1, ...values[name]);
|
|
91
138
|
}
|
|
92
139
|
}
|
package/lib/runner/runner.js
CHANGED
|
@@ -3,7 +3,7 @@ import {replace} from './replacer.js';
|
|
|
3
3
|
export const run = (tokens, {fix, fixCount = 10, plugins}) => {
|
|
4
4
|
const places = [];
|
|
5
5
|
|
|
6
|
-
while (--fixCount) {
|
|
6
|
+
while (--fixCount >= 0) {
|
|
7
7
|
for (const {rule, plugin} of plugins) {
|
|
8
8
|
places.push(...replace(tokens, {
|
|
9
9
|
fix,
|
|
@@ -11,8 +11,10 @@ export const run = (tokens, {fix, fixCount = 10, plugins}) => {
|
|
|
11
11
|
plugin,
|
|
12
12
|
}));
|
|
13
13
|
|
|
14
|
-
if (
|
|
15
|
-
|
|
14
|
+
if (!fix) {
|
|
15
|
+
fixCount = 0;
|
|
16
|
+
break;
|
|
17
|
+
}
|
|
16
18
|
}
|
|
17
19
|
}
|
|
18
20
|
|
package/lib/types/types.js
CHANGED
|
@@ -30,8 +30,15 @@ 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';
|
|
34
|
+
const EXPR = '__expr';
|
|
33
35
|
|
|
34
|
-
const ALL = [
|
|
36
|
+
const ALL = [
|
|
37
|
+
ANY,
|
|
38
|
+
LINKED_NODE,
|
|
39
|
+
ARRAY,
|
|
40
|
+
EXPR,
|
|
41
|
+
];
|
|
35
42
|
|
|
36
43
|
function check(str, item) {
|
|
37
44
|
if (isString(item))
|
|
@@ -42,3 +49,7 @@ function check(str, item) {
|
|
|
42
49
|
|
|
43
50
|
export const isId = (a) => LINKED_NODE.test(a);
|
|
44
51
|
export const isQuote = (a) => QUOTE.test(a);
|
|
52
|
+
export const isTemplateArray = (a) => a === ARRAY;
|
|
53
|
+
export const isTemplateExpression = (a) => a === EXPR;
|
|
54
|
+
export const isTemplateArrayToken = (a) => isIdentifier(a) && isTemplateArray(a.value);
|
|
55
|
+
export const isTemplateExpressionToken = (a) => isIdentifier(a) && isTemplateExpression(a.value);
|