eslint-plugin-esm 0.3.0 → 0.4.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/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # eslint-plugin-esm
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 85cd2d5: refactor(eslint-plugin-esm): rename rule `nearest-relative-path` to `no-useless-path-segments`
8
+
9
+ ### Patch Changes
10
+
11
+ - 36c4c6b: fix(eslint-plugin-esm): report on `./..` and `./`
12
+
3
13
  ## 0.3.0
4
14
 
5
15
  ### Minor Changes
package/dist/index.js CHANGED
@@ -1,4 +1,3 @@
1
- import { nearestRelativePath } from "./rules/nearest-relative-path.js";
2
1
  import { noDirectoryImports } from "./rules/no-directory-imports.js";
3
2
  import { noDynamicImports } from "./rules/no-dynamic-imports.js";
4
3
  import { noEmptyExports } from "./rules/no-empty-exports.js";
@@ -9,9 +8,9 @@ import { noRenameExports } from "./rules/no-rename-exports.js";
9
8
  import { noRenameImports } from "./rules/no-rename-imports.js";
10
9
  import { noSideEffectImports } from "./rules/no-side-effect-imports.js";
11
10
  import { noTsFileImports } from "./rules/no-ts-file-imports.js";
11
+ import { noUselessPathSegments } from "./rules/no-useless-path-segments.js";
12
12
  import { requiredExports } from "./rules/required-exports.js";
13
13
  export const rules = {
14
- [nearestRelativePath.name]: nearestRelativePath.rule,
15
14
  [noDirectoryImports.name]: noDirectoryImports.rule,
16
15
  [noDynamicImports.name]: noDynamicImports.rule,
17
16
  [noEmptyExports.name]: noEmptyExports.rule,
@@ -22,6 +21,7 @@ export const rules = {
22
21
  [noRenameImports.name]: noRenameImports.rule,
23
22
  [noSideEffectImports.name]: noSideEffectImports.rule,
24
23
  [noTsFileImports.name]: noTsFileImports.rule,
24
+ [noUselessPathSegments.name]: noUselessPathSegments.rule,
25
25
  [requiredExports.name]: requiredExports.rule,
26
26
  };
27
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDdkUsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDckUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDakUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQzdELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBQ3hFLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBQ3hFLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLHVDQUF1QyxDQUFDO0FBQ2hGLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUMvRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDL0QsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFDeEUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQ2hFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUU5RCxNQUFNLENBQUMsTUFBTSxLQUFLLEdBQUc7SUFDbkIsQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsRUFBRSxtQkFBbUIsQ0FBQyxJQUFJO0lBQ3BELENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLEVBQUUsa0JBQWtCLENBQUMsSUFBSTtJQUNsRCxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxFQUFFLGdCQUFnQixDQUFDLElBQUk7SUFDOUMsQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLEVBQUUsY0FBYyxDQUFDLElBQUk7SUFDMUMsQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsRUFBRSxtQkFBbUIsQ0FBQyxJQUFJO0lBQ3BELENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLEVBQUUsbUJBQW1CLENBQUMsSUFBSTtJQUNwRCxDQUFDLHVCQUF1QixDQUFDLElBQUksQ0FBQyxFQUFFLHVCQUF1QixDQUFDLElBQUk7SUFDNUQsQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLEVBQUUsZUFBZSxDQUFDLElBQUk7SUFDNUMsQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLEVBQUUsZUFBZSxDQUFDLElBQUk7SUFDNUMsQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsRUFBRSxtQkFBbUIsQ0FBQyxJQUFJO0lBQ3BELENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxFQUFFLGVBQWUsQ0FBQyxJQUFJO0lBQzVDLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxFQUFFLGVBQWUsQ0FBQyxJQUFJO0NBQzdDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBuZWFyZXN0UmVsYXRpdmVQYXRoIH0gZnJvbSBcIi4vcnVsZXMvbmVhcmVzdC1yZWxhdGl2ZS1wYXRoLmpzXCI7XG5pbXBvcnQgeyBub0RpcmVjdG9yeUltcG9ydHMgfSBmcm9tIFwiLi9ydWxlcy9uby1kaXJlY3RvcnktaW1wb3J0cy5qc1wiO1xuaW1wb3J0IHsgbm9EeW5hbWljSW1wb3J0cyB9IGZyb20gXCIuL3J1bGVzL25vLWR5bmFtaWMtaW1wb3J0cy5qc1wiO1xuaW1wb3J0IHsgbm9FbXB0eUV4cG9ydHMgfSBmcm9tIFwiLi9ydWxlcy9uby1lbXB0eS1leHBvcnRzLmpzXCI7XG5pbXBvcnQgeyBub0dpdElnbm9yZWRJbXBvcnRzIH0gZnJvbSBcIi4vcnVsZXMvbm8tZ2l0LWlnbm9yZWQtaW1wb3J0cy5qc1wiO1xuaW1wb3J0IHsgbm9QaGFudG9tRGVwSW1wb3J0cyB9IGZyb20gXCIuL3J1bGVzL25vLXBoYW50b20tZGVwLWltcG9ydHMuanNcIjtcbmltcG9ydCB7IG5vUmVsYXRpdmVQYXJlbnRJbXBvcnRzIH0gZnJvbSBcIi4vcnVsZXMvbm8tcmVsYXRpdmUtcGFyZW50LWltcG9ydHMuanNcIjtcbmltcG9ydCB7IG5vUmVuYW1lRXhwb3J0cyB9IGZyb20gXCIuL3J1bGVzL25vLXJlbmFtZS1leHBvcnRzLmpzXCI7XG5pbXBvcnQgeyBub1JlbmFtZUltcG9ydHMgfSBmcm9tIFwiLi9ydWxlcy9uby1yZW5hbWUtaW1wb3J0cy5qc1wiO1xuaW1wb3J0IHsgbm9TaWRlRWZmZWN0SW1wb3J0cyB9IGZyb20gXCIuL3J1bGVzL25vLXNpZGUtZWZmZWN0LWltcG9ydHMuanNcIjtcbmltcG9ydCB7IG5vVHNGaWxlSW1wb3J0cyB9IGZyb20gXCIuL3J1bGVzL25vLXRzLWZpbGUtaW1wb3J0cy5qc1wiO1xuaW1wb3J0IHsgcmVxdWlyZWRFeHBvcnRzIH0gZnJvbSBcIi4vcnVsZXMvcmVxdWlyZWQtZXhwb3J0cy5qc1wiO1xuXG5leHBvcnQgY29uc3QgcnVsZXMgPSB7XG4gIFtuZWFyZXN0UmVsYXRpdmVQYXRoLm5hbWVdOiBuZWFyZXN0UmVsYXRpdmVQYXRoLnJ1bGUsXG4gIFtub0RpcmVjdG9yeUltcG9ydHMubmFtZV06IG5vRGlyZWN0b3J5SW1wb3J0cy5ydWxlLFxuICBbbm9EeW5hbWljSW1wb3J0cy5uYW1lXTogbm9EeW5hbWljSW1wb3J0cy5ydWxlLFxuICBbbm9FbXB0eUV4cG9ydHMubmFtZV06IG5vRW1wdHlFeHBvcnRzLnJ1bGUsXG4gIFtub0dpdElnbm9yZWRJbXBvcnRzLm5hbWVdOiBub0dpdElnbm9yZWRJbXBvcnRzLnJ1bGUsXG4gIFtub1BoYW50b21EZXBJbXBvcnRzLm5hbWVdOiBub1BoYW50b21EZXBJbXBvcnRzLnJ1bGUsXG4gIFtub1JlbGF0aXZlUGFyZW50SW1wb3J0cy5uYW1lXTogbm9SZWxhdGl2ZVBhcmVudEltcG9ydHMucnVsZSxcbiAgW25vUmVuYW1lRXhwb3J0cy5uYW1lXTogbm9SZW5hbWVFeHBvcnRzLnJ1bGUsXG4gIFtub1JlbmFtZUltcG9ydHMubmFtZV06IG5vUmVuYW1lSW1wb3J0cy5ydWxlLFxuICBbbm9TaWRlRWZmZWN0SW1wb3J0cy5uYW1lXTogbm9TaWRlRWZmZWN0SW1wb3J0cy5ydWxlLFxuICBbbm9Uc0ZpbGVJbXBvcnRzLm5hbWVdOiBub1RzRmlsZUltcG9ydHMucnVsZSxcbiAgW3JlcXVpcmVkRXhwb3J0cy5uYW1lXTogcmVxdWlyZWRFeHBvcnRzLnJ1bGUsXG59O1xuIl19
27
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDckUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDakUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQzdELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBQ3hFLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLG1DQUFtQyxDQUFDO0FBQ3hFLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLHVDQUF1QyxDQUFDO0FBQ2hGLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUMvRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDL0QsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFDeEUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQ2hFLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLHFDQUFxQyxDQUFDO0FBQzVFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUU5RCxNQUFNLENBQUMsTUFBTSxLQUFLLEdBQUc7SUFDbkIsQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsRUFBRSxrQkFBa0IsQ0FBQyxJQUFJO0lBQ2xELENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLEVBQUUsZ0JBQWdCLENBQUMsSUFBSTtJQUM5QyxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsRUFBRSxjQUFjLENBQUMsSUFBSTtJQUMxQyxDQUFDLG1CQUFtQixDQUFDLElBQUksQ0FBQyxFQUFFLG1CQUFtQixDQUFDLElBQUk7SUFDcEQsQ0FBQyxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsRUFBRSxtQkFBbUIsQ0FBQyxJQUFJO0lBQ3BELENBQUMsdUJBQXVCLENBQUMsSUFBSSxDQUFDLEVBQUUsdUJBQXVCLENBQUMsSUFBSTtJQUM1RCxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsRUFBRSxlQUFlLENBQUMsSUFBSTtJQUM1QyxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsRUFBRSxlQUFlLENBQUMsSUFBSTtJQUM1QyxDQUFDLG1CQUFtQixDQUFDLElBQUksQ0FBQyxFQUFFLG1CQUFtQixDQUFDLElBQUk7SUFDcEQsQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLEVBQUUsZUFBZSxDQUFDLElBQUk7SUFDNUMsQ0FBQyxxQkFBcUIsQ0FBQyxJQUFJLENBQUMsRUFBRSxxQkFBcUIsQ0FBQyxJQUFJO0lBQ3hELENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxFQUFFLGVBQWUsQ0FBQyxJQUFJO0NBQzdDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBub0RpcmVjdG9yeUltcG9ydHMgfSBmcm9tIFwiLi9ydWxlcy9uby1kaXJlY3RvcnktaW1wb3J0cy5qc1wiO1xuaW1wb3J0IHsgbm9EeW5hbWljSW1wb3J0cyB9IGZyb20gXCIuL3J1bGVzL25vLWR5bmFtaWMtaW1wb3J0cy5qc1wiO1xuaW1wb3J0IHsgbm9FbXB0eUV4cG9ydHMgfSBmcm9tIFwiLi9ydWxlcy9uby1lbXB0eS1leHBvcnRzLmpzXCI7XG5pbXBvcnQgeyBub0dpdElnbm9yZWRJbXBvcnRzIH0gZnJvbSBcIi4vcnVsZXMvbm8tZ2l0LWlnbm9yZWQtaW1wb3J0cy5qc1wiO1xuaW1wb3J0IHsgbm9QaGFudG9tRGVwSW1wb3J0cyB9IGZyb20gXCIuL3J1bGVzL25vLXBoYW50b20tZGVwLWltcG9ydHMuanNcIjtcbmltcG9ydCB7IG5vUmVsYXRpdmVQYXJlbnRJbXBvcnRzIH0gZnJvbSBcIi4vcnVsZXMvbm8tcmVsYXRpdmUtcGFyZW50LWltcG9ydHMuanNcIjtcbmltcG9ydCB7IG5vUmVuYW1lRXhwb3J0cyB9IGZyb20gXCIuL3J1bGVzL25vLXJlbmFtZS1leHBvcnRzLmpzXCI7XG5pbXBvcnQgeyBub1JlbmFtZUltcG9ydHMgfSBmcm9tIFwiLi9ydWxlcy9uby1yZW5hbWUtaW1wb3J0cy5qc1wiO1xuaW1wb3J0IHsgbm9TaWRlRWZmZWN0SW1wb3J0cyB9IGZyb20gXCIuL3J1bGVzL25vLXNpZGUtZWZmZWN0LWltcG9ydHMuanNcIjtcbmltcG9ydCB7IG5vVHNGaWxlSW1wb3J0cyB9IGZyb20gXCIuL3J1bGVzL25vLXRzLWZpbGUtaW1wb3J0cy5qc1wiO1xuaW1wb3J0IHsgbm9Vc2VsZXNzUGF0aFNlZ21lbnRzIH0gZnJvbSBcIi4vcnVsZXMvbm8tdXNlbGVzcy1wYXRoLXNlZ21lbnRzLmpzXCI7XG5pbXBvcnQgeyByZXF1aXJlZEV4cG9ydHMgfSBmcm9tIFwiLi9ydWxlcy9yZXF1aXJlZC1leHBvcnRzLmpzXCI7XG5cbmV4cG9ydCBjb25zdCBydWxlcyA9IHtcbiAgW25vRGlyZWN0b3J5SW1wb3J0cy5uYW1lXTogbm9EaXJlY3RvcnlJbXBvcnRzLnJ1bGUsXG4gIFtub0R5bmFtaWNJbXBvcnRzLm5hbWVdOiBub0R5bmFtaWNJbXBvcnRzLnJ1bGUsXG4gIFtub0VtcHR5RXhwb3J0cy5uYW1lXTogbm9FbXB0eUV4cG9ydHMucnVsZSxcbiAgW25vR2l0SWdub3JlZEltcG9ydHMubmFtZV06IG5vR2l0SWdub3JlZEltcG9ydHMucnVsZSxcbiAgW25vUGhhbnRvbURlcEltcG9ydHMubmFtZV06IG5vUGhhbnRvbURlcEltcG9ydHMucnVsZSxcbiAgW25vUmVsYXRpdmVQYXJlbnRJbXBvcnRzLm5hbWVdOiBub1JlbGF0aXZlUGFyZW50SW1wb3J0cy5ydWxlLFxuICBbbm9SZW5hbWVFeHBvcnRzLm5hbWVdOiBub1JlbmFtZUV4cG9ydHMucnVsZSxcbiAgW25vUmVuYW1lSW1wb3J0cy5uYW1lXTogbm9SZW5hbWVJbXBvcnRzLnJ1bGUsXG4gIFtub1NpZGVFZmZlY3RJbXBvcnRzLm5hbWVdOiBub1NpZGVFZmZlY3RJbXBvcnRzLnJ1bGUsXG4gIFtub1RzRmlsZUltcG9ydHMubmFtZV06IG5vVHNGaWxlSW1wb3J0cy5ydWxlLFxuICBbbm9Vc2VsZXNzUGF0aFNlZ21lbnRzLm5hbWVdOiBub1VzZWxlc3NQYXRoU2VnbWVudHMucnVsZSxcbiAgW3JlcXVpcmVkRXhwb3J0cy5uYW1lXTogcmVxdWlyZWRFeHBvcnRzLnJ1bGUsXG59O1xuIl19
@@ -0,0 +1,5 @@
1
+ export declare const noUselessPathSegments: {
2
+ name: string;
3
+ rule: import("eslint").Rule.RuleModule;
4
+ };
5
+ //# sourceMappingURL=no-useless-path-segments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-useless-path-segments.d.ts","sourceRoot":"","sources":["../../src/rules/no-useless-path-segments.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,qBAAqB;;;CAIhC,CAAC"}
@@ -0,0 +1,28 @@
1
+ import path from "node:path";
2
+ import { create, createRule, getRuleName, getSourceType } from "../common.js";
3
+ export const noUselessPathSegments = createRule({
4
+ name: getRuleName(import.meta.url),
5
+ message: "The relative source path should be a nearest relative path.",
6
+ create: (context) => create(context, check),
7
+ });
8
+ function check(filename, source) {
9
+ if (getSourceType(source) !== "local" ||
10
+ source.startsWith("/") ||
11
+ source === ".") {
12
+ return false;
13
+ }
14
+ if (source.endsWith("/")) {
15
+ return true;
16
+ }
17
+ const currentPath = path.dirname(filename);
18
+ const absoluteSource = path.resolve(currentPath, source);
19
+ // compatible with windows
20
+ let resultPath = path
21
+ .relative(currentPath, absoluteSource)
22
+ .replaceAll("\\", "/");
23
+ if (!resultPath.startsWith("./") && !resultPath.startsWith("..")) {
24
+ resultPath = `./${resultPath}`;
25
+ }
26
+ return resultPath !== source;
27
+ }
28
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm8tdXNlbGVzcy1wYXRoLXNlZ21lbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bGVzL25vLXVzZWxlc3MtcGF0aC1zZWdtZW50cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLElBQUksTUFBTSxXQUFXLENBQUM7QUFDN0IsT0FBTyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsV0FBVyxFQUFFLGFBQWEsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUU5RSxNQUFNLENBQUMsTUFBTSxxQkFBcUIsR0FBRyxVQUFVLENBQUM7SUFDOUMsSUFBSSxFQUFFLFdBQVcsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQztJQUNsQyxPQUFPLEVBQUUsNkRBQTZEO0lBQ3RFLE1BQU0sRUFBRSxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxLQUFLLENBQUM7Q0FDNUMsQ0FBQyxDQUFDO0FBRUgsU0FBUyxLQUFLLENBQUMsUUFBZ0IsRUFBRSxNQUFjO0lBQzdDLElBQ0UsYUFBYSxDQUFDLE1BQU0sQ0FBQyxLQUFLLE9BQU87UUFDakMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUM7UUFDdEIsTUFBTSxLQUFLLEdBQUcsRUFDZCxDQUFDO1FBQ0QsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBQ0QsSUFBSSxNQUFNLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDekIsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBQ0QsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUMzQyxNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLFdBQVcsRUFBRSxNQUFNLENBQUMsQ0FBQztJQUN6RCwwQkFBMEI7SUFDMUIsSUFBSSxVQUFVLEdBQUcsSUFBSTtTQUNsQixRQUFRLENBQUMsV0FBVyxFQUFFLGNBQWMsQ0FBQztTQUNyQyxVQUFVLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDO0lBQ3pCLElBQUksQ0FBQyxVQUFVLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1FBQ2pFLFVBQVUsR0FBRyxLQUFLLFVBQVUsRUFBRSxDQUFDO0lBQ2pDLENBQUM7SUFDRCxPQUFPLFVBQVUsS0FBSyxNQUFNLENBQUM7QUFDL0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBwYXRoIGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7IGNyZWF0ZSwgY3JlYXRlUnVsZSwgZ2V0UnVsZU5hbWUsIGdldFNvdXJjZVR5cGUgfSBmcm9tIFwiLi4vY29tbW9uLmpzXCI7XG5cbmV4cG9ydCBjb25zdCBub1VzZWxlc3NQYXRoU2VnbWVudHMgPSBjcmVhdGVSdWxlKHtcbiAgbmFtZTogZ2V0UnVsZU5hbWUoaW1wb3J0Lm1ldGEudXJsKSxcbiAgbWVzc2FnZTogXCJUaGUgcmVsYXRpdmUgc291cmNlIHBhdGggc2hvdWxkIGJlIGEgbmVhcmVzdCByZWxhdGl2ZSBwYXRoLlwiLFxuICBjcmVhdGU6IChjb250ZXh0KSA9PiBjcmVhdGUoY29udGV4dCwgY2hlY2spLFxufSk7XG5cbmZ1bmN0aW9uIGNoZWNrKGZpbGVuYW1lOiBzdHJpbmcsIHNvdXJjZTogc3RyaW5nKSB7XG4gIGlmIChcbiAgICBnZXRTb3VyY2VUeXBlKHNvdXJjZSkgIT09IFwibG9jYWxcIiB8fFxuICAgIHNvdXJjZS5zdGFydHNXaXRoKFwiL1wiKSB8fFxuICAgIHNvdXJjZSA9PT0gXCIuXCJcbiAgKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIGlmIChzb3VyY2UuZW5kc1dpdGgoXCIvXCIpKSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbiAgY29uc3QgY3VycmVudFBhdGggPSBwYXRoLmRpcm5hbWUoZmlsZW5hbWUpO1xuICBjb25zdCBhYnNvbHV0ZVNvdXJjZSA9IHBhdGgucmVzb2x2ZShjdXJyZW50UGF0aCwgc291cmNlKTtcbiAgLy8gY29tcGF0aWJsZSB3aXRoIHdpbmRvd3NcbiAgbGV0IHJlc3VsdFBhdGggPSBwYXRoXG4gICAgLnJlbGF0aXZlKGN1cnJlbnRQYXRoLCBhYnNvbHV0ZVNvdXJjZSlcbiAgICAucmVwbGFjZUFsbChcIlxcXFxcIiwgXCIvXCIpO1xuICBpZiAoIXJlc3VsdFBhdGguc3RhcnRzV2l0aChcIi4vXCIpICYmICFyZXN1bHRQYXRoLnN0YXJ0c1dpdGgoXCIuLlwiKSkge1xuICAgIHJlc3VsdFBhdGggPSBgLi8ke3Jlc3VsdFBhdGh9YDtcbiAgfVxuICByZXR1cm4gcmVzdWx0UGF0aCAhPT0gc291cmNlO1xufVxuIl19
@@ -1,5 +1,5 @@
1
1
  <!-- prettier-ignore-start -->
2
- # nearest-relative-path
2
+ # no-useless-path-segments
3
3
 
4
4
  The relative source path should be a nearest relative path.
5
5
 
@@ -27,6 +27,10 @@ import "./../foo" // filename: /a/b/c/d/e.js
27
27
  import("./../foo") // filename: /a/b/c/d/e.js
28
28
  export * from "./../foo" // filename: /a/b/c/d/e.js
29
29
  export {a} from "./../foo" // filename: /a/b/c/d/e.js
30
+ import foo from "./" // filename: /a/b/c/d/e.js
31
+ import foo from '../' // filename: /a/b/c/d/e.js
32
+ import foo from '../../' // filename: /a/b/c/d/e.js
33
+ import foo from './..' // filename: /a/b/c/d/e.js
30
34
  ```
31
35
 
32
36
  ### Pass
@@ -44,5 +48,7 @@ export * from "./a" // filename: /a/b/c/d/e.js
44
48
  export {a} from "a" // filename: /a/b/c/d/e.js
45
49
  export {a} from "./a" // filename: /a/b/c/d/e.js
46
50
  import foo from "." // filename: /a/b/c/d/e.js
51
+ import foo from '..' // filename: /a/b/c/d/e.js
52
+ import foo from '../..' // filename: /a/b/c/d/e.js
47
53
  ```
48
54
  <!-- prettier-ignore-end -->
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-esm",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "ESLint plugin for linting ESM (import/export syntax)",
5
5
  "keywords": [
6
6
  "eslint",
@@ -29,7 +29,7 @@
29
29
  "@types/estree": "1.0.6",
30
30
  "@types/json-schema": "7.0.15",
31
31
  "@types/node": "22.9.1",
32
- "@typescript-eslint/parser": "8.18.1",
32
+ "@typescript-eslint/parser": "8.18.2",
33
33
  "eslint": "8.57.1",
34
34
  "outdent": "0.8.0",
35
35
  "tsx": "4.19.2"
package/src/index.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { nearestRelativePath } from "./rules/nearest-relative-path.js";
2
1
  import { noDirectoryImports } from "./rules/no-directory-imports.js";
3
2
  import { noDynamicImports } from "./rules/no-dynamic-imports.js";
4
3
  import { noEmptyExports } from "./rules/no-empty-exports.js";
@@ -9,10 +8,10 @@ import { noRenameExports } from "./rules/no-rename-exports.js";
9
8
  import { noRenameImports } from "./rules/no-rename-imports.js";
10
9
  import { noSideEffectImports } from "./rules/no-side-effect-imports.js";
11
10
  import { noTsFileImports } from "./rules/no-ts-file-imports.js";
11
+ import { noUselessPathSegments } from "./rules/no-useless-path-segments.js";
12
12
  import { requiredExports } from "./rules/required-exports.js";
13
13
 
14
14
  export const rules = {
15
- [nearestRelativePath.name]: nearestRelativePath.rule,
16
15
  [noDirectoryImports.name]: noDirectoryImports.rule,
17
16
  [noDynamicImports.name]: noDynamicImports.rule,
18
17
  [noEmptyExports.name]: noEmptyExports.rule,
@@ -23,5 +22,6 @@ export const rules = {
23
22
  [noRenameImports.name]: noRenameImports.rule,
24
23
  [noSideEffectImports.name]: noSideEffectImports.rule,
25
24
  [noTsFileImports.name]: noTsFileImports.rule,
25
+ [noUselessPathSegments.name]: noUselessPathSegments.rule,
26
26
  [requiredExports.name]: requiredExports.rule,
27
27
  };
@@ -1,5 +1,5 @@
1
1
  import { test } from "../test.spec.js";
2
- import { nearestRelativePath } from "./nearest-relative-path.js";
2
+ import { noUselessPathSegments } from "./no-useless-path-segments.js";
3
3
 
4
4
  const valid = [
5
5
  'import xxx from "../a"',
@@ -13,7 +13,10 @@ const valid = [
13
13
  'export * from "./a"',
14
14
  'export {a} from "a"',
15
15
  'export {a} from "./a"',
16
+
16
17
  'import foo from "."',
18
+ "import foo from '..'",
19
+ "import foo from '../..'",
17
20
  ].map((code) => ({ code, filename: "/a/b/c/d/e.js" }));
18
21
 
19
22
  const invalid = [
@@ -39,6 +42,11 @@ const invalid = [
39
42
  'import("./../foo")',
40
43
  'export * from "./../foo"',
41
44
  'export {a} from "./../foo"',
45
+
46
+ 'import foo from "./"',
47
+ "import foo from '../'",
48
+ "import foo from '../../'",
49
+ "import foo from './..'",
42
50
  ].map((code) => ({ code, filename: "/a/b/c/d/e.js" }));
43
51
 
44
- test({ valid, invalid, ...nearestRelativePath });
52
+ test({ valid, invalid, ...noUselessPathSegments });
@@ -1,7 +1,7 @@
1
1
  import path from "node:path";
2
2
  import { create, createRule, getRuleName, getSourceType } from "../common.js";
3
3
 
4
- export const nearestRelativePath = createRule({
4
+ export const noUselessPathSegments = createRule({
5
5
  name: getRuleName(import.meta.url),
6
6
  message: "The relative source path should be a nearest relative path.",
7
7
  create: (context) => create(context, check),
@@ -15,13 +15,16 @@ function check(filename: string, source: string) {
15
15
  ) {
16
16
  return false;
17
17
  }
18
+ if (source.endsWith("/")) {
19
+ return true;
20
+ }
18
21
  const currentPath = path.dirname(filename);
19
22
  const absoluteSource = path.resolve(currentPath, source);
20
23
  // compatible with windows
21
24
  let resultPath = path
22
25
  .relative(currentPath, absoluteSource)
23
26
  .replaceAll("\\", "/");
24
- if (!resultPath.startsWith("./") && !resultPath.startsWith("../")) {
27
+ if (!resultPath.startsWith("./") && !resultPath.startsWith("..")) {
25
28
  resultPath = `./${resultPath}`;
26
29
  }
27
30
  return resultPath !== source;
@@ -1,5 +0,0 @@
1
- export declare const nearestRelativePath: {
2
- name: string;
3
- rule: import("eslint").Rule.RuleModule;
4
- };
5
- //# sourceMappingURL=nearest-relative-path.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"nearest-relative-path.d.ts","sourceRoot":"","sources":["../../src/rules/nearest-relative-path.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,mBAAmB;;;CAI9B,CAAC"}
@@ -1,25 +0,0 @@
1
- import path from "node:path";
2
- import { create, createRule, getRuleName, getSourceType } from "../common.js";
3
- export const nearestRelativePath = createRule({
4
- name: getRuleName(import.meta.url),
5
- message: "The relative source path should be a nearest relative path.",
6
- create: (context) => create(context, check),
7
- });
8
- function check(filename, source) {
9
- if (getSourceType(source) !== "local" ||
10
- source.startsWith("/") ||
11
- source === ".") {
12
- return false;
13
- }
14
- const currentPath = path.dirname(filename);
15
- const absoluteSource = path.resolve(currentPath, source);
16
- // compatible with windows
17
- let resultPath = path
18
- .relative(currentPath, absoluteSource)
19
- .replaceAll("\\", "/");
20
- if (!resultPath.startsWith("./") && !resultPath.startsWith("../")) {
21
- resultPath = `./${resultPath}`;
22
- }
23
- return resultPath !== source;
24
- }
25
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmVhcmVzdC1yZWxhdGl2ZS1wYXRoLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bGVzL25lYXJlc3QtcmVsYXRpdmUtcGF0aC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLElBQUksTUFBTSxXQUFXLENBQUM7QUFDN0IsT0FBTyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsV0FBVyxFQUFFLGFBQWEsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUU5RSxNQUFNLENBQUMsTUFBTSxtQkFBbUIsR0FBRyxVQUFVLENBQUM7SUFDNUMsSUFBSSxFQUFFLFdBQVcsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQztJQUNsQyxPQUFPLEVBQUUsNkRBQTZEO0lBQ3RFLE1BQU0sRUFBRSxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxLQUFLLENBQUM7Q0FDNUMsQ0FBQyxDQUFDO0FBRUgsU0FBUyxLQUFLLENBQUMsUUFBZ0IsRUFBRSxNQUFjO0lBQzdDLElBQ0UsYUFBYSxDQUFDLE1BQU0sQ0FBQyxLQUFLLE9BQU87UUFDakMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUM7UUFDdEIsTUFBTSxLQUFLLEdBQUcsRUFDZCxDQUFDO1FBQ0QsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBQ0QsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUMzQyxNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLFdBQVcsRUFBRSxNQUFNLENBQUMsQ0FBQztJQUN6RCwwQkFBMEI7SUFDMUIsSUFBSSxVQUFVLEdBQUcsSUFBSTtTQUNsQixRQUFRLENBQUMsV0FBVyxFQUFFLGNBQWMsQ0FBQztTQUNyQyxVQUFVLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDO0lBQ3pCLElBQUksQ0FBQyxVQUFVLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ2xFLFVBQVUsR0FBRyxLQUFLLFVBQVUsRUFBRSxDQUFDO0lBQ2pDLENBQUM7SUFDRCxPQUFPLFVBQVUsS0FBSyxNQUFNLENBQUM7QUFDL0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBwYXRoIGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7IGNyZWF0ZSwgY3JlYXRlUnVsZSwgZ2V0UnVsZU5hbWUsIGdldFNvdXJjZVR5cGUgfSBmcm9tIFwiLi4vY29tbW9uLmpzXCI7XG5cbmV4cG9ydCBjb25zdCBuZWFyZXN0UmVsYXRpdmVQYXRoID0gY3JlYXRlUnVsZSh7XG4gIG5hbWU6IGdldFJ1bGVOYW1lKGltcG9ydC5tZXRhLnVybCksXG4gIG1lc3NhZ2U6IFwiVGhlIHJlbGF0aXZlIHNvdXJjZSBwYXRoIHNob3VsZCBiZSBhIG5lYXJlc3QgcmVsYXRpdmUgcGF0aC5cIixcbiAgY3JlYXRlOiAoY29udGV4dCkgPT4gY3JlYXRlKGNvbnRleHQsIGNoZWNrKSxcbn0pO1xuXG5mdW5jdGlvbiBjaGVjayhmaWxlbmFtZTogc3RyaW5nLCBzb3VyY2U6IHN0cmluZykge1xuICBpZiAoXG4gICAgZ2V0U291cmNlVHlwZShzb3VyY2UpICE9PSBcImxvY2FsXCIgfHxcbiAgICBzb3VyY2Uuc3RhcnRzV2l0aChcIi9cIikgfHxcbiAgICBzb3VyY2UgPT09IFwiLlwiXG4gICkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICBjb25zdCBjdXJyZW50UGF0aCA9IHBhdGguZGlybmFtZShmaWxlbmFtZSk7XG4gIGNvbnN0IGFic29sdXRlU291cmNlID0gcGF0aC5yZXNvbHZlKGN1cnJlbnRQYXRoLCBzb3VyY2UpO1xuICAvLyBjb21wYXRpYmxlIHdpdGggd2luZG93c1xuICBsZXQgcmVzdWx0UGF0aCA9IHBhdGhcbiAgICAucmVsYXRpdmUoY3VycmVudFBhdGgsIGFic29sdXRlU291cmNlKVxuICAgIC5yZXBsYWNlQWxsKFwiXFxcXFwiLCBcIi9cIik7XG4gIGlmICghcmVzdWx0UGF0aC5zdGFydHNXaXRoKFwiLi9cIikgJiYgIXJlc3VsdFBhdGguc3RhcnRzV2l0aChcIi4uL1wiKSkge1xuICAgIHJlc3VsdFBhdGggPSBgLi8ke3Jlc3VsdFBhdGh9YDtcbiAgfVxuICByZXR1cm4gcmVzdWx0UGF0aCAhPT0gc291cmNlO1xufVxuIl19