import type * as ts from 'typescript' ; import * as path from 'path' ; import type { ParserServices , TSESLint , TSESTree } from '@typescript-eslint/experimental-utils' ; import { ESLintUtils } from '@typescript-eslint/experimental-utils' ; import { PackletAnalyzer } from './PackletAnalyzer' ; import { DependencyAnalyzer , IPackletImport } from './DependencyAnalyzer' ; import { Path } from './Path' ; export type MessageIds = 'circular-import' ; type Options = [ ] ; const circularDeps = { meta : { type : 'problem' , messages : { 'circular-import' : 'Packlet imports create a circular reference:\n{{report}}' } , schema : [ { type : 'object' , additionalProperties : false } ] , docs : { description : 'Check for circular dependencies between packlets' , category : 'Best Practices' , recommended : 'warn' , url : 'https://www.npmjs.com/package/@rushstack/eslint-plugin-packlets' } as TSESLint . RuleMetaDataDocs } , create : ( context ) => { const inputFilePath = context . getFilename ( ) ; const program = ESLintUtils . getParserServices ( context ) . program ; const tsconfigFilePath = program . getCompilerOptions ( ) [ 'configFilePath' ] as string ; const packletAnalyzer = PackletAnalyzer . analyzeInputFile ( inputFilePath , tsconfigFilePath ) ; if ( packletAnalyzer . nothingToDo ) { return { } ; } return { Program : ( node ) : void => { if ( packletAnalyzer . isEntryPoint && ! packletAnalyzer . error ) { const packletImports = DependencyAnalyzer . checkEntryPointForCircularImport ( packletAnalyzer . inputFilePackletName ! , packletAnalyzer , program ) ; if ( packletImports ) { const tsconfigFileFolder = Path . dirname ( tsconfigFilePath ) ; const affectedPackletNames = packletImports . map ( ( x ) => x . packletName ) ; affectedPackletNames . sort ( ) ; if ( affectedPackletNames [ 0 ] === packletAnalyzer . inputFilePackletName ) { let report = '' ; for ( const packletImport of packletImports ) { const filePath = Path . relative ( tsconfigFileFolder , packletImport . fromFilePath ) ; report += `"${ packletImport . packletName }" is referenced by ${ filePath }\n` ; } context . report ( { node : node , messageId : 'circular-import' , data : { report : report } } ) ; } } } } } ; } } ; export { circularDeps } ;