| 
									
										
										
										
											2022-06-29 19:25:31 +08:00
										 |  |  | import { BettererFileTest } from '@betterer/betterer'; | 
					
						
							| 
									
										
										
										
											2023-03-31 00:11:30 +08:00
										 |  |  | import { promises as fs } from 'fs'; | 
					
						
							| 
									
										
										
										
											2022-07-04 19:13:20 +08:00
										 |  |  | import { ESLint, Linter } from 'eslint'; | 
					
						
							| 
									
										
										
										
											2022-12-09 16:18:19 +08:00
										 |  |  | import path from 'path'; | 
					
						
							| 
									
										
										
										
											2023-07-13 22:07:10 +08:00
										 |  |  | import { glob } from 'glob'; | 
					
						
							| 
									
										
										
										
											2022-02-09 20:41:39 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | export default { | 
					
						
							| 
									
										
										
										
											2023-03-29 23:02:53 +08:00
										 |  |  |   'better eslint': () => | 
					
						
							|  |  |  |     countEslintErrors() | 
					
						
							|  |  |  |       .include('**/*.{ts,tsx}') | 
					
						
							|  |  |  |       .exclude(/public\/app\/angular/), | 
					
						
							| 
									
										
										
										
											2023-05-11 20:26:12 +08:00
										 |  |  |   'no undocumented stories': () => countUndocumentedStories().include('**/!(*.internal).story.tsx'), | 
					
						
							| 
									
										
										
										
											2022-02-09 20:41:39 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2022-06-29 19:25:31 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | function countUndocumentedStories() { | 
					
						
							|  |  |  |   return new BettererFileTest(async (filePaths, fileTestResult) => { | 
					
						
							| 
									
										
										
										
											2023-03-31 00:11:30 +08:00
										 |  |  |     await Promise.all( | 
					
						
							|  |  |  |       filePaths.map(async (filePath) => { | 
					
						
							|  |  |  |         // look for .mdx import in the story file
 | 
					
						
							|  |  |  |         const regex = new RegExp("^import.*.mdx';$", 'gm'); | 
					
						
							|  |  |  |         const fileText = await fs.readFile(filePath, 'utf8'); | 
					
						
							|  |  |  |         if (!regex.test(fileText)) { | 
					
						
							|  |  |  |           // In this case the file contents don't matter:
 | 
					
						
							|  |  |  |           const file = fileTestResult.addFile(filePath, ''); | 
					
						
							|  |  |  |           // Add the issue to the first character of the file:
 | 
					
						
							|  |  |  |           file.addIssue(0, 0, 'No undocumented stories are allowed, please add an .mdx file with some documentation'); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-06-29 19:25:31 +08:00
										 |  |  |   }); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-07-04 19:13:20 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | function countEslintErrors() { | 
					
						
							|  |  |  |   return new BettererFileTest(async (filePaths, fileTestResult, resolver) => { | 
					
						
							|  |  |  |     const { baseDirectory } = resolver; | 
					
						
							|  |  |  |     const cli = new ESLint({ cwd: baseDirectory }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-02 20:59:34 +08:00
										 |  |  |     const eslintConfigFiles = await glob('**/.eslintrc'); | 
					
						
							| 
									
										
										
										
											2022-12-09 16:18:19 +08:00
										 |  |  |     const eslintConfigMainPaths = eslintConfigFiles.map((file) => path.resolve(path.dirname(file))); | 
					
						
							| 
									
										
										
										
											2022-07-04 19:13:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-09 16:18:19 +08:00
										 |  |  |     const baseRules: Partial<Linter.RulesRecord> = { | 
					
						
							|  |  |  |       '@typescript-eslint/no-explicit-any': 'error', | 
					
						
							| 
									
										
										
										
											2023-01-18 23:02:35 +08:00
										 |  |  |       '@grafana/no-aria-label-selectors': 'error', | 
					
						
							| 
									
										
										
										
											2022-12-09 16:18:19 +08:00
										 |  |  |     }; | 
					
						
							| 
									
										
										
										
											2022-07-04 19:13:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-09 16:18:19 +08:00
										 |  |  |     const nonTestFilesRules: Partial<Linter.RulesRecord> = { | 
					
						
							|  |  |  |       ...baseRules, | 
					
						
							|  |  |  |       '@typescript-eslint/consistent-type-assertions': ['error', { assertionStyle: 'never' }], | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2022-08-11 22:06:15 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-09 16:18:19 +08:00
										 |  |  |     // group files by eslint config file
 | 
					
						
							|  |  |  |     // this will create two file groups for each eslint config file
 | 
					
						
							|  |  |  |     // one for test files and one for non-test files
 | 
					
						
							|  |  |  |     const fileGroups: Record<string, string[]> = {}; | 
					
						
							| 
									
										
										
										
											2022-07-04 19:13:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-09 16:18:19 +08:00
										 |  |  |     for (const filePath of filePaths) { | 
					
						
							|  |  |  |       let configPath = eslintConfigMainPaths.find((configPath) => filePath.startsWith(configPath)) ?? ''; | 
					
						
							|  |  |  |       const isTestFile = | 
					
						
							|  |  |  |         filePath.endsWith('.test.tsx') || | 
					
						
							|  |  |  |         filePath.endsWith('.test.ts') || | 
					
						
							|  |  |  |         filePath.includes('__mocks__') || | 
					
						
							|  |  |  |         filePath.includes('public/test/'); | 
					
						
							| 
									
										
										
										
											2022-07-04 19:13:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-09 16:18:19 +08:00
										 |  |  |       if (isTestFile) { | 
					
						
							|  |  |  |         configPath += '-test'; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (!fileGroups[configPath]) { | 
					
						
							|  |  |  |         fileGroups[configPath] = []; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       fileGroups[configPath].push(filePath); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (const configPath of Object.keys(fileGroups)) { | 
					
						
							|  |  |  |       const rules = configPath.endsWith('-test') ? baseRules : nonTestFilesRules; | 
					
						
							|  |  |  |       // this is by far the slowest part of this code. It takes eslint about 2 seconds just to find the config
 | 
					
						
							|  |  |  |       const linterOptions = (await cli.calculateConfigForFile(fileGroups[configPath][0])) as Linter.Config; | 
					
						
							|  |  |  |       const runner = new ESLint({ | 
					
						
							|  |  |  |         baseConfig: { | 
					
						
							|  |  |  |           ...linterOptions, | 
					
						
							|  |  |  |           rules: rules, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         useEslintrc: false, | 
					
						
							|  |  |  |         cwd: baseDirectory, | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       const lintResults = await runner.lintFiles(fileGroups[configPath]); | 
					
						
							|  |  |  |       lintResults | 
					
						
							|  |  |  |         .filter((lintResult) => lintResult.source) | 
					
						
							|  |  |  |         .forEach((lintResult) => { | 
					
						
							|  |  |  |           const { messages } = lintResult; | 
					
						
							|  |  |  |           const filePath = lintResult.filePath; | 
					
						
							|  |  |  |           const file = fileTestResult.addFile(filePath, ''); | 
					
						
							|  |  |  |           messages.forEach((message, index) => { | 
					
						
							|  |  |  |             file.addIssue(0, 0, message.message, `${index}`); | 
					
						
							| 
									
										
										
										
											2022-07-04 19:13:20 +08:00
										 |  |  |           }); | 
					
						
							| 
									
										
										
										
											2022-12-09 16:18:19 +08:00
										 |  |  |         }); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-07-04 19:13:20 +08:00
										 |  |  |   }); | 
					
						
							|  |  |  | } |