Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add internal lint rule no-relative-paths-to-internal-packages
- Loading branch information
1 parent
6954a4a
commit 088d69b
Showing
4 changed files
with
188 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
packages/eslint-plugin-internal/src/rules/no-relative-paths-to-internal-packages.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import path from 'path'; | ||
|
||
import { createRule } from '../util'; | ||
|
||
export const REPO_ROOT = path.resolve(__dirname, '../../../..'); | ||
export const PACKAGES_DIR = path.join(REPO_ROOT, 'packages'); | ||
|
||
export default createRule({ | ||
name: __filename, | ||
meta: { | ||
type: 'problem', | ||
docs: { | ||
recommended: 'recommended', | ||
description: 'Disallow relative paths to internal packages', | ||
}, | ||
messages: { | ||
noRelativePathsToInternalPackages: | ||
'Use absolute paths instead of relative paths to import modules in other internal packages.', | ||
}, | ||
schema: [], | ||
fixable: 'code', | ||
}, | ||
|
||
defaultOptions: [], | ||
|
||
create(context) { | ||
return { | ||
ImportDeclaration(node): void { | ||
const importSource = node.source; | ||
if ( | ||
importSource.value.startsWith('@typescript-eslint') || | ||
!importSource.value.startsWith('.') | ||
) { | ||
return; | ||
} | ||
|
||
// The idea here is to check if the import source resolves to a different | ||
// package than the package the file is currently in. This lets us not flag | ||
// relative paths to modules inside a package called 'utils' but still flag | ||
// if importing the '@typescript-eslint/utils' package with a relative path. | ||
|
||
const pathOfFileFromPackagesDir = path.relative( | ||
PACKAGES_DIR, | ||
context.physicalFilename, | ||
); | ||
const packageOfFile = pathOfFileFromPackagesDir.split(path.sep)[0]; | ||
const absolutePathOfImport = path.resolve( | ||
path.dirname(context.physicalFilename), | ||
importSource.value, | ||
); | ||
const pathOfImportFromPackagesDir = path.relative( | ||
PACKAGES_DIR, | ||
absolutePathOfImport, | ||
); | ||
const packageOfImport = pathOfImportFromPackagesDir.split(path.sep)[0]; | ||
|
||
if (packageOfImport !== packageOfFile) { | ||
context.report({ | ||
node: importSource, | ||
messageId: 'noRelativePathsToInternalPackages', | ||
fix: fixer => | ||
fixer.replaceText( | ||
importSource, | ||
`'@typescript-eslint/${path.relative(PACKAGES_DIR, absolutePathOfImport)}'`, | ||
), | ||
}); | ||
} | ||
}, | ||
}; | ||
}, | ||
}); |
113 changes: 113 additions & 0 deletions
113
packages/eslint-plugin-internal/tests/rules/no-relative-paths-to-internal-packages.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import { RuleTester } from '@typescript-eslint/rule-tester'; | ||
import path from 'path'; | ||
|
||
import rule, { | ||
PACKAGES_DIR, | ||
} from '../../src/rules/no-relative-paths-to-internal-packages'; | ||
|
||
const ruleTester = new RuleTester({ | ||
parser: '@typescript-eslint/parser', | ||
}); | ||
|
||
ruleTester.run('no-relative-paths-to-internal-packages', rule, { | ||
valid: [ | ||
"import { parse } from '@typescript-eslint/typescript-estree';", | ||
"import { something } from 'not/a/relative/path';", | ||
{ | ||
filename: path.resolve( | ||
PACKAGES_DIR, | ||
'eslint-plugin/src/rules/my-awesome-rule.ts', | ||
), | ||
code: "import { something } from './utils';", | ||
}, | ||
{ | ||
code: "import type { ValueOf } from './utils';", | ||
filename: path.resolve( | ||
PACKAGES_DIR, | ||
'ast-spec/src/expression/AssignmentExpression/spec.ts', | ||
), | ||
}, | ||
{ | ||
code: "import type { ValueOf } from '../../utils';", | ||
filename: path.resolve( | ||
PACKAGES_DIR, | ||
'ast-spec/src/expression/AssignmentExpression/spec.ts', | ||
), | ||
}, | ||
{ | ||
code: "import type { ValueOf } from '../../../utils';", | ||
filename: path.resolve( | ||
PACKAGES_DIR, | ||
'ast-spec/src/expression/AssignmentExpression/spec.ts', | ||
), | ||
}, | ||
], | ||
invalid: [ | ||
{ | ||
code: "import { parse } from '../../../typescript-estree';", | ||
filename: path.resolve( | ||
PACKAGES_DIR, | ||
'eslint-plugin/src/rules/my-awesome-rule.ts', | ||
), | ||
output: `import { parse } from '@typescript-eslint/typescript-estree';`, | ||
errors: [ | ||
{ | ||
messageId: 'noRelativePathsToInternalPackages', | ||
line: 1, | ||
}, | ||
], | ||
}, | ||
{ | ||
code: "import { parse } from '../../../typescript-estree/inner-module';", | ||
filename: path.resolve( | ||
PACKAGES_DIR, | ||
'eslint-plugin/src/rules/my-awesome-rule.ts', | ||
), | ||
output: `import { parse } from '@typescript-eslint/typescript-estree/inner-module';`, | ||
errors: [ | ||
{ | ||
messageId: 'noRelativePathsToInternalPackages', | ||
line: 1, | ||
}, | ||
], | ||
}, | ||
{ | ||
code: "import type { ValueOf } from '../../../../utils';", | ||
output: "import type { ValueOf } from '@typescript-eslint/utils';", | ||
filename: path.resolve( | ||
PACKAGES_DIR, | ||
'ast-spec/src/expression/AssignmentExpression/spec.ts', | ||
), | ||
errors: [ | ||
{ | ||
messageId: 'noRelativePathsToInternalPackages', | ||
line: 1, | ||
}, | ||
], | ||
}, | ||
{ | ||
code: ` | ||
import type { | ||
MemberExpressionComputedName, | ||
MemberExpressionNonComputedName, | ||
} from '../../../types/src/generated/ast-spec'; | ||
`, | ||
output: ` | ||
import type { | ||
MemberExpressionComputedName, | ||
MemberExpressionNonComputedName, | ||
} from '@typescript-eslint/types/src/generated/ast-spec'; | ||
`, | ||
filename: path.resolve( | ||
PACKAGES_DIR, | ||
'eslint-plugin/src/rules/prefer-find.ts', | ||
), | ||
errors: [ | ||
{ | ||
messageId: 'noRelativePathsToInternalPackages', | ||
line: 5, | ||
}, | ||
], | ||
}, | ||
], | ||
}); |