import * as path from 'path' ; import * as fs from 'fs' ; import type { TSESLint , TSESTree } from '@typescript-eslint/experimental-utils' ; import { ESLintUtils } from '@typescript-eslint/experimental-utils' ; import { PackletAnalyzer } from './PackletAnalyzer' ; export type MessageIds = 'missing-readme' | 'error-reading-file' | 'readme-too-short' ; type Options = [ { minimumReadmeWords ? : number ; } ] ; const readme = { meta : { type : 'problem' , messages : { 'missing-readme' : 'The ESLint configuration requires each packlet to provide a README.md file summarizing' + ' its purpose and usage: {{readmePath}}' , 'readme-too-short' : 'The ESLint configuration requires at least {{minimumReadmeWords}} words of documentation in the' + ' README.md file: {{readmePath}}' , 'error-reading-file' : 'Error reading input file {{readmePath}}:\n{{errorMessage}}' } , schema : [ { type : 'object' , properties : { minimumReadmeWords : { type : 'number' } } , additionalProperties : false } ] , docs : { description : 'Require each packlet folder to have a README.md file summarizing its purpose and usage' , category : 'Best Practices' , recommended : false , url : 'https://www.npmjs.com/package/@rushstack/eslint-plugin-packlets' } as TSESLint . RuleMetaDataDocs } , create : ( context ) => { const minimumReadmeWords = context . options [ 0 ] ?. minimumReadmeWords || 10 ; const inputFilePath = context . getFilename ( ) ; const tsconfigFilePath = ESLintUtils . getParserServices ( context ) . program . getCompilerOptions ( ) [ 'configFilePath' ] as string ; const packletAnalyzer = PackletAnalyzer . analyzeInputFile ( inputFilePath , tsconfigFilePath ) ; if ( ! packletAnalyzer . nothingToDo && ! packletAnalyzer . error ) { if ( packletAnalyzer . isEntryPoint ) { return { Program : ( node ) : void => { const readmePath = path . join ( packletAnalyzer . packletsFolderPath ! , packletAnalyzer . inputFilePackletName ! , 'README.md' ) ; try { if ( ! fs . existsSync ( readmePath ) ) { context . report ( { node : node , messageId : 'missing-readme' , data : { readmePath } } ) ; } else { if ( minimumReadmeWords > 0 ) { const readmeContent = fs . readFileSync ( readmePath ) . toString ( ) ; const words = readmeContent . split ( /[^a-z'"]+/i ) . filter ( ( x ) => x . length > 0 ) ; if ( words . length < minimumReadmeWords ) { context . report ( { node : node , messageId : 'readme-too-short' , data : { readmePath , minimumReadmeWords } } ) ; } } } } catch ( error ) { context . report ( { node : node , messageId : 'error-reading-file' , data : { readmePath , errorMessage : ( error as Error ) . toString ( ) } } ) ; } } } ; } } return { } ; } } ; export { readme } ;