Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: migrate all remaining rules #51

Merged
merged 26 commits into from
Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
737a0fe
refactor: migrate no-commonjs rule
JounQin Mar 15, 2024
76958dc
refactor: migrate no-amd rule
JounQin Mar 15, 2024
fc7a9fc
refactor: migrate no-duplicates rule
JounQin Mar 15, 2024
29984ad
refactor: migrate max-dependencies rule
JounQin Mar 15, 2024
b863d08
refactor: migrate no-extraneous-dependencies rule
JounQin Mar 15, 2024
3b5b13b
refactor: migrate no-absolute-path rule
JounQin Mar 15, 2024
afd156e
refactor: migrate no-nodejs-modules rule
JounQin Mar 15, 2024
2eff97a
refactor: migrate no-webpack-loader-syntax rule
JounQin Mar 15, 2024
f7fd61d
refactor: migrate order rule
JounQin Mar 18, 2024
c9f1d4b
refactor: migrate newline-after-import rule
JounQin Mar 18, 2024
fc7af71
refactor: migrate prefer-default-export rule
JounQin Mar 18, 2024
d10ff73
refactor: migrate no-default-export rule
JounQin Mar 18, 2024
df5934e
refactor: migrate no-named-export rule
JounQin Mar 18, 2024
6d74320
refactor: migrate no-dynamic-require rule
JounQin Mar 18, 2024
68b511f
refactor: migrate unambiguous rule
JounQin Mar 18, 2024
36189de
refactor: migrate no-unassigned-import rule
JounQin Mar 18, 2024
0d967aa
refactor: migrate no-useless-path-segments rule
JounQin Mar 18, 2024
8a48ffb
refactor: migrate dynamic-import-chunkname rule
JounQin Mar 18, 2024
7715219
refactor: migrate no-import-module-exports rule
JounQin Mar 18, 2024
6e190b8
refactor: migrate no-empty-named-blocks rule
JounQin Mar 18, 2024
5832e5e
refactor: migrate exports-last rule
JounQin Mar 18, 2024
0869d2c
refactor: migrate no-deprecated rule
JounQin Mar 18, 2024
ff7ec2a
refactor: migrate no-duplicates rule test cases
JounQin Mar 18, 2024
bb4c5a8
refactor: migrate first rule test cases
JounQin Mar 18, 2024
e333c5e
refactor: migrate imports-first rule
JounQin Mar 18, 2024
31d8668
Create blue-dolls-thank.md
JounQin Mar 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/blue-dolls-thank.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eslint-plugin-import-x": patch
---

refactor: migrate all remaining rules
6 changes: 6 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,11 @@ module.exports = {
'import-x/default': 0,
},
},
{
files: 'global.d.ts',
rules: {
'import-x/no-extraneous-dependencies': 0,
},
},
],
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
"@changesets/cli": "^2.27.1",
"@eslint/import-test-order-redirect-scoped": "link:./test/fixtures/order-redirect-scoped",
"@test-scope/some-module": "link:./test/fixtures/symlinked-module",
"@total-typescript/ts-reset": "^0.5.1",
"@types/debug": "^4.1.12",
"@types/doctrine": "^0.0.9",
"@types/eslint": "^8.56.5",
Expand Down
2 changes: 2 additions & 0 deletions src/core/import-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,5 @@ function typeTest(name: string, context: RuleContext, path?: string | null) {
export function importType(name: string, context: RuleContext) {
return typeTest(name, context, resolve(name, context))
}

export type ImportType = ReturnType<typeof importType>
2 changes: 1 addition & 1 deletion src/docs-url.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore - We're using commonjs
// @ts-ignore - The structures of `lib` and `src` are same
import pkg from '../package.json'

const repoUrl = 'https://github.com/un-es/eslint-plugin-import-x'
Expand Down
1 change: 1 addition & 0 deletions src/global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import '@total-typescript/ts-reset'
72 changes: 48 additions & 24 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,30 @@ import noNamedAsDefault from './rules/no-named-as-default'
import noNamedAsDefaultMember from './rules/no-named-as-default-member'
import noAnonymousDefaultExport from './rules/no-anonymous-default-export'
import noUnusedModules from './rules/no-unused-modules'
import noCommonjs from './rules/no-commonjs'
import noAmd from './rules/no-amd'
import noDuplicates from './rules/no-duplicates'
import first from './rules/first'
import maxDependencies from './rules/max-dependencies'
import noExtraneousDependencies from './rules/no-extraneous-dependencies'
import noAbsolutePath from './rules/no-absolute-path'
import noNodejsModules from './rules/no-nodejs-modules'
import noWebpackLoaderSyntax from './rules/no-webpack-loader-syntax'
import order from './rules/order'
import newlineAfterImport from './rules/newline-after-import'
import preferDefaultExport from './rules/prefer-default-export'
import noDefaultExport from './rules/no-default-export'
import noNamedExport from './rules/no-named-export'
import noDynamicRequire from './rules/no-dynamic-require'
import unambiguous from './rules/unambiguous'
import noUnassignedImport from './rules/no-unassigned-import'
import noUselessPathSegments from './rules/no-useless-path-segments'
import dynamicImportChunkname from './rules/dynamic-import-chunkname'
import noImportModuleExports from './rules/no-import-module-exports'
import noEmptyNamedBlocks from './rules/no-empty-named-blocks'
import exportsLast from './rules/exports-last'
import noDeprecated from './rules/no-deprecated'
import importsFirst from './rules/imports-first'

// configs
import recommended from './config/recommended'
Expand Down Expand Up @@ -59,36 +83,36 @@ export const rules = {
'no-anonymous-default-export': noAnonymousDefaultExport,
'no-unused-modules': noUnusedModules,

'no-commonjs': require('./rules/no-commonjs'),
'no-amd': require('./rules/no-amd'),
'no-duplicates': require('./rules/no-duplicates'),
first: require('./rules/first'),
'max-dependencies': require('./rules/max-dependencies'),
'no-extraneous-dependencies': require('./rules/no-extraneous-dependencies'),
'no-absolute-path': require('./rules/no-absolute-path'),
'no-nodejs-modules': require('./rules/no-nodejs-modules'),
'no-webpack-loader-syntax': require('./rules/no-webpack-loader-syntax'),
order: require('./rules/order'),
'newline-after-import': require('./rules/newline-after-import'),
'prefer-default-export': require('./rules/prefer-default-export'),
'no-default-export': require('./rules/no-default-export'),
'no-named-export': require('./rules/no-named-export'),
'no-dynamic-require': require('./rules/no-dynamic-require'),
unambiguous: require('./rules/unambiguous'),
'no-unassigned-import': require('./rules/no-unassigned-import'),
'no-useless-path-segments': require('./rules/no-useless-path-segments'),
'dynamic-import-chunkname': require('./rules/dynamic-import-chunkname'),
'no-import-module-exports': require('./rules/no-import-module-exports'),
'no-empty-named-blocks': require('./rules/no-empty-named-blocks'),
'no-commonjs': noCommonjs,
'no-amd': noAmd,
'no-duplicates': noDuplicates,
first,
'max-dependencies': maxDependencies,
'no-extraneous-dependencies': noExtraneousDependencies,
'no-absolute-path': noAbsolutePath,
'no-nodejs-modules': noNodejsModules,
'no-webpack-loader-syntax': noWebpackLoaderSyntax,
order,
'newline-after-import': newlineAfterImport,
'prefer-default-export': preferDefaultExport,
'no-default-export': noDefaultExport,
'no-named-export': noNamedExport,
'no-dynamic-require': noDynamicRequire,
unambiguous,
'no-unassigned-import': noUnassignedImport,
'no-useless-path-segments': noUselessPathSegments,
'dynamic-import-chunkname': dynamicImportChunkname,
'no-import-module-exports': noImportModuleExports,
'no-empty-named-blocks': noEmptyNamedBlocks,

// export
'exports-last': require('./rules/exports-last'),
'exports-last': exportsLast,

// metadata-based
'no-deprecated': require('./rules/no-deprecated'),
'no-deprecated': noDeprecated,

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

export const configs = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
import vm from 'vm'
import { docsUrl } from '../docs-url'

module.exports = {
import { createRule } from '../utils'
import { TSESTree } from '@typescript-eslint/utils'

type Options = {
allowEmpty?: boolean
importFunctions?: readonly string[]
webpackChunknameFormat?: string
}

type MessageId =
| 'leadingComment'
| 'blockComment'
| 'paddedSpaces'
| 'webpackComment'
| 'chunknameFormat'

export = createRule<[Options?], MessageId>({
name: 'dynamic-import-chunkname',
meta: {
type: 'suggestion',
docs: {
category: 'Style guide',
description:
'Enforce a leading comment with the webpackChunkName for dynamic imports.',
url: docsUrl('dynamic-import-chunkname'),
},
schema: [
{
Expand All @@ -30,32 +45,41 @@ module.exports = {
},
},
],
messages: {
leadingComment:
'dynamic imports require a leading comment with the webpack chunkname',
blockComment:
'dynamic imports require a /* foo */ style comment, not a // foo comment',
paddedSpaces:
'dynamic imports require a block comment padded with spaces - /* foo */',
webpackComment:
'dynamic imports require a "webpack" comment with valid syntax',
chunknameFormat:
'dynamic imports require a leading comment in the form /*{{format}}*/',
},
},

defaultOptions: [],
create(context) {
const config = context.options[0]
const { importFunctions = [], allowEmpty = false } = config || {}
const {
importFunctions = [],
allowEmpty = false,
webpackChunknameFormat = '([0-9a-zA-Z-_/.]|\\[(request|index)\\])+',
} = config || {}
} = context.options[0] || {}

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

function run(node, arg) {
function run(node: TSESTree.Node, arg: TSESTree.Node) {
const sourceCode = context.getSourceCode()
const leadingComments = sourceCode.getCommentsBefore
? sourceCode.getCommentsBefore(arg) // This method is available in ESLint >= 4.
: sourceCode.getComments(arg).leading // This method is deprecated in ESLint 7.
const leadingComments = sourceCode.getCommentsBefore(arg)

if ((!leadingComments || leadingComments.length === 0) && !allowEmpty) {
context.report({
node,
message:
'dynamic imports require a leading comment with the webpack chunkname',
messageId: 'leadingComment',
})
return
}
Expand All @@ -66,16 +90,15 @@ module.exports = {
if (comment.type !== 'Block') {
context.report({
node,
message:
'dynamic imports require a /* foo */ style comment, not a // foo comment',
messageId: 'blockComment',
})
return
}

if (!paddedCommentRegex.test(comment.value)) {
context.report({
node,
message: `dynamic imports require a block comment padded with spaces - /* foo */`,
messageId: 'paddedSpaces',
})
return
}
Expand All @@ -86,15 +109,15 @@ module.exports = {
} catch (error) {
context.report({
node,
message: `dynamic imports require a "webpack" comment with valid syntax`,
messageId: 'webpackComment',
})
return
}

if (!commentStyleRegex.test(comment.value)) {
context.report({
node,
message: `dynamic imports require a "webpack" comment with valid syntax`,
messageId: 'webpackComment',
})
return
}
Expand All @@ -107,7 +130,10 @@ module.exports = {
if (!isChunknamePresent && !allowEmpty) {
context.report({
node,
message: `dynamic imports require a leading comment in the form /*${chunkSubstrFormat}*/`,
messageId: 'chunknameFormat',
data: {
format: chunkSubstrFormat,
},
})
}
}
Expand All @@ -119,7 +145,9 @@ module.exports = {

CallExpression(node) {
if (
// @ts-expect-error - legacy parser type
node.callee.type !== 'Import' &&
'name' in node.callee &&
importFunctions.indexOf(node.callee.name) < 0
) {
return
Expand All @@ -129,4 +157,4 @@ module.exports = {
},
}
},
}
})
20 changes: 12 additions & 8 deletions src/rules/exports-last.js → src/rules/exports-last.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
import { docsUrl } from '../docs-url'
import type { TSESTree } from '@typescript-eslint/utils'

function isNonExportStatement({ type }) {
import { createRule } from '../utils'

function isNonExportStatement({ type }: TSESTree.Node) {
return (
type !== 'ExportDefaultDeclaration' &&
type !== 'ExportNamedDeclaration' &&
type !== 'ExportAllDeclaration'
)
}

module.exports = {
export = createRule({
name: 'exports-last',
meta: {
type: 'suggestion',
docs: {
category: 'Style guide',
description: 'Ensure all exports appear after other statements.',
url: docsUrl('exports-last'),
},
schema: [],
messages: {
end: 'Export statements should appear at the end of the file',
},
},

defaultOptions: [],
create(context) {
return {
Program({ body }) {
Expand All @@ -30,13 +35,12 @@ module.exports = {
if (!isNonExportStatement(node)) {
context.report({
node,
message:
'Export statements should appear at the end of the file',
messageId: 'end',
})
}
})
}
},
}
},
}
})
Loading
Loading