-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
94 lines (86 loc) · 2.88 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
const { basename } = require('path');
const eslintResolve = require('eslint-module-utils/resolve').default;
const resolveImportType = require('eslint-plugin-import/lib/core/importType').default;
const defaultIndexFiles = ['index.js', 'index.jsx', 'index.ts', 'index.tsx'];
const defaultIgnoredExtensions = ['.js', '.cjs', '.json', '.css', '.scss'];
/** Checks whether the extension at the end of the provided path is in the "ignored extensions" list */
function isExtensionIgnored(path, ignoredExtensions) {
const extension = path.substring(path.lastIndexOf('.'));
return ignoredExtensions.includes(extension);
}
/** Checks whether the folder import was resolved to one of the index files */
function resolvedDirToIndex(importPath, resolvedPath, indexFiles) {
try {
return indexFiles.includes(basename(resolvedPath))
&& basename(importPath) !== 'index'; // in case 'index' was resolved to e.g. 'index.js'
} catch (e) { return false; }
}
function rule(check) {
return {
meta: {
fixable: true,
},
create(context) {
function ruleInner(node) {
const source = node.source;
if (!source) return;
const importType = resolveImportType(source.value, context);
const value = source.value.replace(/\?.*$/, '');
const ignored = context.settings['esm-import']?.ignore ?? defaultIgnoredExtensions;
if (!value || importType === 'external' || isExtensionIgnored(value, ignored)) return;
check(context, node, eslintResolve(value, context));
}
return {
DeclareExportDeclaration: ruleInner,
DeclareExportAllDeclaration: ruleInner,
ExportAllDeclaration: ruleInner,
ExportNamedDeclaration: ruleInner,
ImportDeclaration: ruleInner,
};
},
};
}
const meta = {
name: 'eslint-plugin-esm-import',
version: '1.0.0',
engines: {
eslint: ">=9.0.0"
}
};
const configs = {
recommended: {
plugins: ['esm-import'],
rules: {
'esm-import/extensions': 'error',
},
},
};
const rules = {
'extensions': rule((context, node, path) => {
const value = node.source.value;
if (path) {
const indexFiles = context.settings['esm-import']?.index ?? defaultIndexFiles;
let message;
let fix;
if (resolvedDirToIndex(value, path, indexFiles)) {
message = 'Importing a directory requires /index.js';
fix = value.includes('?') ? undefined : (fixer) => fixer.replaceText(node.source, `'${value}/index.js'`);
} else {
message = 'Local imports and exports must end with .js';
// imports with query strings require manual fix for now
fix = value.includes('?') ? undefined : (fixer) => fixer.replaceText(node.source, `'${value}.js'`);
}
context.report({
node,
message,
fix,
});
}
}),
};
// Add default export combining all exports
module.exports = {
meta,
configs,
rules
};