Skip to content

Commit

Permalink
refactor: migrate several rules (#50)
Browse files Browse the repository at this point in the history
  • Loading branch information
JounQin committed Mar 15, 2024
1 parent 3d7a551 commit de896f4
Show file tree
Hide file tree
Showing 28 changed files with 1,316 additions and 1,183 deletions.
5 changes: 5 additions & 0 deletions .changeset/odd-chicken-boil.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eslint-plugin-import-x": patch
---

refactor: migrate several rules
35 changes: 24 additions & 11 deletions patches/@typescript-eslint+utils+5.62.0.patch
Original file line number Diff line number Diff line change
@@ -1,24 +1,37 @@
diff --git a/node_modules/@typescript-eslint/utils/dist/ts-eslint/Rule.d.ts b/node_modules/@typescript-eslint/utils/dist/ts-eslint/Rule.d.ts
index 9a3a1fd..6a2e2dd 100644
index 9a3a1fd..c6ed412 100644
--- a/node_modules/@typescript-eslint/utils/dist/ts-eslint/Rule.d.ts
+++ b/node_modules/@typescript-eslint/utils/dist/ts-eslint/Rule.d.ts
@@ -7,15 +7,13 @@ import type { SourceCode } from './SourceCode';
@@ -6,6 +6,10 @@ import type { Scope } from './Scope';
import type { SourceCode } from './SourceCode';
export type RuleRecommendation = 'error' | 'strict' | 'warn' | false;
interface RuleMetaDataDocs {
/**
- * Concise description of the rule
+ /**
+ * The category the rule falls under
*/
- description: string;
+ */
+ category?: string;
/**
- * The recommendation level for the rule.
- * Used by the build tools to generate the recommended and strict configs.
- * Set to false to not include it as a recommendation
+ * Concise description of the rule
* Concise description of the rule
*/
@@ -15,7 +19,7 @@ interface RuleMetaDataDocs {
* Used by the build tools to generate the recommended and strict configs.
* Set to false to not include it as a recommendation
*/
- recommended: 'error' | 'strict' | 'warn' | false;
+ description: string;
+ recommended?: 'error' | 'strict' | 'warn' | boolean;
/**
* The URL of the rule's docs
*/
diff --git a/node_modules/@typescript-eslint/utils/dist/ts-eslint/RuleTester.d.ts b/node_modules/@typescript-eslint/utils/dist/ts-eslint/RuleTester.d.ts
index c8afefe..d629d04 100644
--- a/node_modules/@typescript-eslint/utils/dist/ts-eslint/RuleTester.d.ts
+++ b/node_modules/@typescript-eslint/utils/dist/ts-eslint/RuleTester.d.ts
@@ -115,7 +115,7 @@ interface RunTests<TMessageIds extends string, TOptions extends Readonly<unknown
readonly invalid: readonly InvalidTestCase<TMessageIds, TOptions>[];
}
interface RuleTesterConfig extends Linter.Config {
- readonly parser: string;
+ readonly parser?: string;
readonly parserOptions?: Readonly<ParserOptions>;
}
declare class RuleTesterBase {
57 changes: 32 additions & 25 deletions src/export-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ export interface DeclarationMetadata {
isOnlyImportingTypes?: boolean
}

export interface ModuleNamespace {
doc?: Annotation
namespace?: ExportMap | null
}

export interface ModuleImport {
getter: () => ExportMap | null
declarations: Set<DeclarationMetadata>
}

export class ExportMap {
static for(context: ChildContext) {
const { path } = context
Expand Down Expand Up @@ -216,18 +226,25 @@ export class ExportMap {
return ExportMap.for(childContext(rp, context))
}

function getNamespace(identifier: TSESTree.Identifier) {
if (!namespaces.has(identifier.name)) {
function getNamespace(identifier: TSESTree.Identifier | string) {
const namespace =
typeof identifier === 'string' ? identifier : identifier.name
if (!namespaces.has(namespace)) {
return
}

return function () {
return resolveImport(namespaces.get(identifier.name))
return resolveImport(namespaces.get(namespace))
}
}

function addNamespace(object: object, identifier: TSESTree.Identifier) {
const nsfn = getNamespace(identifier)
function addNamespace(
object: object,
identifier: TSESTree.Identifier | string,
) {
const namespace =
typeof identifier === 'string' ? identifier : identifier.name
const nsfn = getNamespace(namespace)
if (nsfn) {
Object.defineProperty(object, 'namespace', { get: nsfn })
}
Expand All @@ -247,7 +264,7 @@ export class ExportMap {
n.source &&
(n.source as TSESTree.StringLiteral).value) as string

const exportMeta = {}
const exportMeta: ModuleNamespace = {}

let local: string

Expand All @@ -273,11 +290,7 @@ export class ExportMap {
s.exported!.name ||
// @ts-expect-error - legacy parser type
s.exported!.value,
addNamespace(
exportMeta,
// @ts-expect-error -- FIXME: no idea yet
s.source.value,
),
addNamespace(exportMeta, s.source.value),
)
return
case 'ExportSpecifier':
Expand Down Expand Up @@ -625,7 +638,7 @@ export class ExportMap {
return m
}

namespace = new Map()
namespace = new Map<string, ModuleNamespace>()

// todo: restructure to key on path, value is resolver + map of names
reexports = new Map<
Expand All @@ -644,19 +657,13 @@ export class ExportMap {
/**
* dependencies of this module that are not explicitly re-exported
*/
imports = new Map<
string,
{
getter: () => ExportMap | null
declarations: Set<DeclarationMetadata>
}
>()
imports = new Map<string, ModuleImport>()

errors: ParseError[] = []

parseGoal: 'ambiguous' | 'Module' | 'Script' = 'ambiguous'

private declare visitorKeys: TSESLint.SourceCode.VisitorKeys | null
declare visitorKeys: TSESLint.SourceCode.VisitorKeys | null

private declare mtime: Date

Expand Down Expand Up @@ -770,7 +777,7 @@ export class ExportMap {
return { found: false, path: [this] }
}

get<T = unknown>(name: string): T | null | undefined {
get(name: string): ModuleNamespace | null | undefined {
if (this.namespace.has(name)) {
return this.namespace.get(name)
}
Expand Down Expand Up @@ -808,15 +815,15 @@ export class ExportMap {

const innerValue = innerMap.get(name)
if (innerValue !== undefined) {
return innerValue as T
return innerValue
}
}
}
}

forEach<T>(
forEach(
callback: (
value: T | null | undefined,
value: ModuleNamespace | null | undefined,
name: string,
map: ExportMap,
) => void,
Expand All @@ -839,7 +846,7 @@ export class ExportMap {
return
}

d.forEach<T>((v, n) => {
d.forEach((v, n) => {
if (n !== 'default') {
callback.call(thisArg, v, n, this)
}
Expand Down
21 changes: 14 additions & 7 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ import groupExports from './rules/group-exports'
import noRelativePackages from './rules/no-relative-packages'
import noRelativeParentImports from './rules/no-relative-parent-imports'
import consistentTypeSpecifierStyle from './rules/consistent-type-specifier-style'
import noSelfImport from './rules/no-self-import'
import noCycle from './rules/no-cycle'
import noNamedDefault from './rules/no-named-default'
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'

// configs
import recommended from './config/recommended'
Expand Down Expand Up @@ -44,13 +51,13 @@ export const rules = {
'no-relative-parent-imports': noRelativeParentImports,
'consistent-type-specifier-style': consistentTypeSpecifierStyle,

'no-self-import': require('./rules/no-self-import'),
'no-cycle': require('./rules/no-cycle'),
'no-named-default': require('./rules/no-named-default'),
'no-named-as-default': require('./rules/no-named-as-default'),
'no-named-as-default-member': require('./rules/no-named-as-default-member'),
'no-anonymous-default-export': require('./rules/no-anonymous-default-export'),
'no-unused-modules': require('./rules/no-unused-modules'),
'no-self-import': noSelfImport,
'no-cycle': noCycle,
'no-named-default': noNamedDefault,
'no-named-as-default': noNamedAsDefault,
'no-named-as-default-member': noNamedAsDefaultMember,
'no-anonymous-default-export': noAnonymousDefaultExport,
'no-unused-modules': noUnusedModules,

'no-commonjs': require('./rules/no-commonjs'),
'no-amd': require('./rules/no-amd'),
Expand Down
16 changes: 6 additions & 10 deletions src/rules/namespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type Options = {

function processBodyStatement(
context: RuleContext<MessageId>,
namespaces: Map<string, ExportMap>,
namespaces: Map<string, ExportMap | null>,
declaration: TSESTree.ProgramStatement,
) {
if (declaration.type !== 'ImportDeclaration') {
Expand Down Expand Up @@ -56,7 +56,7 @@ function processBodyStatement(
break
case 'ImportDefaultSpecifier':
case 'ImportSpecifier': {
const meta = imports.get<{ namespace?: ExportMap }>(
const meta = imports.get(
'imported' in specifier && specifier.imported
? specifier.imported.name ||
// @ts-expect-error - legacy parser node
Expand Down Expand Up @@ -136,7 +136,7 @@ export = createRule<[Options], MessageId>({
// read options
const { allowComputed } = context.options[0] || {}

const namespaces = new Map<string, ExportMap>()
const namespaces = new Map<string, ExportMap | null>()

return {
// pick up all imports at body entry time, to properly respect hoisting
Expand Down Expand Up @@ -231,9 +231,7 @@ export = createRule<[Options], MessageId>({
break
}

const exported = namespace.get<{ namespace: ExportMap }>(
deref.property.name,
)
const exported = namespace.get(deref.property.name)

if (exported == null) {
return
Expand Down Expand Up @@ -268,7 +266,7 @@ export = createRule<[Options], MessageId>({
// DFS traverse child namespaces
function testKey(
pattern: TSESTree.Node,
namespace?: ExportMap,
namespace?: ExportMap | null,
path: string[] = [initName],
) {
if (!(namespace instanceof ExportMap)) {
Expand Down Expand Up @@ -304,9 +302,7 @@ export = createRule<[Options], MessageId>({

path.push(property.key.name)

const dependencyExportMap = namespace.get<{ namespace: ExportMap }>(
property.key.name,
)
const dependencyExportMap = namespace.get(property.key.name)

// could be null when ignored or ambiguous
if (dependencyExportMap != null) {
Expand Down
7 changes: 1 addition & 6 deletions src/rules/newline-after-import.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/**
* @fileoverview Rule to enforce new line after import not followed by another import.
* @author Radek Benkel
* Rule to enforce new line after import not followed by another import.
*/

import { isStaticRequire } from '../core/static-require'
Expand All @@ -9,10 +8,6 @@ import { docsUrl } from '../docs-url'
import debug from 'debug'
const log = debug('eslint-plugin-import-x:rules:newline-after-import')

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

function containsNodeOrEqual(outerNode, innerNode) {
return (
outerNode.range[0] <= innerNode.range[0] &&
Expand Down
7 changes: 1 addition & 6 deletions src/rules/no-amd.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
/**
* @fileoverview Rule to prefer imports to AMD
* @author Jamund Ferguson
* Rule to prefer imports to AMD
*/

import { docsUrl } from '../docs-url'

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

module.exports = {
meta: {
type: 'suggestion',
Expand Down
Loading

0 comments on commit de896f4

Please sign in to comment.