import type { TSESLint , TSESTree } from '@typescript-eslint/experimental-utils' ; import { AST_NODE_TYPES , ESLintUtils } from '@typescript-eslint/experimental-utils' ; import { PackletAnalyzer , IAnalyzerError , InputFileMessageIds , ImportMessageIds } from './PackletAnalyzer' ; export type MessageIds = InputFileMessageIds | ImportMessageIds ; type Options = [ ] ; const mechanics = { meta : { type : 'problem' , messages : { 'file-in-packets-folder' : 'The "packlets" folder must not contain regular source files' , 'invalid-packlet-name' : 'Invalid packlet name "{{packletName}}".' + ' The name must be lowercase alphanumeric words separated by hyphens. Example: "my-packlet"' , 'misplaced-packlets-folder' : 'The packlets folder must be located at "{{expectedPackletsFolder}}"' , 'missing-src-folder' : 'Expecting to find a "src" folder at: {{srcFolderPath}}' , 'missing-tsconfig' : 'In order to use @rushstack/eslint-plugin-packlets, your ESLint config file' + ' must configure the TypeScript parser' , 'packlet-folder-case' : 'The packlets folder must be all lower case: {{packletsFolderPath}}' , 'bypassed-entry-point' : 'The import statement does not use the packlet\'s entry point "{{entryPointModulePath}}"' , 'circular-entry-point' : 'Files under a packlet folder must not import from their own index.ts file' , 'packlet-importing-project-file' : 'A local project file cannot be imported.' + " A packlet's dependencies must be NPM packages and/or other packlets." } , schema : [ { type : 'object' , additionalProperties : false } ] , docs : { description : 'Check that file paths and imports follow the basic mechanics for the packlet formalism' , 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 tsconfigFilePath = ESLintUtils . getParserServices ( context ) . program . getCompilerOptions ( ) [ 'configFilePath' ] as string ; const packletAnalyzer = PackletAnalyzer . analyzeInputFile ( inputFilePath , tsconfigFilePath ) ; if ( packletAnalyzer . nothingToDo ) { return { } ; } return { Program : ( node ) : void => { if ( packletAnalyzer . error ) { context . report ( { node : node , messageId : packletAnalyzer . error . messageId , data : packletAnalyzer . error . data } ) ; } } , 'ImportDeclaration, ExportNamedDeclaration, ExportAllDeclaration' : ( node ) : void => { if ( node . source ?. type === AST_NODE_TYPES . Literal ) { if ( packletAnalyzer . projectUsesPacklets ) { const modulePath = node . source . value ; if ( typeof modulePath !== 'string' ) { return ; } if ( ! ( modulePath . startsWith ( '.' ) || modulePath . startsWith ( '..' ) ) ) { return ; } const lint = packletAnalyzer . analyzeImport ( modulePath ) ; if ( lint ) { context . report ( { node : node , messageId : lint . messageId , data : lint . data } ) ; } } } } } ; } } ; export { mechanics } ;