@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 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": "on"
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,6 @@
1
+ export const report = (path) => path.node.type;
2
+
3
+ export const fix = () => {};
4
+ export const include = () => [
5
+ 'ExportDefaultDeclaration',
6
+ ];
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@putout/plugin-esm",
3
- "version": "4.1.2",
3
+ "version": "4.2.1",
4
4
  "type": "module",
5
5
  "author": "coderaiser <mnemonic.enemy@gmail.com> (https://github.com/coderaiser)",
6
6
  "description": "🐊Putout plugin improves ability to transform ESM code",