131 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
		
		
			
		
	
	
			131 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
|  | /** | ||
|  |  * @license | ||
|  |  * Copyright Google Inc. All Rights Reserved. | ||
|  |  * | ||
|  |  * Use of this source code is governed by an MIT-style license that can be | ||
|  |  * found in the LICENSE file at https://angular.io/license
 | ||
|  |  */ | ||
|  | 
 | ||
|  | import {prompt} from 'inquirer'; | ||
|  | import * as multimatch from 'multimatch'; | ||
|  | import {join} from 'path'; | ||
|  | 
 | ||
|  | import {getAngularDevConfig, getRepoBaseDir} from '../utils/config'; | ||
|  | 
 | ||
|  | import {FormatConfig} from './config'; | ||
|  | import {runInParallel} from './run-commands-parallel'; | ||
|  | 
 | ||
|  | /** By default, run the formatter on all javascript and typescript files. */ | ||
|  | const DEFAULT_MATCHERS = ['**/*.{t,j}s']; | ||
|  | 
 | ||
|  | /** | ||
|  |  * Format provided files in place. | ||
|  |  */ | ||
|  | export async function formatFiles(unfilteredFiles: string[]) { | ||
|  |   // Whether any files failed to format.
 | ||
|  |   let formatFailed = false; | ||
|  |   // All files which formatting should be applied to.
 | ||
|  |   const files = filterFilesByMatchers(unfilteredFiles); | ||
|  | 
 | ||
|  |   console.info(`Formatting ${files.length} file(s)`); | ||
|  | 
 | ||
|  | 
 | ||
|  |   // Run the formatter to format the files in place, split across (number of available
 | ||
|  |   // cpu threads - 1) processess. The task is done in multiple processess to speed up
 | ||
|  |   // the overall time of the task, as running across entire repositories takes a large
 | ||
|  |   // amount of time.
 | ||
|  |   // As a data point for illustration, using 8 process rather than 1 cut the execution
 | ||
|  |   // time from 276 seconds to 39 seconds for the same 2700 files
 | ||
|  |   await runInParallel(files, `${getFormatterBinary()} -i -style=file`, (file, code, _, stderr) => { | ||
|  |     if (code !== 0) { | ||
|  |       formatFailed = true; | ||
|  |       console.error(`Error running clang-format on: ${file}`); | ||
|  |       console.error(stderr); | ||
|  |       console.error(); | ||
|  |     } | ||
|  |   }); | ||
|  | 
 | ||
|  |   // The process should exit as a failure if any of the files failed to format.
 | ||
|  |   if (formatFailed) { | ||
|  |     console.error(`Formatting failed, see errors above for more information.`); | ||
|  |     process.exit(1); | ||
|  |   } | ||
|  |   console.info(`√  Formatting complete.`); | ||
|  |   process.exit(0); | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * Check provided files for formatting correctness. | ||
|  |  */ | ||
|  | export async function checkFiles(unfilteredFiles: string[]) { | ||
|  |   // All files which formatting should be applied to.
 | ||
|  |   const files = filterFilesByMatchers(unfilteredFiles); | ||
|  |   // Files which are currently not formatted correctly.
 | ||
|  |   const failures: string[] = []; | ||
|  | 
 | ||
|  |   console.info(`Checking format of ${files.length} file(s)`); | ||
|  | 
 | ||
|  |   // Run the formatter to check the format of files, split across (number of available
 | ||
|  |   // cpu threads - 1) processess. The task is done in multiple processess to speed up
 | ||
|  |   // the overall time of the task, as running across entire repositories takes a large
 | ||
|  |   // amount of time.
 | ||
|  |   // As a data point for illustration, using 8 process rather than 1 cut the execution
 | ||
|  |   // time from 276 seconds to 39 seconds for the same 2700 files.
 | ||
|  |   await runInParallel(files, `${getFormatterBinary()} --Werror -n -style=file`, (file, code) => { | ||
|  |     // Add any files failing format checks to the list.
 | ||
|  |     if (code !== 0) { | ||
|  |       failures.push(file); | ||
|  |     } | ||
|  |   }); | ||
|  | 
 | ||
|  |   if (failures.length) { | ||
|  |     // Provide output expressing which files are failing formatting.
 | ||
|  |     console.group('\nThe following files are out of format:'); | ||
|  |     for (const file of failures) { | ||
|  |       console.info(`  - ${file}`); | ||
|  |     } | ||
|  |     console.groupEnd(); | ||
|  |     console.info(); | ||
|  | 
 | ||
|  |     // If the command is run in a non-CI environment, prompt to format the files immediately.
 | ||
|  |     let runFormatter = false; | ||
|  |     if (!process.env['CI']) { | ||
|  |       runFormatter = (await prompt({ | ||
|  |                        type: 'confirm', | ||
|  |                        name: 'runFormatter', | ||
|  |                        message: 'Format the files now?', | ||
|  |                      })).runFormatter; | ||
|  |     } | ||
|  | 
 | ||
|  |     if (runFormatter) { | ||
|  |       // Format the failing files as requested.
 | ||
|  |       await formatFiles(failures); | ||
|  |       process.exit(0); | ||
|  |     } else { | ||
|  |       // Inform user how to format files in the future.
 | ||
|  |       console.info(); | ||
|  |       console.info(`To format the failing file run the following command:`); | ||
|  |       console.info(`  yarn ng-dev format files ${failures.join(' ')}`); | ||
|  |       process.exit(1); | ||
|  |     } | ||
|  |   } else { | ||
|  |     console.info('√  All files correctly formatted.'); | ||
|  |     process.exit(0); | ||
|  |   } | ||
|  | } | ||
|  | 
 | ||
|  | /** Get the full path of the formatter binary to execute. */ | ||
|  | function getFormatterBinary() { | ||
|  |   return join(getRepoBaseDir(), 'node_modules/.bin/clang-format'); | ||
|  | } | ||
|  | 
 | ||
|  | /** Filter a list of files to only contain files which are expected to be formatted. */ | ||
|  | function filterFilesByMatchers(allFiles: string[]) { | ||
|  |   const matchers = | ||
|  |       getAngularDevConfig<'format', FormatConfig>().format.matchers || DEFAULT_MATCHERS; | ||
|  |   const files = multimatch(allFiles, matchers, {dot: true}); | ||
|  | 
 | ||
|  |   console.info(`Formatting enforced on ${files.length} of ${allFiles.length} file(s)`); | ||
|  |   return files; | ||
|  | } |