@putout/plugin-esm 6.5.1 → 6.6.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
@@ -35,6 +35,7 @@ npm i putout @putout/plugin-esm -D
35
35
  ## File rules
36
36
 
37
37
  - ✅ [apply-namespace-import-file](#resolve-imported-file);
38
+ - ✅ [apply-privately-imported-file](#apply-privately-imported-file);
38
39
  - ✅ [resolve-imported-file](#resolve-imported-file);
39
40
  - ✅ [shorten-imported-file](#shorten-imported-file);
40
41
 
@@ -59,6 +60,7 @@ npm i putout @putout/plugin-esm -D
59
60
  "esm/resolve-imported-file": "off",
60
61
  "esm/shorten-imported-file": "off",
61
62
  "esm/apply-namespace-of-file": "off",
63
+ "esm/apply-privately-imported-file": "off",
62
64
  "esm/remove-useless-export-specifiers": "off"
63
65
  }
64
66
  }
@@ -444,6 +446,45 @@ import a from './a.js';
444
446
  import * as a from './a.js';
445
447
  ```
446
448
 
449
+ ### apply-privately-imported-to-file
450
+
451
+ > Entries in the imports field must be strings starting with `#`.
452
+ > Package imports permit mapping to external packages.
453
+ > This field defines subpath imports for the current package.
454
+ >
455
+ > (c) [nodejs.org](https://nodejs.org/api/packages.html#imports)
456
+
457
+ Check out in 🐊**Putout Editor**:
458
+
459
+ - ✅ [`get-imports`](https://putout.cloudcmd.io/#/gist/5d7687215e9fbdf705935c444503dded/75a98d2db9d3847c73017e41637924b1cfd5a598);
460
+ - ✅ [`change-imports`](https://putout.cloudcmd.io/#/gist/23a6dc6741b772c03fbed95feda2b451/1fbecac6fc40282bcda0593aa666a8c213ef85b7);
461
+
462
+ Let's consider file structure:
463
+
464
+ ```
465
+ /
466
+ |-- package.json {"imports": {"#is: {"default": "./lib/tokenize/is.js"}}}
467
+ |-- lib/
468
+ | `-- tokenize/
469
+ | `-- is.js "export const isPrev = () => {}"
470
+ | `-- expressions/
471
+ `-- spread-element.js "import {isPrev} from '../is.js"
472
+ ```
473
+
474
+ In this case `spread-element.js` can be fixed:
475
+
476
+ #### ❌ Example of incorrect code
477
+
478
+ ```js
479
+ import {isPrev} from '../is.js';
480
+ ```
481
+
482
+ #### ✅ Example of correct code
483
+
484
+ ```js
485
+ import {isPrev} from '#is';
486
+ ```
487
+
447
488
  ### resolve-imported-file
448
489
 
449
490
  Check out in 🐊**Putout Editor**:
@@ -0,0 +1,151 @@
1
+ import {
2
+ join,
3
+ dirname,
4
+ resolve,
5
+ } from 'node:path';
6
+ import {tryCatch} from 'try-catch';
7
+ import {
8
+ parse,
9
+ print,
10
+ transform,
11
+ operator,
12
+ } from 'putout';
13
+ import * as getImports from '../shorten-imported-file/get-imports/index.js';
14
+ import * as changeImports from '../resolve-imported-file/change-imports/index.js';
15
+
16
+ const {
17
+ getFilename,
18
+ getFileType,
19
+ getParentDirectory,
20
+ readFileContent,
21
+ writeFileContent,
22
+ readDirectory,
23
+ } = operator;
24
+
25
+ const {entries} = Object;
26
+ const {parse: parseJson} = JSON;
27
+
28
+ const getMessage = (a) => a.message;
29
+
30
+ export const report = (file, {from, to}) => `Apply privately imported source: '${from}' -> '${to}'`;
31
+ export const fix = (file, {content, ast, from, to}) => {
32
+ transform(ast, content, {
33
+ rules: {
34
+ 'change-imports': ['on', {
35
+ from,
36
+ to,
37
+ }],
38
+ },
39
+ plugins: [
40
+ ['change-imports', changeImports],
41
+ ],
42
+ });
43
+
44
+ const newContent = print(ast);
45
+
46
+ writeFileContent(file, newContent);
47
+ };
48
+
49
+ export const scan = (rootPath, {push, trackFile}) => {
50
+ const mask = [
51
+ '*.js',
52
+ '*.mjs',
53
+ ];
54
+
55
+ const getPrivateImports = createGetPrivateImports();
56
+
57
+ for (const file of trackFile(rootPath, mask)) {
58
+ const content = readFileContent(file);
59
+
60
+ if (!content.includes('import'))
61
+ continue;
62
+
63
+ const [, privateImports] = getPrivateImports(file);
64
+
65
+ if (!privateImports.size)
66
+ continue;
67
+
68
+ const ast = parse(content);
69
+
70
+ const places = transform(ast, content, {
71
+ plugins: [
72
+ ['get-imports', getImports],
73
+ ],
74
+ });
75
+
76
+ const imports = places.map(getMessage);
77
+
78
+ const filename = getFilename(file);
79
+ const dir = dirname(filename);
80
+
81
+ for (const from of imports) {
82
+ const to = join(dir, from).replace(dir, '.');
83
+
84
+ if (privateImports.has(to))
85
+ push(file, {
86
+ from,
87
+ to: privateImports.get(to),
88
+ content,
89
+ ast,
90
+ });
91
+ }
92
+ }
93
+ };
94
+
95
+ const createGetPrivateImports = (importsCache = new Map(), emptyMap = new Map()) => (file) => {
96
+ const filename = getFilename(file);
97
+ const dir = dirname(filename);
98
+
99
+ if (importsCache.has(dir))
100
+ return importsCache.get(dir);
101
+
102
+ const [packageDirectory, packagePath] = findPackage(file);
103
+
104
+ if (!packagePath) {
105
+ importsCache.set(dir, {});
106
+ return ['', emptyMap];
107
+ }
108
+
109
+ const packageContent = readFileContent(packagePath);
110
+ const [error, packageJson] = tryCatch(parseJson, packageContent);
111
+
112
+ if (error) {
113
+ importsCache.set(dir, emptyMap);
114
+
115
+ return ['', emptyMap];
116
+ }
117
+
118
+ const {imports = {}} = packageJson;
119
+ const importsEntries = new Map();
120
+
121
+ for (const [alias, {default: filePath}] of entries(imports)) {
122
+ const resolvedPath = resolve(packageDirectory, filePath);
123
+ importsEntries.set(resolvedPath, alias);
124
+ }
125
+
126
+ importsCache.set(dir, [packageDirectory, importsEntries]);
127
+
128
+ return [packageDirectory, importsEntries];
129
+ };
130
+
131
+ function findPackage(file) {
132
+ const parentDirectory = getParentDirectory(file);
133
+ const directoryName = getFilename(parentDirectory);
134
+
135
+ for (const currentFile of readDirectory(parentDirectory)) {
136
+ const type = getFileType(currentFile);
137
+
138
+ if (type === 'directory')
139
+ continue;
140
+
141
+ const currentName = getFilename(currentFile);
142
+
143
+ if (currentName.endsWith('package.json'))
144
+ return [directoryName, currentFile];
145
+ }
146
+
147
+ if (directoryName === '/')
148
+ return [];
149
+
150
+ return findPackage(parentDirectory);
151
+ }
package/lib/index.js CHANGED
@@ -2,9 +2,6 @@ import * as applyExportFrom from './apply-export-from/index.js';
2
2
  import * as mergeExportDeclarations from './merge-export-declarations/index.js';
3
3
  import * as removeUselessExportSpecifiers from './remove-useless-export-specifiers/index.js';
4
4
  import * as mergeDeclarationWithExport from './merge-declaration-with-export/index.js';
5
- import * as applyNamespaceImportToFile from './apply-namespace-import-to-file/index.js';
6
- import * as resolveImportedFile from './resolve-imported-file/index.js';
7
- import * as shortenImportedFile from './shorten-imported-file/index.js';
8
5
  import * as addIndexToImport from './add-index-to-import/index.js';
9
6
  import * as declareImportsFirst from './declare-imports-first/index.js';
10
7
  import * as groupImportsBySource from './group-imports-by-source/index.js';
@@ -14,6 +11,10 @@ import * as removeEmptyImport from './remove-empty-import/index.js';
14
11
  import * as removeEmptyExport from './remove-empty-export/index.js';
15
12
  import * as mergeDuplicateImports from './merge-duplicate-imports/index.js';
16
13
  import * as convertAssertToWith from './convert-assert-to-with/index.js';
14
+ import * as applyNamespaceImportToFile from './apply-namespace-import-to-file/index.js';
15
+ import * as applyPrivatelyImportedFile from './apply-privately-imported-file/index.js';
16
+ import * as resolveImportedFile from './resolve-imported-file/index.js';
17
+ import * as shortenImportedFile from './shorten-imported-file/index.js';
17
18
 
18
19
  export const rules = {
19
20
  'add-index-to-import': ['off', addIndexToImport],
@@ -26,10 +27,12 @@ export const rules = {
26
27
  'remove-empty-import': removeEmptyImport,
27
28
  'remove-empty-export': removeEmptyExport,
28
29
  'sort-imports-by-specifiers': sortImportsBySpecifiers,
29
- 'resolve-imported-file': ['off', resolveImportedFile],
30
- 'shorten-imported-file': ['off', shortenImportedFile],
31
- 'apply-namespace-import-to-file': ['off', applyNamespaceImportToFile],
32
30
  'merge-declaration-with-export': mergeDeclarationWithExport,
33
31
  'remove-useless-export-specifiers': removeUselessExportSpecifiers,
34
32
  'merge-export-declarations': mergeExportDeclarations,
33
+
34
+ 'resolve-imported-file': ['off', resolveImportedFile],
35
+ 'shorten-imported-file': ['off', shortenImportedFile],
36
+ 'apply-namespace-import-to-file': ['off', applyNamespaceImportToFile],
37
+ 'apply-privately-imported-file': ['off', applyPrivatelyImportedFile],
35
38
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@putout/plugin-esm",
3
- "version": "6.5.1",
3
+ "version": "6.6.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",