@putout/plugin-esm 1.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/LICENSE +21 -0
- package/README.md +221 -0
- package/lib/declare-imports-first/index.js +63 -0
- package/lib/group-imports-by-source/index.js +70 -0
- package/lib/index.js +21 -0
- package/lib/merge-duplicate-imports-join/index.js +109 -0
- package/lib/merge-duplicate-imports-rename/index.js +53 -0
- package/lib/remove-empty-export/index.js +20 -0
- package/lib/remove-empty-import/index.js +35 -0
- package/lib/remove-quotes-from-import-assertions/index.js +7 -0
- package/lib/sort-imports-by-specifiers/index.js +43 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) coderaiser
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# @putout/plugin-esm [![NPM version][NPMIMGURL]][NPMURL]
|
|
2
|
+
|
|
3
|
+
[NPMIMGURL]: https://img.shields.io/npm/v/@putout/plugin-esm.svg?style=flat&longCache=true
|
|
4
|
+
[NPMURL]: https://npmjs.org/package/@putout/plugin-esm "npm"
|
|
5
|
+
|
|
6
|
+
> The static `import` statement is used to `import` read only live bindings which are exported by another module.
|
|
7
|
+
> The imported bindings are called live bindings because they are updated by the module that exported the binding, but cannot be re-assigned by the importing module.
|
|
8
|
+
>
|
|
9
|
+
> (c) [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
π[**Putout**](https://github.com/coderaiser/putout) plugin adds ability to transform to new **Node.js** API and apply best practices.
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
npm i putout @putout/plugin-esm -D
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Rules
|
|
21
|
+
|
|
22
|
+
- β
[declare-imports-first](#declare-imports-first);
|
|
23
|
+
- β
[group-imports-by-source](#group-imports-by-source);
|
|
24
|
+
- β
[merge-duplicate-imports](#merge-duplicate-imports);
|
|
25
|
+
- β
[remove-quotes-from-import-assertions](#remove-quotes-from-import-assertions);
|
|
26
|
+
- β
[remove-empty-import](#remove-empty-import);
|
|
27
|
+
- β
[remove-empty-export](#remove-empty-export);
|
|
28
|
+
- β
[sort-imports-by-specifiers](#sort-imports-by-specifiers);
|
|
29
|
+
|
|
30
|
+
## Config
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"rules": {
|
|
35
|
+
"esm/declare-imports-first": "on",
|
|
36
|
+
"esm/group-imports-by-source": "on",
|
|
37
|
+
"esm/merge-duplicate-imports": "on",
|
|
38
|
+
"esm/remove-quotes-from-import-assertions": "on",
|
|
39
|
+
"esm/remove-empty-export": "on",
|
|
40
|
+
"esm/remove-empty-import": ["on", {
|
|
41
|
+
"ignore": []
|
|
42
|
+
}],
|
|
43
|
+
"esm/sort-imports-by-specifiers": "on"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## declare-imports-first
|
|
49
|
+
|
|
50
|
+
Check out in π[**Putout Editor**](https://putout.cloudcmd.io/#/gist/b1c18e5d726afe4ebb69d6b7a7dda82b/8189590815a1b8adb35bb8a846e28228e3c7fadf). For **CommonJS** use [nodejs/declare-after-require](https://github.com/coderaiser/putout/tree/master/packages/plugin-nodejs#declare-after-require).
|
|
51
|
+
|
|
52
|
+
## β Example of incorrect code
|
|
53
|
+
|
|
54
|
+
```js
|
|
55
|
+
const [arg] = process.argv;
|
|
56
|
+
import esbuild from 'esbuild';
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## β
Example of correct code
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
import esbuild from 'esbuild';
|
|
63
|
+
|
|
64
|
+
const [arg] = process.argv;
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## group-imports-by-source
|
|
68
|
+
|
|
69
|
+
Group order:
|
|
70
|
+
|
|
71
|
+
- β
builtins;
|
|
72
|
+
- β
external;
|
|
73
|
+
- β
internal;
|
|
74
|
+
|
|
75
|
+
Checkout in π[**Putout Editor**](https://putout.cloudcmd.io/#/gist/3cc782acf95211f9d456d63a99032ee1/0674223d050bba572f5271ffdccf8616cb441af5).
|
|
76
|
+
|
|
77
|
+
## β Example of incorrect code
|
|
78
|
+
|
|
79
|
+
```js
|
|
80
|
+
import fs from 'node:fs';
|
|
81
|
+
import {lodash} from 'lodash';
|
|
82
|
+
import react from 'react';
|
|
83
|
+
import d from '../hello.js';
|
|
84
|
+
import ss from '../../bb/ss.js';
|
|
85
|
+
import b from './ss.js';
|
|
86
|
+
|
|
87
|
+
const c = 5;
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## β
Example of correct code
|
|
91
|
+
|
|
92
|
+
```js
|
|
93
|
+
import fs from 'node:fs';
|
|
94
|
+
import react from 'react';
|
|
95
|
+
import {lodash} from 'lodash';
|
|
96
|
+
import b from './ss.js';
|
|
97
|
+
import d from '../hello.js';
|
|
98
|
+
import ss from '../../bb/ss.js';
|
|
99
|
+
|
|
100
|
+
const c = 5;
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## merge-duplicate-imports
|
|
104
|
+
|
|
105
|
+
### join
|
|
106
|
+
|
|
107
|
+
To disable use:
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"rules": {
|
|
112
|
+
"esm/merge-duplicate-imports-join": "off"
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### β Example of incorrect code
|
|
118
|
+
|
|
119
|
+
```js
|
|
120
|
+
import test from 'supertape';
|
|
121
|
+
import {stub} from 'supertape';
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
#### β
Example of correct code
|
|
125
|
+
|
|
126
|
+
```js
|
|
127
|
+
import test, {stub} from 'supertape';
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### rename
|
|
131
|
+
|
|
132
|
+
Checkout in π[**Putout Editor**](https://putout.cloudcmd.io/#/gist/6604936dec6b1eed8ce0d143f2962f15/17b310a6e4d85b0b8615a8b91d0e27414e8af291).
|
|
133
|
+
|
|
134
|
+
To disable use:
|
|
135
|
+
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"rules": {
|
|
139
|
+
"esm/merge-duplicate-imports-rename": "off"
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
#### β Example of incorrect code
|
|
143
|
+
|
|
144
|
+
```js
|
|
145
|
+
import putout from './putout.js';
|
|
146
|
+
import all from './putout.js';
|
|
147
|
+
import x from './putout.js';
|
|
148
|
+
|
|
149
|
+
console.log(all);
|
|
150
|
+
console.log(x);
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
#### β
Example of correct code
|
|
154
|
+
|
|
155
|
+
```js
|
|
156
|
+
import putout from './putout.js';
|
|
157
|
+
|
|
158
|
+
console.log(putout);
|
|
159
|
+
console.log(putout);
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## remove-empty-export
|
|
163
|
+
|
|
164
|
+
```diff
|
|
165
|
+
-export {};
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## remove-empty-import
|
|
169
|
+
|
|
170
|
+
```diff
|
|
171
|
+
-import 'abc';
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
## remove-quotes-from-import-assertions
|
|
176
|
+
|
|
177
|
+
Checkout in π[**Putout Editor**](https://putout.cloudcmd.io/#/gist/f9f34acddbefba0ded53225ca10fa44e/7b4dba44602b9b2d28fe3a98989474a4b0d8d73d).
|
|
178
|
+
|
|
179
|
+
## β Example of incorrect code
|
|
180
|
+
|
|
181
|
+
```js
|
|
182
|
+
import json from './mod.json' with { type: 'json' };
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## β
Example of correct code
|
|
186
|
+
|
|
187
|
+
```js
|
|
188
|
+
import json from './mod.json' with { type: 'json' };
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## sort-imports-by-specifiers
|
|
192
|
+
|
|
193
|
+
Checkout in π[**Putout Editor**](https://putout.cloudcmd.io/#/gist/521e2ff199243a7ce1f65db7140c272e/28c0588281286f8a6765b8aa2ecabbfcde2973a7).
|
|
194
|
+
|
|
195
|
+
## β Example of incorrect code
|
|
196
|
+
|
|
197
|
+
```js
|
|
198
|
+
import {
|
|
199
|
+
a,
|
|
200
|
+
b,
|
|
201
|
+
c,
|
|
202
|
+
d,
|
|
203
|
+
} from 'd';
|
|
204
|
+
import a1 from 'a1';
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## β
Example of correct code
|
|
208
|
+
|
|
209
|
+
```js
|
|
210
|
+
import a1 from 'a1';
|
|
211
|
+
import {
|
|
212
|
+
a,
|
|
213
|
+
b,
|
|
214
|
+
c,
|
|
215
|
+
d,
|
|
216
|
+
} from 'd';
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## License
|
|
220
|
+
|
|
221
|
+
MIT
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {replaceWith} = require('putout').operator;
|
|
4
|
+
|
|
5
|
+
module.exports.report = () => `Declare imports first`;
|
|
6
|
+
|
|
7
|
+
module.exports.fix = ({path, importPath}) => {
|
|
8
|
+
let prev = path;
|
|
9
|
+
let preventInfiniteLoop = 500;
|
|
10
|
+
|
|
11
|
+
while (--preventInfiniteLoop) {
|
|
12
|
+
const {node} = importPath;
|
|
13
|
+
|
|
14
|
+
replaceWith(importPath, prev.node);
|
|
15
|
+
replaceWith(prev, node);
|
|
16
|
+
|
|
17
|
+
importPath = prev;
|
|
18
|
+
prev = prev.getPrevSibling();
|
|
19
|
+
|
|
20
|
+
if (!prev.node || prev.isImportDeclaration())
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
module.exports.traverse = ({push, pathStore}) => ({
|
|
26
|
+
ImportDeclaration: (path) => {
|
|
27
|
+
pathStore(path);
|
|
28
|
+
},
|
|
29
|
+
ExportNamedDeclaration: (path) => {
|
|
30
|
+
const {source} = path.node;
|
|
31
|
+
|
|
32
|
+
if (!source)
|
|
33
|
+
return;
|
|
34
|
+
|
|
35
|
+
pathStore(path);
|
|
36
|
+
},
|
|
37
|
+
ExportAllDeclaration: (path) => {
|
|
38
|
+
pathStore(path);
|
|
39
|
+
},
|
|
40
|
+
Program: {
|
|
41
|
+
exit: () => {
|
|
42
|
+
for (const importPath of pathStore()) {
|
|
43
|
+
if (importPath) {
|
|
44
|
+
const path = importPath.getPrevSibling();
|
|
45
|
+
|
|
46
|
+
if (!path.node)
|
|
47
|
+
continue;
|
|
48
|
+
|
|
49
|
+
if (path.isImportDeclaration())
|
|
50
|
+
continue;
|
|
51
|
+
|
|
52
|
+
if (path.isExportDeclaration())
|
|
53
|
+
continue;
|
|
54
|
+
|
|
55
|
+
push({
|
|
56
|
+
path,
|
|
57
|
+
importPath,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {isDeepStrictEqual} = require('node:util');
|
|
4
|
+
const {types, operator} = require('putout');
|
|
5
|
+
const {isImportDeclaration} = types;
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
replaceWithMultiple,
|
|
9
|
+
remove,
|
|
10
|
+
} = operator;
|
|
11
|
+
|
|
12
|
+
module.exports.report = () => `Group imports by source: 'builtins', 'external', 'internal'`;
|
|
13
|
+
|
|
14
|
+
module.exports.fix = ({grouped}) => {
|
|
15
|
+
const [first, ...others] = grouped;
|
|
16
|
+
const nodes = [first.node];
|
|
17
|
+
|
|
18
|
+
for (const current of others) {
|
|
19
|
+
const {node} = current;
|
|
20
|
+
remove(current);
|
|
21
|
+
nodes.push(node);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
replaceWithMultiple(first, nodes);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
module.exports.traverse = ({pathStore, push}) => ({
|
|
28
|
+
ImportDeclaration: pathStore,
|
|
29
|
+
Program: {
|
|
30
|
+
exit(path) {
|
|
31
|
+
const external = [];
|
|
32
|
+
const internal = [];
|
|
33
|
+
const builtin = [];
|
|
34
|
+
const all = pathStore().filter(isImportDeclaration);
|
|
35
|
+
|
|
36
|
+
if (!all.length)
|
|
37
|
+
return;
|
|
38
|
+
|
|
39
|
+
for (const current of all) {
|
|
40
|
+
const {value} = current.node.source;
|
|
41
|
+
|
|
42
|
+
if (value.startsWith('.')) {
|
|
43
|
+
internal.push(current);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (value.startsWith('node:')) {
|
|
48
|
+
builtin.push(current);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
external.push(current);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const grouped = [
|
|
56
|
+
...builtin,
|
|
57
|
+
...external,
|
|
58
|
+
...internal,
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
if (isDeepStrictEqual(all, grouped))
|
|
62
|
+
return;
|
|
63
|
+
|
|
64
|
+
push({
|
|
65
|
+
path,
|
|
66
|
+
grouped,
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
});
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const declareImportsFirst = require('./declare-imports-first');
|
|
4
|
+
const groupImportsBySource = require('./group-imports-by-source');
|
|
5
|
+
const mergeDuplicateImportsJoin = require('./merge-duplicate-imports-join');
|
|
6
|
+
const mergeDuplicateImportsRename = require('./merge-duplicate-imports-rename');
|
|
7
|
+
const removeQuotesFromImportAssertions = require('./remove-quotes-from-import-assertions');
|
|
8
|
+
const sortImportsBySpecifiers = require('./sort-imports-by-specifiers');
|
|
9
|
+
const removeEmptyImport = require('./remove-empty-import');
|
|
10
|
+
const removeEmptyExport = require('./remove-empty-export');
|
|
11
|
+
|
|
12
|
+
module.exports.rules = {
|
|
13
|
+
'declare-imports-first': declareImportsFirst,
|
|
14
|
+
'group-imports-by-source': groupImportsBySource,
|
|
15
|
+
'merge-duplicate-imports-join': mergeDuplicateImportsJoin,
|
|
16
|
+
'merge-duplicate-imports-rename': mergeDuplicateImportsRename,
|
|
17
|
+
'remove-quotes-from-import-assertions': removeQuotesFromImportAssertions,
|
|
18
|
+
'remove-empty-import': removeEmptyImport,
|
|
19
|
+
'remove-empty-export': removeEmptyExport,
|
|
20
|
+
'sort-imports-by-specifiers': sortImportsBySpecifiers,
|
|
21
|
+
};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {types, operator} = require('putout');
|
|
4
|
+
|
|
5
|
+
const {remove} = operator;
|
|
6
|
+
const {values} = Object;
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
isImportDefaultSpecifier,
|
|
10
|
+
isImportNamespaceSpecifier,
|
|
11
|
+
isImportDeclaration,
|
|
12
|
+
} = types;
|
|
13
|
+
|
|
14
|
+
module.exports.report = () => `Avoid duplicate imports`;
|
|
15
|
+
|
|
16
|
+
module.exports.fix = ({path, imports}) => {
|
|
17
|
+
const all = [];
|
|
18
|
+
|
|
19
|
+
for (const imp of imports) {
|
|
20
|
+
const {specifiers} = imp.node;
|
|
21
|
+
|
|
22
|
+
for (const spec of specifiers) {
|
|
23
|
+
if (isImportDefaultSpecifier(spec)) {
|
|
24
|
+
path.node.specifiers.unshift(spec);
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
all.push(spec);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
remove(imp);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
path.node.specifiers.push(...all);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
module.exports.traverse = ({push, pathStore}) => ({
|
|
38
|
+
ImportDeclaration(path) {
|
|
39
|
+
pathStore(path);
|
|
40
|
+
},
|
|
41
|
+
Program: {
|
|
42
|
+
exit: () => {
|
|
43
|
+
const imports = pathStore().filter(isImportDeclaration);
|
|
44
|
+
processImports(push, imports);
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
function processImports(push, imports) {
|
|
50
|
+
const {get, add} = duplicatesStore();
|
|
51
|
+
const importDefaults = new Map();
|
|
52
|
+
|
|
53
|
+
for (const path of imports) {
|
|
54
|
+
const {source, specifiers} = path.node;
|
|
55
|
+
|
|
56
|
+
const {value} = source;
|
|
57
|
+
|
|
58
|
+
if (specifiers.find(isImportNamespaceSpecifier))
|
|
59
|
+
continue;
|
|
60
|
+
|
|
61
|
+
const count = importDefaults.get(value) || 0;
|
|
62
|
+
|
|
63
|
+
const importDefaultCount = count + specifiers.filter(isImportDefaultSpecifier).length;
|
|
64
|
+
|
|
65
|
+
importDefaults.set(value, importDefaultCount);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
for (const path of imports) {
|
|
69
|
+
const {source, specifiers} = path.node;
|
|
70
|
+
|
|
71
|
+
const {value} = source;
|
|
72
|
+
|
|
73
|
+
if (specifiers.find(isImportNamespaceSpecifier))
|
|
74
|
+
continue;
|
|
75
|
+
|
|
76
|
+
if (importDefaults.get(value) > 1)
|
|
77
|
+
continue;
|
|
78
|
+
|
|
79
|
+
add(value, path);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
for (const list of get()) {
|
|
83
|
+
if (list.length === 1)
|
|
84
|
+
continue;
|
|
85
|
+
|
|
86
|
+
const [path, ...imports] = list;
|
|
87
|
+
|
|
88
|
+
push({
|
|
89
|
+
path,
|
|
90
|
+
imports,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function duplicatesStore() {
|
|
96
|
+
const duplicates = [];
|
|
97
|
+
|
|
98
|
+
const get = () => values(duplicates);
|
|
99
|
+
|
|
100
|
+
const add = (value, path) => {
|
|
101
|
+
duplicates[value] = duplicates[value] || [];
|
|
102
|
+
duplicates[value].push(path);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
get,
|
|
107
|
+
add,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {types, operator} = require('putout');
|
|
4
|
+
const {rename, remove} = operator;
|
|
5
|
+
const {isImportDefaultSpecifier} = types;
|
|
6
|
+
|
|
7
|
+
module.exports.report = () => 'Avoid duplicate imports';
|
|
8
|
+
|
|
9
|
+
module.exports.fix = ({path, imports}) => {
|
|
10
|
+
const {name} = path.node.specifiers[0].local;
|
|
11
|
+
remove(path);
|
|
12
|
+
|
|
13
|
+
const [first, ...other] = imports;
|
|
14
|
+
|
|
15
|
+
const firstName = first.node.specifiers[0].local.name;
|
|
16
|
+
rename(first, firstName, name);
|
|
17
|
+
|
|
18
|
+
for (const current of other) {
|
|
19
|
+
const currentName = current.node.specifiers[0].local.name;
|
|
20
|
+
rename(current, currentName, name);
|
|
21
|
+
remove(current);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
module.exports.traverse = ({push, uplist}) => ({
|
|
26
|
+
ImportDeclaration: (path) => {
|
|
27
|
+
const {value} = path.node.source;
|
|
28
|
+
const [specifier, ...other] = path.node.specifiers;
|
|
29
|
+
|
|
30
|
+
if (other.length)
|
|
31
|
+
return;
|
|
32
|
+
|
|
33
|
+
if (!isImportDefaultSpecifier(specifier))
|
|
34
|
+
return;
|
|
35
|
+
|
|
36
|
+
uplist(value, path);
|
|
37
|
+
},
|
|
38
|
+
Program: {
|
|
39
|
+
exit() {
|
|
40
|
+
for (const items of uplist()) {
|
|
41
|
+
if (items.length < 2)
|
|
42
|
+
continue;
|
|
43
|
+
|
|
44
|
+
const [path, ...imports] = items;
|
|
45
|
+
|
|
46
|
+
push({
|
|
47
|
+
path,
|
|
48
|
+
imports,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {operator} = require('putout');
|
|
4
|
+
const {remove} = operator;
|
|
5
|
+
|
|
6
|
+
module.exports.report = () => 'Remove empty export';
|
|
7
|
+
|
|
8
|
+
module.exports.fix = (path) => {
|
|
9
|
+
remove(path);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
module.exports.include = () => [
|
|
13
|
+
'ExportNamedDeclaration',
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
module.exports.filter = (path) => {
|
|
17
|
+
const {specifiers, declaration} = path.node;
|
|
18
|
+
|
|
19
|
+
return !declaration && !specifiers.length;
|
|
20
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {operator} = require('putout');
|
|
4
|
+
const {remove} = operator;
|
|
5
|
+
|
|
6
|
+
module.exports.report = () => `Avoid empty 'import' statement`;
|
|
7
|
+
|
|
8
|
+
module.exports.fix = (path) => {
|
|
9
|
+
remove(path);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const isCSS = (a) => /\.css/.test(a);
|
|
13
|
+
const isMin = (a) => /\.min\./.test(a);
|
|
14
|
+
|
|
15
|
+
module.exports.include = () => [
|
|
16
|
+
'ImportDeclaration',
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
module.exports.filter = (path, {options}) => {
|
|
20
|
+
const {specifiers, source} = path.node;
|
|
21
|
+
|
|
22
|
+
const {ignore = []} = options;
|
|
23
|
+
const {value} = source;
|
|
24
|
+
|
|
25
|
+
if (ignore.includes(value))
|
|
26
|
+
return false;
|
|
27
|
+
|
|
28
|
+
if (specifiers.length)
|
|
29
|
+
return false;
|
|
30
|
+
|
|
31
|
+
if (isCSS(value))
|
|
32
|
+
return false;
|
|
33
|
+
|
|
34
|
+
return !isMin(value);
|
|
35
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {parseImportSpecifiers} = require('parse-import-specifiers');
|
|
4
|
+
const {operator} = require('putout');
|
|
5
|
+
const {insertBefore, remove} = operator;
|
|
6
|
+
|
|
7
|
+
module.exports.report = () => `Sort imports by specifiers count`;
|
|
8
|
+
|
|
9
|
+
module.exports.fix = ({path, nextPath}) => {
|
|
10
|
+
const {node} = nextPath;
|
|
11
|
+
remove(nextPath);
|
|
12
|
+
insertBefore(path, node);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
module.exports.traverse = ({push}) => ({
|
|
16
|
+
ImportDeclaration(path) {
|
|
17
|
+
const {node} = path;
|
|
18
|
+
const {source, specifiers} = node;
|
|
19
|
+
const {imports} = parseImportSpecifiers(specifiers);
|
|
20
|
+
|
|
21
|
+
if (imports.length < 4)
|
|
22
|
+
return;
|
|
23
|
+
|
|
24
|
+
const nextPath = path.getNextSibling();
|
|
25
|
+
|
|
26
|
+
if (!nextPath.isImportDeclaration())
|
|
27
|
+
return;
|
|
28
|
+
|
|
29
|
+
if (nextPath.node.specifiers.length !== 1)
|
|
30
|
+
return;
|
|
31
|
+
|
|
32
|
+
if (!source.value.startsWith('./') && nextPath.node.source.value.startsWith('./'))
|
|
33
|
+
return;
|
|
34
|
+
|
|
35
|
+
if (source.value.startsWith('node:') && !nextPath.node.source.value.startsWith('node:'))
|
|
36
|
+
return;
|
|
37
|
+
|
|
38
|
+
push({
|
|
39
|
+
path,
|
|
40
|
+
nextPath,
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@putout/plugin-esm",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "commonjs",
|
|
5
|
+
"author": "coderaiser <mnemonic.enemy@gmail.com> (https://github.com/coderaiser)",
|
|
6
|
+
"description": "πPutout plugin improves ability to transform ESM code",
|
|
7
|
+
"homepage": "https://github.com/coderaiser/putout/tree/master/packages/plugin-esm#readme",
|
|
8
|
+
"main": "lib/index.js",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./lib/index.js"
|
|
11
|
+
},
|
|
12
|
+
"release": false,
|
|
13
|
+
"tag": false,
|
|
14
|
+
"changelog": false,
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/coderaiser/putout.git"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"test": "madrun test",
|
|
21
|
+
"watch:test": "madrun watch:test",
|
|
22
|
+
"lint": "madrun lint",
|
|
23
|
+
"fresh:lint": "madrun fresh:lint",
|
|
24
|
+
"lint:fresh": "madrun lint:fresh",
|
|
25
|
+
"fix:lint": "madrun fix:lint",
|
|
26
|
+
"coverage": "madrun coverage",
|
|
27
|
+
"report": "madrun report"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"putout",
|
|
32
|
+
"putout-plugin",
|
|
33
|
+
"plugin",
|
|
34
|
+
"esm"
|
|
35
|
+
],
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@putout/eslint-flat": "^2.0.0",
|
|
38
|
+
"@putout/plugin-declare": "*",
|
|
39
|
+
"@putout/plugin-declare-before-reference": "*",
|
|
40
|
+
"@putout/plugin-putout": "*",
|
|
41
|
+
"@putout/plugin-reuse-duplicate-init": "*",
|
|
42
|
+
"@putout/plugin-typescript": "*",
|
|
43
|
+
"@putout/test": "^11.0.0",
|
|
44
|
+
"c8": "^10.0.0",
|
|
45
|
+
"eslint": "^9.0.0",
|
|
46
|
+
"eslint-plugin-n": "^17.0.0",
|
|
47
|
+
"eslint-plugin-putout": "^23.0.0",
|
|
48
|
+
"lerna": "^6.0.1",
|
|
49
|
+
"madrun": "^10.0.0",
|
|
50
|
+
"montag": "^1.2.1",
|
|
51
|
+
"nodemon": "^3.0.1"
|
|
52
|
+
},
|
|
53
|
+
"peerDependencies": {
|
|
54
|
+
"putout": ">=37"
|
|
55
|
+
},
|
|
56
|
+
"license": "MIT",
|
|
57
|
+
"engines": {
|
|
58
|
+
"node": ">=18"
|
|
59
|
+
},
|
|
60
|
+
"publishConfig": {
|
|
61
|
+
"access": "public"
|
|
62
|
+
}
|
|
63
|
+
}
|