Skip to content

Commit e0c140b

Browse files
authored
Feature/2.0.0 (#21)
* update to 2.0.0 * add bundler * add some error handling * normalize the source before splitting * handle absolute path and fix other issues * fix tests * update readme and change version * update to use vite 5 * fix error message when viteConfig is not object * remove unnecessary log
1 parent 6709967 commit e0c140b

File tree

8 files changed

+2165
-1088
lines changed

8 files changed

+2165
-1088
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
node_modules/
2+
dist/

.npmignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.editorconfig
2+
.gitignore
3+
index.js
4+
index.test.js
5+
jest.config.js
6+
Makefile
7+
vite.config.js

README.md

Lines changed: 17 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -2,88 +2,45 @@
22

33
Vite module resolution plugin for `eslint-plugin-import`. This plugin will resolve the `resolve.alias` option.
44

5-
> #### Version `2.0.0-beta.3` is available. See [what's changed](https://github.com/pzmosquito/eslint-import-resolver-vite/releases/tag/2.0.0-beta.1).
6-
> ```sh
7-
> npm install --save-dev [email protected]
8-
> ```
95

106
### Installation
117
```sh
128
npm install --save-dev eslint-import-resolver-vite
13-
14-
# install vite-plugin-eslint if you don't already have it
15-
npm install --save-dev vite-plugin-eslint
169
```
1710

11+
12+
### Config Options
13+
- **viteConfig**: The Vite config object.
14+
- Required: Yes
15+
- Type: object
16+
17+
1818
### How to use
19-
```js
20-
/**
21-
* vite config file
22-
*/
23-
import eslintPlugin from "vite-plugin-eslint";
2419

25-
export default {
20+
#### Vite config file
21+
```js
22+
export const viteConfigObj = {
2623
resolve: {
2724
alias: {
2825
_: path.resolve(__dirname, "src")
2926
}
3027
},
31-
plugins: [
32-
eslintPlugin()
33-
]
3428
};
29+
```
3530

36-
/**
37-
* eslint config file
38-
*/
31+
#### ESLint config file
32+
NOTE:
33+
- Since `eslint-plugin-import` doesn't support an async resolver, Vite's [ResolvedConfig API](https://vitejs.dev/guide/api-javascript.html#resolvedconfig) cannot be utilized.
34+
- This plugin accepts a Vite config object to accommodate various setups, e.g. CJS, ESM, or mixed.
35+
```js
3936
module.exports = {
4037
settings: {
41-
// This uses the default `vite.config.js` file and the Vite configuration is an object.
42-
"import/resolver": "vite",
43-
44-
// OR use custom config (see Config Options below):
4538
"import/resolver": {
4639
vite: {
47-
configPath: "./app1/vite.confg.ts"
40+
viteConfig: require("./vite.config").viteConfigObj,
4841
}
4942
}
5043
}
5144
}
5245

5346
```
54-
55-
### Config Options
56-
- **configPath**: vite config file path.
57-
- Required: No
58-
- Type: string
59-
- Default: "vite.config.js"
60-
- By default, the plugin assumes the vite config file and eslintrc file are in the same directory.
61-
- **namedExport**: named export of vite config object.
62-
- Required: No
63-
- Type: string
64-
- Default: [No Default]
65-
- **If you use a function as vite config, you must export a named vite config object. This is a result of the limitation of `eslint-plugin-import`.**
66-
```js
67-
/**
68-
* vite config file
69-
*/
70-
export const viteConfig = {};
71-
72-
export default ({ command, mode }) => {
73-
// conditional config
74-
return viteConfig;
75-
}
76-
77-
/**
78-
* eslintrc file
79-
*/
80-
module.exports = {
81-
settings: {
82-
"import/resolver": {
83-
vite: {
84-
namedExport: "viteConfig"
85-
}
86-
}
87-
}
88-
}
89-
```

index.js

Lines changed: 71 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,97 @@
11
const path = require("path");
22
const resolve = require("resolve");
3-
const fs = require("fs");
43
const debug = require("debug");
5-
64
const namespace = "eslint-plugin-import:resolver:vite";
7-
85
const log = debug(namespace);
96

10-
const logError = (message) => {
11-
log(message);
12-
console.error(`[${namespace}] ${message}`);
7+
const processAlias = (alias, source) => {
8+
if (alias) {
9+
const pathParts = path.normalize(source).split(path.sep);
10+
if (Array.isArray(alias)) {
11+
for (let i = 0; i < pathParts.length; i++) {
12+
alias.forEach(({find, replacement}) => {
13+
if (pathParts[i] === find) {
14+
pathParts[i] = replacement;
15+
}
16+
});
17+
}
18+
}
19+
else if (typeof alias === "object") {
20+
for (let i = 0; i < pathParts.length; i++) {
21+
if (alias.hasOwnProperty(pathParts[i])) {
22+
pathParts[i] = alias[pathParts[i]];
23+
}
24+
}
25+
}
26+
else {
27+
throw new Error("The alias must be either an object, or an array of objects.");
28+
}
29+
return pathParts.join(path.sep);
30+
}
31+
return source;
32+
};
33+
34+
const resolveSync = (source, resolveOptions, label) => {
35+
log("resolving:\t", `(${label})`, source);
36+
const resolvedPath = resolve.sync(source, resolveOptions);
37+
log("resolved:\t", resolvedPath);
38+
return { found: true, path: resolvedPath };
1339
};
1440

1541
exports.interfaceVersion = 2;
1642

1743
exports.resolve = (source, file, config) => {
18-
log("resolving:", source);
19-
log("in file:", file);
44+
log("\nin file:\t", file);
2045

2146
if (resolve.isCore(source)) {
47+
log("resolved:\t", source);
2248
return { found: true, path: null };
2349
}
2450

25-
try {
26-
// combine default config with user defined config
27-
const pluginConfig = {
28-
configPath: "vite.config.js",
29-
...(config ?? {}),
30-
};
31-
32-
// load vite config
33-
const viteConfigPath = path.resolve(pluginConfig.configPath);
34-
if (!fs.existsSync(viteConfigPath)) {
35-
throw new Error(`Vite config file doesn't exist at '${viteConfigPath}'`)
36-
}
37-
const viteConfigFile = require(viteConfigPath);
38-
39-
let viteConfig;
40-
if (pluginConfig.namedExport) {
41-
viteConfig = viteConfigFile[pluginConfig.namedExport]
42-
}
43-
else {
44-
const viteConfigObj = viteConfigFile.default ?? viteConfigFile
45-
viteConfig = typeof viteConfigObj === "function" ? viteConfigObj() : viteConfigObj;
46-
}
51+
const { viteConfig } = config;
52+
if (!viteConfig) {
53+
throw new Error("'viteConfig' option must be a vite config object.");
54+
}
4755

48-
const defaultExtensions = [".mjs", ".js", ".ts", ".jsx", ".tsx", ".json"];
49-
const { alias, extensions = defaultExtensions } = viteConfig.resolve ?? {};
56+
const defaultExtensions = [".mjs", ".js", ".ts", ".jsx", ".tsx", ".json"];
57+
const { alias, extensions = defaultExtensions } = viteConfig.resolve ?? {};
58+
const resolveOptions = { basedir: path.dirname(file), extensions };
5059

51-
let actualSource = path.normalize(source);
60+
// try to resolve the source as is
61+
try {
62+
return resolveSync(source, resolveOptions, "as is");
63+
}
64+
catch {}
5265

53-
// parse and replace alias
54-
if (alias) {
55-
const pathParts = actualSource.split(path.sep);
56-
if (Array.isArray(alias)) {
57-
for (let i = 0; i < pathParts.length; i++) {
58-
alias.forEach(({find, replacement}) => {
59-
if (pathParts[i] === find) {
60-
pathParts[i] = replacement;
61-
}
62-
});
63-
}
64-
}
65-
else if (typeof alias === "object") {
66-
for (let i = 0; i < pathParts.length; i++) {
67-
if (alias.hasOwnProperty(pathParts[i])) {
68-
pathParts[i] = alias[pathParts[i]];
69-
}
70-
}
71-
}
72-
else {
73-
throw new Error("The alias must be either an object, or an array of objects.");
74-
}
75-
actualSource = pathParts.join(path.sep);
66+
// try to resolve the source with alias
67+
const parsedSource = processAlias(alias, source);
68+
if (parsedSource !== source) {
69+
try {
70+
return resolveSync(parsedSource, resolveOptions, "with alias");
7671
}
72+
catch {}
73+
}
7774

78-
// resolve module
79-
let resolvedPath = "";
75+
// try to resolve the source if it is an absolute path
76+
if (path.isAbsolute(parsedSource)) {
77+
const root = viteConfig.root ?? process.cwd();
78+
const absoluteSource = path.join(path.resolve(root), parsedSource);
8079
try {
81-
resolvedPath = resolve.sync(actualSource, {
82-
basedir: path.dirname(file),
83-
extensions,
84-
});
85-
}
86-
catch (err) {
87-
if (viteConfig.publicDir !== false) {
88-
const publicDir = viteConfig.publicDir ?? "public";
89-
const publicActualSource = path.join(path.resolve(publicDir), actualSource);
90-
resolvedPath = resolve.sync(publicActualSource, {
91-
basedir: path.dirname(file),
92-
extensions,
93-
});
94-
}
95-
else {
96-
throw new Error("source cannot be resolved in actual path nor in 'Public' path.");
97-
}
80+
return resolveSync(absoluteSource, resolveOptions, "absolute path");
9881
}
99-
100-
log("resolved to:", resolvedPath);
101-
return { found: true, path: resolvedPath };
82+
catch {}
10283
}
103-
catch (err) {
104-
logError(err.message);
105-
return { found: false };
84+
85+
// try to resolve the source in public directory if all above failed
86+
if (viteConfig.publicDir !== false) {
87+
const publicDir = viteConfig.publicDir ?? "public";
88+
const publicSource = path.join(path.resolve(publicDir), parsedSource);
89+
try {
90+
return resolveSync(publicSource, resolveOptions, "in public directory");
91+
}
92+
catch {}
10693
}
94+
95+
log("ERROR:\t", "Unable to resolve");
96+
return { found: false };
10797
};

0 commit comments

Comments
 (0)