Skip to content

Commit f4ca4b5

Browse files
authored
refactor: migrate all remaining rules (#51)
1 parent de896f4 commit f4ca4b5

File tree

70 files changed

+2633
-2000
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+2633
-2000
lines changed

.changeset/blue-dolls-thank.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"eslint-plugin-import-x": patch
3+
---
4+
5+
refactor: migrate all remaining rules

.eslintrc.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,5 +77,11 @@ module.exports = {
7777
'import-x/default': 0,
7878
},
7979
},
80+
{
81+
files: 'global.d.ts',
82+
rules: {
83+
'import-x/no-extraneous-dependencies': 0,
84+
},
85+
},
8086
],
8187
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
"@changesets/cli": "^2.27.1",
7474
"@eslint/import-test-order-redirect-scoped": "link:./test/fixtures/order-redirect-scoped",
7575
"@test-scope/some-module": "link:./test/fixtures/symlinked-module",
76+
"@total-typescript/ts-reset": "^0.5.1",
7677
"@types/debug": "^4.1.12",
7778
"@types/doctrine": "^0.0.9",
7879
"@types/eslint": "^8.56.5",

src/core/import-type.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,5 @@ function typeTest(name: string, context: RuleContext, path?: string | null) {
177177
export function importType(name: string, context: RuleContext) {
178178
return typeTest(name, context, resolve(name, context))
179179
}
180+
181+
export type ImportType = ReturnType<typeof importType>

src/docs-url.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
2-
// @ts-ignore - We're using commonjs
2+
// @ts-ignore - The structures of `lib` and `src` are same
33
import pkg from '../package.json'
44

55
const repoUrl = 'https://github.com/un-es/eslint-plugin-import-x'

src/global.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import '@total-typescript/ts-reset'

src/index.ts

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,30 @@ import noNamedAsDefault from './rules/no-named-as-default'
2424
import noNamedAsDefaultMember from './rules/no-named-as-default-member'
2525
import noAnonymousDefaultExport from './rules/no-anonymous-default-export'
2626
import noUnusedModules from './rules/no-unused-modules'
27+
import noCommonjs from './rules/no-commonjs'
28+
import noAmd from './rules/no-amd'
29+
import noDuplicates from './rules/no-duplicates'
30+
import first from './rules/first'
31+
import maxDependencies from './rules/max-dependencies'
32+
import noExtraneousDependencies from './rules/no-extraneous-dependencies'
33+
import noAbsolutePath from './rules/no-absolute-path'
34+
import noNodejsModules from './rules/no-nodejs-modules'
35+
import noWebpackLoaderSyntax from './rules/no-webpack-loader-syntax'
36+
import order from './rules/order'
37+
import newlineAfterImport from './rules/newline-after-import'
38+
import preferDefaultExport from './rules/prefer-default-export'
39+
import noDefaultExport from './rules/no-default-export'
40+
import noNamedExport from './rules/no-named-export'
41+
import noDynamicRequire from './rules/no-dynamic-require'
42+
import unambiguous from './rules/unambiguous'
43+
import noUnassignedImport from './rules/no-unassigned-import'
44+
import noUselessPathSegments from './rules/no-useless-path-segments'
45+
import dynamicImportChunkname from './rules/dynamic-import-chunkname'
46+
import noImportModuleExports from './rules/no-import-module-exports'
47+
import noEmptyNamedBlocks from './rules/no-empty-named-blocks'
48+
import exportsLast from './rules/exports-last'
49+
import noDeprecated from './rules/no-deprecated'
50+
import importsFirst from './rules/imports-first'
2751

2852
// configs
2953
import recommended from './config/recommended'
@@ -59,36 +83,36 @@ export const rules = {
5983
'no-anonymous-default-export': noAnonymousDefaultExport,
6084
'no-unused-modules': noUnusedModules,
6185

62-
'no-commonjs': require('./rules/no-commonjs'),
63-
'no-amd': require('./rules/no-amd'),
64-
'no-duplicates': require('./rules/no-duplicates'),
65-
first: require('./rules/first'),
66-
'max-dependencies': require('./rules/max-dependencies'),
67-
'no-extraneous-dependencies': require('./rules/no-extraneous-dependencies'),
68-
'no-absolute-path': require('./rules/no-absolute-path'),
69-
'no-nodejs-modules': require('./rules/no-nodejs-modules'),
70-
'no-webpack-loader-syntax': require('./rules/no-webpack-loader-syntax'),
71-
order: require('./rules/order'),
72-
'newline-after-import': require('./rules/newline-after-import'),
73-
'prefer-default-export': require('./rules/prefer-default-export'),
74-
'no-default-export': require('./rules/no-default-export'),
75-
'no-named-export': require('./rules/no-named-export'),
76-
'no-dynamic-require': require('./rules/no-dynamic-require'),
77-
unambiguous: require('./rules/unambiguous'),
78-
'no-unassigned-import': require('./rules/no-unassigned-import'),
79-
'no-useless-path-segments': require('./rules/no-useless-path-segments'),
80-
'dynamic-import-chunkname': require('./rules/dynamic-import-chunkname'),
81-
'no-import-module-exports': require('./rules/no-import-module-exports'),
82-
'no-empty-named-blocks': require('./rules/no-empty-named-blocks'),
86+
'no-commonjs': noCommonjs,
87+
'no-amd': noAmd,
88+
'no-duplicates': noDuplicates,
89+
first,
90+
'max-dependencies': maxDependencies,
91+
'no-extraneous-dependencies': noExtraneousDependencies,
92+
'no-absolute-path': noAbsolutePath,
93+
'no-nodejs-modules': noNodejsModules,
94+
'no-webpack-loader-syntax': noWebpackLoaderSyntax,
95+
order,
96+
'newline-after-import': newlineAfterImport,
97+
'prefer-default-export': preferDefaultExport,
98+
'no-default-export': noDefaultExport,
99+
'no-named-export': noNamedExport,
100+
'no-dynamic-require': noDynamicRequire,
101+
unambiguous,
102+
'no-unassigned-import': noUnassignedImport,
103+
'no-useless-path-segments': noUselessPathSegments,
104+
'dynamic-import-chunkname': dynamicImportChunkname,
105+
'no-import-module-exports': noImportModuleExports,
106+
'no-empty-named-blocks': noEmptyNamedBlocks,
83107

84108
// export
85-
'exports-last': require('./rules/exports-last'),
109+
'exports-last': exportsLast,
86110

87111
// metadata-based
88-
'no-deprecated': require('./rules/no-deprecated'),
112+
'no-deprecated': noDeprecated,
89113

90114
// deprecated aliases to rules
91-
'imports-first': require('./rules/imports-first'),
115+
'imports-first': importsFirst,
92116
} satisfies Record<string, TSESLint.RuleModule<string, readonly unknown[]>>
93117

94118
export const configs = {

src/rules/dynamic-import-chunkname.js renamed to src/rules/dynamic-import-chunkname.ts

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,29 @@
11
import vm from 'vm'
2-
import { docsUrl } from '../docs-url'
32

4-
module.exports = {
3+
import { createRule } from '../utils'
4+
import { TSESTree } from '@typescript-eslint/utils'
5+
6+
type Options = {
7+
allowEmpty?: boolean
8+
importFunctions?: readonly string[]
9+
webpackChunknameFormat?: string
10+
}
11+
12+
type MessageId =
13+
| 'leadingComment'
14+
| 'blockComment'
15+
| 'paddedSpaces'
16+
| 'webpackComment'
17+
| 'chunknameFormat'
18+
19+
export = createRule<[Options?], MessageId>({
20+
name: 'dynamic-import-chunkname',
521
meta: {
622
type: 'suggestion',
723
docs: {
824
category: 'Style guide',
925
description:
1026
'Enforce a leading comment with the webpackChunkName for dynamic imports.',
11-
url: docsUrl('dynamic-import-chunkname'),
1227
},
1328
schema: [
1429
{
@@ -30,32 +45,41 @@ module.exports = {
3045
},
3146
},
3247
],
48+
messages: {
49+
leadingComment:
50+
'dynamic imports require a leading comment with the webpack chunkname',
51+
blockComment:
52+
'dynamic imports require a /* foo */ style comment, not a // foo comment',
53+
paddedSpaces:
54+
'dynamic imports require a block comment padded with spaces - /* foo */',
55+
webpackComment:
56+
'dynamic imports require a "webpack" comment with valid syntax',
57+
chunknameFormat:
58+
'dynamic imports require a leading comment in the form /*{{format}}*/',
59+
},
3360
},
34-
61+
defaultOptions: [],
3562
create(context) {
36-
const config = context.options[0]
37-
const { importFunctions = [], allowEmpty = false } = config || {}
3863
const {
64+
importFunctions = [],
65+
allowEmpty = false,
3966
webpackChunknameFormat = '([0-9a-zA-Z-_/.]|\\[(request|index)\\])+',
40-
} = config || {}
67+
} = context.options[0] || {}
4168

4269
const paddedCommentRegex = /^ (\S[\s\S]+\S) $/
4370
const commentStyleRegex =
4471
/^( ((webpackChunkName: .+)|((webpackPrefetch|webpackPreload): (true|false|-?[0-9]+))|(webpackIgnore: (true|false))|((webpackInclude|webpackExclude): \/.*\/)|(webpackMode: ["'](lazy|lazy-once|eager|weak)["'])|(webpackExports: (['"]\w+['"]|\[(['"]\w+['"], *)+(['"]\w+['"]*)\]))),?)+ $/
4572
const chunkSubstrFormat = ` webpackChunkName: ["']${webpackChunknameFormat}["'],? `
4673
const chunkSubstrRegex = new RegExp(chunkSubstrFormat)
4774

48-
function run(node, arg) {
75+
function run(node: TSESTree.Node, arg: TSESTree.Node) {
4976
const sourceCode = context.getSourceCode()
50-
const leadingComments = sourceCode.getCommentsBefore
51-
? sourceCode.getCommentsBefore(arg) // This method is available in ESLint >= 4.
52-
: sourceCode.getComments(arg).leading // This method is deprecated in ESLint 7.
77+
const leadingComments = sourceCode.getCommentsBefore(arg)
5378

5479
if ((!leadingComments || leadingComments.length === 0) && !allowEmpty) {
5580
context.report({
5681
node,
57-
message:
58-
'dynamic imports require a leading comment with the webpack chunkname',
82+
messageId: 'leadingComment',
5983
})
6084
return
6185
}
@@ -66,16 +90,15 @@ module.exports = {
6690
if (comment.type !== 'Block') {
6791
context.report({
6892
node,
69-
message:
70-
'dynamic imports require a /* foo */ style comment, not a // foo comment',
93+
messageId: 'blockComment',
7194
})
7295
return
7396
}
7497

7598
if (!paddedCommentRegex.test(comment.value)) {
7699
context.report({
77100
node,
78-
message: `dynamic imports require a block comment padded with spaces - /* foo */`,
101+
messageId: 'paddedSpaces',
79102
})
80103
return
81104
}
@@ -86,15 +109,15 @@ module.exports = {
86109
} catch (error) {
87110
context.report({
88111
node,
89-
message: `dynamic imports require a "webpack" comment with valid syntax`,
112+
messageId: 'webpackComment',
90113
})
91114
return
92115
}
93116

94117
if (!commentStyleRegex.test(comment.value)) {
95118
context.report({
96119
node,
97-
message: `dynamic imports require a "webpack" comment with valid syntax`,
120+
messageId: 'webpackComment',
98121
})
99122
return
100123
}
@@ -107,7 +130,10 @@ module.exports = {
107130
if (!isChunknamePresent && !allowEmpty) {
108131
context.report({
109132
node,
110-
message: `dynamic imports require a leading comment in the form /*${chunkSubstrFormat}*/`,
133+
messageId: 'chunknameFormat',
134+
data: {
135+
format: chunkSubstrFormat,
136+
},
111137
})
112138
}
113139
}
@@ -119,7 +145,9 @@ module.exports = {
119145

120146
CallExpression(node) {
121147
if (
148+
// @ts-expect-error - legacy parser type
122149
node.callee.type !== 'Import' &&
150+
'name' in node.callee &&
123151
importFunctions.indexOf(node.callee.name) < 0
124152
) {
125153
return
@@ -129,4 +157,4 @@ module.exports = {
129157
},
130158
}
131159
},
132-
}
160+
})
Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,29 @@
1-
import { docsUrl } from '../docs-url'
1+
import type { TSESTree } from '@typescript-eslint/utils'
22

3-
function isNonExportStatement({ type }) {
3+
import { createRule } from '../utils'
4+
5+
function isNonExportStatement({ type }: TSESTree.Node) {
46
return (
57
type !== 'ExportDefaultDeclaration' &&
68
type !== 'ExportNamedDeclaration' &&
79
type !== 'ExportAllDeclaration'
810
)
911
}
1012

11-
module.exports = {
13+
export = createRule({
14+
name: 'exports-last',
1215
meta: {
1316
type: 'suggestion',
1417
docs: {
1518
category: 'Style guide',
1619
description: 'Ensure all exports appear after other statements.',
17-
url: docsUrl('exports-last'),
1820
},
1921
schema: [],
22+
messages: {
23+
end: 'Export statements should appear at the end of the file',
24+
},
2025
},
21-
26+
defaultOptions: [],
2227
create(context) {
2328
return {
2429
Program({ body }) {
@@ -30,13 +35,12 @@ module.exports = {
3035
if (!isNonExportStatement(node)) {
3136
context.report({
3237
node,
33-
message:
34-
'Export statements should appear at the end of the file',
38+
messageId: 'end',
3539
})
3640
}
3741
})
3842
}
3943
},
4044
}
4145
},
42-
}
46+
})

0 commit comments

Comments
 (0)