@putout/plugin-esm 6.1.1 β†’ 6.3.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/README.md CHANGED
@@ -93,15 +93,20 @@ export const rules = {};
93
93
  >
94
94
  > (c) [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export)
95
95
 
96
- Check out in 🐊[**Putout Editor**](https://putout.cloudcmd.io/##/gist/c9a3983d269745da89c1c7560f3b7fac/3ecb9aa6b910ce3816605bae11c8dd86bdc457e5).
96
+ Check out 🐊**Putout Editor**:
97
+
98
+ - [#1](https://putout.cloudcmd.io/#/gist/c9a3983d269745da89c1c7560f3b7fac/3ecb9aa6b910ce3816605bae11c8dd86bdc457e5);
99
+ - [#2](https://putout.cloudcmd.io/#/gist/9b2a0a51acf477291a6bbcbe7d846ddf/fa21768506f518ca0a1073beb82a9b8b8f5e7c19);
97
100
 
98
101
  #### ❌ Example of incorrect code
99
102
 
100
103
  ```js
101
104
  import * as ns_1 from 'x';
105
+ import {createAsyncLoader} from './load/async-loader.js';
102
106
 
103
107
  export {
104
108
  ns_1 as ns,
109
+ createAsyncLoader,
105
110
  };
106
111
  ```
107
112
 
@@ -109,6 +114,7 @@ export {
109
114
 
110
115
  ```js
111
116
  export * as ns from 'x';
117
+ export {createAsyncLoader} from './load/async-loader.js';
112
118
  ```
113
119
 
114
120
  ### merge-declaration-with-export
@@ -1,43 +1,78 @@
1
1
  import {types, operator} from 'putout';
2
2
 
3
3
  const {
4
- compare,
5
- getTemplateValues,
6
- remove,
7
- } = operator;
4
+ isExportSpecifier,
5
+ isImportSpecifier,
6
+ exportNamedDeclaration,
7
+ exportNamespaceSpecifier,
8
+ isImportNamespaceSpecifier,
9
+ } = types;
8
10
 
9
- const {exportNamespaceSpecifier} = types;
11
+ const {values} = Object;
12
+ const {remove, insertAfter} = operator;
10
13
 
11
- export const report = () => `Use 'export *' instead of 'import/export'`;
14
+ export const report = () => `Use 'export from' instead of 'import' + 'export'`;
12
15
 
13
- const IMPORT = 'import * as __a from "__b"';
14
-
15
- export const fix = ({path, current}) => {
16
- const {exported} = current.node.specifiers[0];
17
-
18
- current.node.source = path.node.source;
19
-
20
- delete current.node.local;
21
- delete current.node.exported;
22
-
23
- current.node.specifiers = [
24
- exportNamespaceSpecifier(exported),
25
- ];
16
+ export const fix = ({path, reference}) => {
17
+ const {parentPath} = path;
18
+ const parentReference = reference.parentPath;
19
+ const exportNode = createExport(path, parentReference);
26
20
 
27
- remove(path);
21
+ insertAfter(parentPath, exportNode);
22
+ removeSpecifier(path);
23
+ removeSpecifier(parentReference);
28
24
  };
29
25
 
30
26
  export const traverse = ({push}) => ({
31
- [IMPORT]: (path) => {
32
- const {__a} = getTemplateValues(path, IMPORT);
33
- const {name} = __a;
27
+ Program(path) {
28
+ const {bindings} = path.scope;
29
+ const imports = values(bindings).filter(isExported);
34
30
 
35
- for (const current of path.parentPath.get('body')) {
36
- if (compare(current, `export {${name} as __b}`))
37
- push({
38
- path,
39
- current,
40
- });
31
+ for (const {path, referencePaths} of imports) {
32
+ const [reference] = referencePaths;
33
+
34
+ push({
35
+ path,
36
+ reference,
37
+ });
41
38
  }
42
39
  },
43
40
  });
41
+
42
+ function isExported(binding) {
43
+ const {
44
+ path,
45
+ references,
46
+ referencePaths,
47
+ } = binding;
48
+
49
+ if (references !== 1)
50
+ return false;
51
+
52
+ if (!isImportSpecifier(path) && !isImportNamespaceSpecifier(path))
53
+ return false;
54
+
55
+ const [refPath] = referencePaths;
56
+
57
+ return isExportSpecifier(refPath.parentPath);
58
+ }
59
+
60
+ function removeSpecifier(path) {
61
+ if (path.parentPath.node.specifiers.length === 1)
62
+ remove(path.parentPath);
63
+ else
64
+ remove(path);
65
+ }
66
+
67
+ function createExport(path, parentReference) {
68
+ const {parentPath} = path;
69
+ const {source} = parentPath.node;
70
+
71
+ if (isImportSpecifier(path))
72
+ return exportNamedDeclaration(null, [parentReference.node], source);
73
+
74
+ const {exported} = parentReference.node;
75
+ const specifier = exportNamespaceSpecifier(exported);
76
+
77
+ return exportNamedDeclaration(null, [specifier], source);
78
+ }
package/lib/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import * as applyExportFrom from './apply-export-from/index.js';
1
2
  import * as mergeExportDeclarations from './merge-export-declarations/index.js';
2
3
  import * as removeUselessExportSpecifiers from './remove-useless-export-specifiers/index.js';
3
4
  import * as mergeDeclarationWithExport from './merge-declaration-with-export/index.js';
@@ -12,7 +13,6 @@ import * as removeEmptyImport from './remove-empty-import/index.js';
12
13
  import * as removeEmptyExport from './remove-empty-export/index.js';
13
14
  import * as mergeDuplicateImports from './merge-duplicate-imports/index.js';
14
15
  import * as convertAssertToWith from './convert-assert-to-with/index.js';
15
- import * as applyExportFrom from './apply-export-from/index.js';
16
16
 
17
17
  export const rules = {
18
18
  'add-index-to-import': ['off', addIndexToImport],
@@ -25,6 +25,9 @@ export const filter = (path) => {
25
25
  const {scope} = path;
26
26
  const specifiers = path.get('specifiers');
27
27
 
28
+ if (!specifiers.length)
29
+ return false;
30
+
28
31
  for (const spec of specifiers) {
29
32
  const {local, exported} = spec.node;
30
33
  const {name} = local;
@@ -1,39 +1,58 @@
1
1
  import {operator, types} from 'putout';
2
2
 
3
- const {isExportNamedDeclaration} = types;
4
3
  const {remove} = operator;
4
+ const {isExportNamedDeclaration} = types;
5
5
 
6
6
  export const report = () => `Merge export declarations`;
7
7
 
8
- export const fix = ({path, count, exports}) => {
8
+ export const fix = ({path, exports}) => {
9
9
  const all = [];
10
10
 
11
- for (const [index, path] of exports.entries()) {
11
+ for (const path of exports) {
12
12
  const {node} = path;
13
13
  const {specifiers} = node;
14
14
 
15
15
  all.push(...specifiers);
16
-
17
- if (index < count - 1)
18
- remove(path);
16
+ remove(path);
19
17
  }
20
18
 
21
- path.node.specifiers = all;
19
+ path.node.specifiers.push(...all);
22
20
  };
23
21
 
24
22
  export const traverse = ({push}) => ({
25
23
  Program(path) {
26
- const exports = path.get('body').filter(hasSpecifiers);
27
- const count = exports.length;
24
+ const filteredExports = path.get('body').filter(hasSpecifiers);
25
+ const count = filteredExports.length;
28
26
 
29
27
  if (count < 2)
30
28
  return;
31
29
 
32
- push({
33
- path: exports.at(-1),
34
- exports,
35
- count,
36
- });
30
+ const lists = [];
31
+ const marked = new Set();
32
+
33
+ for (const [i, a] of filteredExports.entries()) {
34
+ if (marked.has(a))
35
+ continue;
36
+
37
+ for (const b of filteredExports) {
38
+ if (a === b)
39
+ continue;
40
+
41
+ if (isSameSources(a, b)) {
42
+ marked.add(b);
43
+
44
+ lists[i] = lists[i] || [a];
45
+ lists[i].push(b);
46
+ }
47
+ }
48
+ }
49
+
50
+ for (const [path, ...exports] of lists) {
51
+ push({
52
+ path,
53
+ exports,
54
+ });
55
+ }
37
56
  },
38
57
  });
39
58
 
@@ -43,3 +62,16 @@ function hasSpecifiers(path) {
43
62
 
44
63
  return path.node.specifiers.length;
45
64
  }
65
+
66
+ function isSameSources(a, b) {
67
+ const sourceA = a.node.source;
68
+ const sourceB = b.node.source;
69
+
70
+ if (!sourceA && sourceA === sourceB)
71
+ return true;
72
+
73
+ if (!sourceA || !sourceB)
74
+ return false;
75
+
76
+ return sourceA.value === sourceB.value;
77
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@putout/plugin-esm",
3
- "version": "6.1.1",
3
+ "version": "6.3.0",
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",