|
1 | | -import { |
2 | | - findKey, |
3 | | - keys, |
4 | | - replace, |
5 | | - some, |
6 | | - startsWith, |
7 | | -} from '@dword-design/functions' |
8 | | -import { resolvePath } from 'babel-plugin-module-resolver' |
| 1 | +import { OptionManager } from '@babel/core' |
| 2 | +import { find, keys, replace, some, startsWith } from '@dword-design/functions' |
| 3 | +import { resolvePath as defaultResolvePath } from 'babel-plugin-module-resolver' |
9 | 4 | import P from 'path' |
10 | 5 |
|
11 | 6 | const isParentImport = path => /^(\.\/)?\.\.\//.test(path) |
| 7 | +const findMatchingAlias = (sourcePath, currentFile, options) => { |
| 8 | + const resolvePath = options.resolvePath || defaultResolvePath |
| 9 | + const absoluteSourcePath = P.resolve(P.dirname(currentFile), sourcePath) |
| 10 | + for (const aliasName of options.alias |> keys) { |
| 11 | + const path = P.resolve( |
| 12 | + P.dirname(currentFile), |
| 13 | + resolvePath(`${aliasName}/`, currentFile, options) |
| 14 | + ) |
| 15 | + if (absoluteSourcePath |> startsWith(path)) { |
| 16 | + return { name: aliasName, path } |
| 17 | + } |
| 18 | + } |
| 19 | + return undefined |
| 20 | +} |
12 | 21 |
|
13 | 22 | export default { |
14 | 23 | meta: { |
15 | 24 | type: 'suggestion', |
16 | 25 | fixable: true, |
17 | | - schema: [ |
18 | | - { |
19 | | - type: 'object', |
20 | | - properties: { |
21 | | - aliases: { type: 'object', default: { '@': '.' } }, |
22 | | - }, |
23 | | - required: ['aliases'], |
24 | | - }, |
25 | | - ], |
26 | 26 | }, |
27 | 27 | create: context => { |
28 | | - const aliases = context.options[0]?.aliases || { '@': '.' } |
29 | | - const path = context.getFilename() |
| 28 | + const currentFile = context.getFilename() |
| 29 | + const folder = P.dirname(currentFile) |
30 | 30 | // can't check a non-file |
31 | | - if (path === '<text>') return {} |
| 31 | + if (currentFile === '<text>') return {} |
| 32 | + const manager = new OptionManager() |
| 33 | + const babelConfig = manager.init({ |
| 34 | + babelrc: true, |
| 35 | + root: folder, |
| 36 | + filename: currentFile, |
| 37 | + }) |
| 38 | + const plugin = babelConfig.plugins |> find({ key: 'module-resolver' }) |
| 39 | + const options = plugin.options |
| 40 | + const resolvePath = options.resolvePath || defaultResolvePath |
32 | 41 | return { |
33 | 42 | ImportDeclaration: node => { |
34 | | - const importPath = node.source.value |
| 43 | + const sourcePath = node.source.value |
35 | 44 | const hasAlias = |
36 | | - aliases |> keys |> some(alias => importPath |> startsWith(alias)) |
37 | | - const resolvedImport = resolvePath(importPath, path, { |
38 | | - alias: aliases, |
39 | | - }) |
| 45 | + options.alias |
| 46 | + |> keys |
| 47 | + |> some(alias => sourcePath |> startsWith(`${alias}/`)) |
40 | 48 | // relative parent |
41 | | - if (importPath |> isParentImport) { |
42 | | - const folder = P.basename(path) |
43 | | - const resolvedImportPath = P.resolve(folder, importPath) |
44 | | - const matchingAlias = |
45 | | - aliases |
46 | | - |> findKey( |
47 | | - aliasPath => |
48 | | - resolvedImportPath |> startsWith(P.resolve(aliasPath)) |
49 | | - ) |
| 49 | + if (sourcePath |> isParentImport) { |
| 50 | + const matchingAlias = findMatchingAlias( |
| 51 | + sourcePath, |
| 52 | + currentFile, |
| 53 | + options |
| 54 | + ) |
50 | 55 | if (!matchingAlias) { |
51 | 56 | return context.report({ |
52 | 57 | node, |
53 | | - message: `Unexpected parent import '${importPath}'. No matching alias found to fix the issue`, |
| 58 | + message: `Unexpected parent import '${sourcePath}'. No matching alias found to fix the issue`, |
54 | 59 | }) |
55 | 60 | } |
56 | | - const rewrittenImport = `${matchingAlias}/${ |
57 | | - P.relative(P.resolve(aliases[matchingAlias]), resolvedImportPath) |
| 61 | + const absoluteImportPath = P.resolve(folder, sourcePath) |
| 62 | + const rewrittenImport = `${matchingAlias.name}/${ |
| 63 | + P.relative(matchingAlias.path, absoluteImportPath) |
58 | 64 | |> replace(/\\/g, '/') |
59 | 65 | }` |
60 | 66 | return context.report({ |
61 | 67 | node, |
62 | | - message: `Unexpected parent import '${importPath}'. Use '${rewrittenImport}' instead`, |
| 68 | + message: `Unexpected parent import '${sourcePath}'. Use '${rewrittenImport}' instead`, |
63 | 69 | fix: fixer => |
64 | 70 | fixer.replaceTextRange( |
65 | 71 | [node.source.range[0] + 1, node.source.range[1] - 1], |
66 | 72 | rewrittenImport |
67 | 73 | ), |
68 | 74 | }) |
69 | 75 | } |
70 | | - if (!(resolvedImport |> isParentImport) && hasAlias) { |
| 76 | + const importWithoutAlias = resolvePath(sourcePath, currentFile, options) |
| 77 | + if (!(importWithoutAlias |> isParentImport) && hasAlias) { |
71 | 78 | return context.report({ |
72 | 79 | node, |
73 | | - message: `Unexpected subpath import via alias '${importPath}'. Use '${resolvedImport}' instead`, |
| 80 | + message: `Unexpected subpath import via alias '${sourcePath}'. Use '${importWithoutAlias}' instead`, |
74 | 81 | fix: fixer => |
75 | 82 | fixer.replaceTextRange( |
76 | 83 | [node.source.range[0] + 1, node.source.range[1] - 1], |
77 | | - resolvedImport |
| 84 | + importWithoutAlias |
78 | 85 | ), |
79 | 86 | }) |
80 | 87 | } |
|
0 commit comments