import { CliTree, CliTrees, objectPropertiesToCliTrees, writeCliTree } from '@cirrusct/cli-utils'; import { Logger } from '@cirrusct/logging'; import { createError, getIncludedFilePathsFromConfig, getPackageMappedFileList, MrCommandHandler, MrCommandResults, MrPackage, } from '@cirrusct/mr-core'; import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; import { Configuration, findFormatter, ILinterOptions, Linter } from 'tslint'; import { CommandName } from './manifest'; import { LintCommandArguments, LintCommandConfigSettings, LintCommandOptions } from './types'; export const lintPackage = async ( mrPackage: MrPackage, tsLintOptions: ILinterOptions, logger: Logger, files: string[] ): Promise => { const initialCwd = process.cwd(); try { process.chdir(mrPackage.path); const commandConfig = mrPackage.config.getCommandConfig(CommandName); const commandConfigSettings = commandConfig ? commandConfig.value : {}; const filePaths = await getIncludedFilePathsFromConfig(commandConfigSettings, mrPackage.path, files); let output = ''; if (filePaths.length > 0) { // const profileLintConfigFilePath = mrPackage.monoRepo.profiles.resolvePath('lint', 'tslint.json'); filePaths.map(fileName => { let loadConfig: Configuration.IConfigurationLoadResult; try { loadConfig = Configuration.findConfiguration(null, fileName); if (!loadConfig) { // TODO: Implement Load file resource from profile throw createError(`No lint config file for '${fileName}'`); // loadConfig = Configuration.findConfiguration(profileLintConfigFilePath, fileName); } } catch (e) { throw createError('findConfiguration failed', e); } if (!loadConfig) { throw createError(`No Lint config for file: ${fileName}`); } logger.debug( { configFile: loadConfig.path, fileName, }, 'linting' ); const fileContents = fs.readFileSync(fileName, 'utf8'); const linter = new Linter(tsLintOptions); const configuration = loadConfig.results; linter.lint(fileName, fileContents, configuration); const result = linter.getResult(); if ((result.output || '').trim().length) { output += `${result.output}`; } }); } else { logger.info('Lint: No files to format'); } return output; } catch (e) { throw createError(`linitPackage failed`, e); } finally { process.chdir(initialCwd); } }; const buildTsLintOptions = (cliOptions: LintCommandOptions): ILinterOptions => { const tsLinterOptions = { ...cliOptions, // formatter: cliOptions.format || (cliOptions.out ? 'json' : 'tspretty'), formatter: cliOptions.format || (cliOptions.out ? 'json' : 'codeFrame'), formattersDirectory: path.join(path.resolve(path.dirname(require.resolve('.'))), 'formatters'), }; return tsLinterOptions as ILinterOptions; }; export const handleCommand: MrCommandHandler = async ({ args, options, session, logger, packages, }) => { debugger; const { project } = session; // get optional individual file names (mapped to packages) based on --git-staged setting and cmd args const isFileSpec = !!options.gitStaged || (args && args.files && args.files.length > 0); const tsLintOptions = buildTsLintOptions(options); let fileOutput = ''; const writePkgOutput = (pkg: MrPackage, pkgOut: string = '') => { if (pkgOut.trim().length > 0) { if (options.out) { fileOutput += pkgOut; } else { logger.info(`Package: ${pkg.name} - ${pkg.path}`); logger.info(pkgOut); } } }; if (isFileSpec) { const filesMap = await getPackageMappedFileList( project, options.gitStaged || false, args.files || [], packages ); if (filesMap.size > 0) { // operating on individual files // get array of packages in the map (union with packages array passed to command) const filePkgs = Array.from(filesMap.keys()); // iterated packages for (const pkg of filePkgs) { const pkgOut = await lintPackage(pkg, tsLintOptions, logger, filesMap.get(pkg)); writePkgOutput(pkg, pkgOut); } } else { logger.info( { ...options, packages: (packages || []).map(p => p.name).join(', '), }, 'Lint: No files matching fileSpec options' ); } } else { // iterate over packages passed to command, processing all files based on command config for (const pkg of packages) { const pkgOut = await lintPackage(pkg, tsLintOptions, logger, []); writePkgOutput(pkg, pkgOut); } } if (options.out) { fs.writeFileSync(options.out, fileOutput); } };