@putout/plugin-esm 4.1.2 → 4.2.1
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/README.md +45 -1
- package/lib/apply-namespace-import-to-file/apply-namespace-import/index.js +16 -0
- package/lib/apply-namespace-import-to-file/get-imports/index.js +29 -0
- package/lib/apply-namespace-import-to-file/has-export-default/index.js +6 -0
- package/lib/apply-namespace-import-to-file/index.js +123 -0
- package/lib/apply-namespace-import-to-file/is-esm/index.js +18 -0
- package/lib/index.js +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,6 +27,10 @@ npm i putout @putout/plugin-esm -D
|
|
|
27
27
|
- ✅ [remove-empty-import](#remove-empty-import);
|
|
28
28
|
- ✅ [remove-empty-export](#remove-empty-export);
|
|
29
29
|
- ✅ [sort-imports-by-specifiers](#sort-imports-by-specifiers);
|
|
30
|
+
|
|
31
|
+
## File rules
|
|
32
|
+
|
|
33
|
+
- ✅ [apply-namespace-import-file](#resolve-imported-file);
|
|
30
34
|
- ✅ [resolve-imported-file](#resolve-imported-file);
|
|
31
35
|
|
|
32
36
|
## Config
|
|
@@ -45,7 +49,8 @@ npm i putout @putout/plugin-esm -D
|
|
|
45
49
|
"ignore": []
|
|
46
50
|
}],
|
|
47
51
|
"esm/sort-imports-by-specifiers": "on",
|
|
48
|
-
"esm/resolve-imported-file": "
|
|
52
|
+
"esm/resolve-imported-file": "off",
|
|
53
|
+
"esm/apply-namespace-of-file": "off"
|
|
49
54
|
}
|
|
50
55
|
}
|
|
51
56
|
```
|
|
@@ -306,12 +311,51 @@ import('foo.json', {
|
|
|
306
311
|
});
|
|
307
312
|
```
|
|
308
313
|
|
|
314
|
+
## File Rules
|
|
315
|
+
|
|
316
|
+
### apply-namespace-import-to-file
|
|
317
|
+
|
|
318
|
+
Check out in 🐊**Putout Editor**:
|
|
319
|
+
|
|
320
|
+
- ✅ [`apply-namespace-import-to-file`](https://putout.cloudcmd.io/#/gist/1492d584559e5798325047de679222a0/c6a37a803b80823de1b64ab944f2427aecefb51b);
|
|
321
|
+
- ✅ [`get-imports`](https://putout.cloudcmd.io/#/gist/5d7687215e9fbdf705935c444503dded/75a98d2db9d3847c73017e41637924b1cfd5a598);
|
|
322
|
+
- ✅ [`has-export-default`](https://putout.cloudcmd.io/#/gist/b50ccfe5cc8c0c97e2fc98b37903ade4/fbc026e6f1027581f7aa4879dcafcaa7754bf8f4);
|
|
323
|
+
- ✅ [`apply-namespace-import`](https://putout.cloudcmd.io/#/gist/23a6dc6741b772c03fbed95feda2b451/1fbecac6fc40282bcda0593aa666a8c213ef85b7);
|
|
324
|
+
|
|
325
|
+
Let's consider file structure:
|
|
326
|
+
|
|
327
|
+
```
|
|
328
|
+
/
|
|
329
|
+
|-- lib/
|
|
330
|
+
| `-- index.js "import a from './a.js';"
|
|
331
|
+
| `-- a.js "export const x = 2;"
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
In this case `index.js` can be fixed:
|
|
335
|
+
|
|
336
|
+
#### ❌ Example of incorrect code
|
|
337
|
+
|
|
338
|
+
```js
|
|
339
|
+
import a from './a.js';
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
#### ✅ Example of correct code
|
|
343
|
+
|
|
344
|
+
```js
|
|
345
|
+
import * as a from './a.js';
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
## License
|
|
349
|
+
|
|
350
|
+
MIT
|
|
351
|
+
|
|
309
352
|
### resolve-imported-file
|
|
310
353
|
|
|
311
354
|
Check out in 🐊**Putout Editor**:
|
|
312
355
|
|
|
313
356
|
- ✅ [`resolve-imported-file`](https://putout.cloudcmd.io/#/gist/241489cb2781dd37ec96baf0115cde4e/83c2f2e9f490850b7fda432f8d25ae6a64ed07e3);
|
|
314
357
|
- ✅ [`get-imports`](https://putout.cloudcmd.io/#/gist/ee10100fed86e4db926885dd54298668/7538bca7a9ae006d976f41261c0ed4c0e1902ace);
|
|
358
|
+
- ✅ [`is-esm`](https://putout.cloudcmd.io/#/gist/fa080be2bf3a6560e289d84b5873c2bc/2601091f6bf97148843767968c3afcb36dde31de);
|
|
315
359
|
- ✅ [`change-imports`](https://putout.cloudcmd.io/#/gist/23a6dc6741b772c03fbed95feda2b451/1fbecac6fc40282bcda0593aa666a8c213ef85b7);
|
|
316
360
|
|
|
317
361
|
Let's consider file structure:
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const report = (path) => {
|
|
2
|
+
const source = path.node.source.value;
|
|
3
|
+
const {specifiers} = path.node;
|
|
4
|
+
const [{local}] = specifiers;
|
|
5
|
+
const {name} = local;
|
|
6
|
+
|
|
7
|
+
return `'import ${name} from "${source}"' -> 'import * as ${name} from "${source}"'`;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const replace = ({options}) => {
|
|
11
|
+
const {name, source} = options;
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
[`import ${name} from "${source}"`]: `import * as ${name} from "${source}"`,
|
|
15
|
+
};
|
|
16
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export const include = () => [
|
|
2
|
+
'import __a from "__b"',
|
|
3
|
+
];
|
|
4
|
+
|
|
5
|
+
export const report = (path) => {
|
|
6
|
+
const [name, source] = getImport(path);
|
|
7
|
+
return `${name} <- ${source}`;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const fix = (path) => {
|
|
11
|
+
const [name, source] = getImport(path);
|
|
12
|
+
|
|
13
|
+
path.node.leadingComments = [
|
|
14
|
+
CommentLine(`${name} <- ${source}'`),
|
|
15
|
+
];
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const CommentLine = (value) => ({
|
|
19
|
+
type: 'CommentLine',
|
|
20
|
+
value: ` ${value}`,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const getImport = (path) => {
|
|
24
|
+
const source = path.node.source.value;
|
|
25
|
+
const [first] = path.node.specifiers;
|
|
26
|
+
const {name} = first.local;
|
|
27
|
+
|
|
28
|
+
return [name, source];
|
|
29
|
+
};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import {join, dirname} from 'node:path';
|
|
2
|
+
import putout, {
|
|
3
|
+
parse,
|
|
4
|
+
print,
|
|
5
|
+
transform,
|
|
6
|
+
operator,
|
|
7
|
+
} from 'putout';
|
|
8
|
+
import * as isESMPlugin from './is-esm/index.js';
|
|
9
|
+
import * as hasExportDefaultPlugin from './has-export-default/index.js';
|
|
10
|
+
import * as applyNamespaceImportPlugin from './apply-namespace-import/index.js';
|
|
11
|
+
import * as getImportsPlugin from './get-imports/index.js';
|
|
12
|
+
|
|
13
|
+
const {
|
|
14
|
+
findFile,
|
|
15
|
+
getFilename,
|
|
16
|
+
readFileContent,
|
|
17
|
+
writeFileContent,
|
|
18
|
+
} = operator;
|
|
19
|
+
|
|
20
|
+
const getMessage = (a) => a.message;
|
|
21
|
+
const isESM = (a) => a.rule === 'is-esm';
|
|
22
|
+
const hasExportDefault = (a) => a.rule === 'has-export-default';
|
|
23
|
+
|
|
24
|
+
export const report = (file, {name, source}) => `Use 'import * as ${name} from '${source}'`;
|
|
25
|
+
export const fix = (file, {name, source, content, ast}) => {
|
|
26
|
+
transform(ast, content, {
|
|
27
|
+
rules: {
|
|
28
|
+
'apply-namespace-import': ['on', {
|
|
29
|
+
name,
|
|
30
|
+
source,
|
|
31
|
+
}],
|
|
32
|
+
},
|
|
33
|
+
plugins: [
|
|
34
|
+
['apply-namespace-import', applyNamespaceImportPlugin],
|
|
35
|
+
],
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const newContent = print(ast);
|
|
39
|
+
|
|
40
|
+
writeFileContent(file, newContent);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const scan = (rootPath, {push, trackFile}) => {
|
|
44
|
+
const mask = [
|
|
45
|
+
'*.js',
|
|
46
|
+
'*.mjs',
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
for (const file of trackFile(rootPath, mask)) {
|
|
50
|
+
const content = readFileContent(file);
|
|
51
|
+
const ast = parse(content);
|
|
52
|
+
const importsTuples = getImports(file, content, ast);
|
|
53
|
+
|
|
54
|
+
for (const [name, source, importedFilename] of importsTuples) {
|
|
55
|
+
if (hasImportDefault(rootPath, importedFilename))
|
|
56
|
+
continue;
|
|
57
|
+
|
|
58
|
+
push(file, {
|
|
59
|
+
name,
|
|
60
|
+
source,
|
|
61
|
+
ast,
|
|
62
|
+
content,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
function getImports(file, content, ast) {
|
|
69
|
+
if (!content.includes('import'))
|
|
70
|
+
return [];
|
|
71
|
+
|
|
72
|
+
const places = transform(ast, content, {
|
|
73
|
+
fix: false,
|
|
74
|
+
plugins: [
|
|
75
|
+
['get-imports', getImportsPlugin],
|
|
76
|
+
],
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const filename = getFilename(file);
|
|
80
|
+
const dir = dirname(filename);
|
|
81
|
+
|
|
82
|
+
const imports = places.map(getMessage);
|
|
83
|
+
|
|
84
|
+
return buildImports(dir, imports);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function hasImportDefault(rootPath, importedFilename) {
|
|
88
|
+
const [importedFile] = findFile(rootPath, importedFilename);
|
|
89
|
+
|
|
90
|
+
if (!importedFile)
|
|
91
|
+
return true;
|
|
92
|
+
|
|
93
|
+
const importedContent = readFileContent(importedFile);
|
|
94
|
+
|
|
95
|
+
const {places} = putout(importedContent, {
|
|
96
|
+
fix: false,
|
|
97
|
+
plugins: [
|
|
98
|
+
['has-export-default', hasExportDefaultPlugin],
|
|
99
|
+
['is-esm', isESMPlugin],
|
|
100
|
+
],
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
const esm = places.filter(isESM);
|
|
104
|
+
const defaultExport = places.filter(hasExportDefault);
|
|
105
|
+
|
|
106
|
+
if (defaultExport.length)
|
|
107
|
+
return true;
|
|
108
|
+
|
|
109
|
+
return !esm.length;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function buildImports(dir, imports) {
|
|
113
|
+
const list = [];
|
|
114
|
+
|
|
115
|
+
for (const current of imports) {
|
|
116
|
+
const [name, source] = current.split(' <- ');
|
|
117
|
+
const full = join(dir, source);
|
|
118
|
+
|
|
119
|
+
list.push([name, source, full]);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return list;
|
|
123
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const report = (path) => path.type;
|
|
2
|
+
|
|
3
|
+
export const fix = (path) => {
|
|
4
|
+
path.node.leadingComments = [
|
|
5
|
+
CommentLine('esm'),
|
|
6
|
+
];
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export const include = () => [
|
|
10
|
+
'ExportDefaultDeclaration',
|
|
11
|
+
'ExportNamedDeclaration',
|
|
12
|
+
'ImportDeclaration',
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
const CommentLine = (value) => ({
|
|
16
|
+
type: 'CommentLine',
|
|
17
|
+
value: ` ${value}`,
|
|
18
|
+
});
|
package/lib/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as applyNamespaceImportToFile from './apply-namespace-import-to-file/index.js';
|
|
1
2
|
import * as resolveImportedFile from './resolve-imported-file/index.js';
|
|
2
3
|
import * as addIndexToImport from './add-index-to-import/index.js';
|
|
3
4
|
import * as declareImportsFirst from './declare-imports-first/index.js';
|
|
@@ -22,4 +23,5 @@ export const rules = {
|
|
|
22
23
|
'remove-empty-export': removeEmptyExport,
|
|
23
24
|
'sort-imports-by-specifiers': sortImportsBySpecifiers,
|
|
24
25
|
'resolve-imported-file': ['off', resolveImportedFile],
|
|
26
|
+
'apply-namespace-import-to-file': ['off', applyNamespaceImportToFile],
|
|
25
27
|
};
|
package/package.json
CHANGED