UNPKG

@maniascript/mslint

Version:
248 lines (244 loc) 8.94 kB
import path from 'node:path'; import { loadConfig, createConfig } from './config.js'; import { MSLintError } from './error.js'; import { Linter } from './lint.js'; import * as output from './output.js'; import { version } from '../../version.js'; import { Severity } from './rule.js'; import { allRules } from '../rules/index.js'; var Capture; (function (Capture) { Capture[Capture["None"] = 0] = "None"; Capture[Capture["ConfigPath"] = 1] = "ConfigPath"; })(Capture || (Capture = {})); const CLI_HELP = ` Usage: mslint [options] [file|glob-pattern]+ -h, --help Displays this help -v, --version Displays MSLint version number -c, --config String Path to an MSLint configuration file - default: "" -l, --verbose Displays information about the lint as it progresses -s, --stats Displays lint statistics at the end --report-unused-disable-directives Report disable directive comments that are not useful --report-disable-directives-without-description Report disable directive comments without a description mslint version: ${version} `; function formatResult(result) { let resultOuput = ''; let errorsCount = 0; let warningsCount = 0; if (!result.success) resultOuput += '\n'; for (const fileResult of result.files) { if (fileResult.messages.length <= 0) continue; const messagesOutput = []; const maxLength = []; for (const message of fileResult.messages) { if (message.severity !== Severity.Off) { let severityOutput = ''; switch (message.severity) { case Severity.Error: { severityOutput = output.formatTextColorRed('error'); break; } case Severity.Warn: { severityOutput = output.formatTextColorOrange('warning'); break; } } const messageOuput = [ output.formatTextDim(`${message.source.loc.start.line.toString()}:${message.source.loc.start.column.toString()}`), severityOutput, message.message, output.formatTextDim(message.ruleId ?? '') ]; for (let index = 0; index < messageOuput.length; index++) { if (maxLength.at(index) === undefined || maxLength[index] < messageOuput[index].length) { maxLength[index] = messageOuput[index].length; } } if (message.severity === Severity.Error) { errorsCount++; } else { warningsCount++; } messagesOutput.push(messageOuput); } } if (messagesOutput.length > 0) { resultOuput += `${output.formatTextUnderline(path.resolve(fileResult.path))}\n`; for (const message of messagesOutput) { let index = 0; for (const part of message) { resultOuput += ` ${part.padEnd(maxLength[index], ' ')}`; index++; } resultOuput += '\n'; } } } if (errorsCount === 1) { resultOuput += `\n🔴 ${output.formatTextColorRed('1 error')}`; } else if (errorsCount > 1) { resultOuput += `\n🔴 ${output.formatTextColorRed(`${errorsCount.toString()} errors`)}`; } if (warningsCount === 1) { resultOuput += `\n🟡 ${output.formatTextColorOrange('1 warning')}`; } else if (warningsCount > 1) { resultOuput += `\n🟡 ${output.formatTextColorOrange(`${warningsCount.toString()} warnings`)}`; } if (errorsCount > 0 || warningsCount > 0) { resultOuput += '\n'; } return resultOuput; } function captureArgumentValue(command, capture, argName, argValue) { if (argValue.startsWith('-')) { throw new MSLintError(`Missing value for argument ${argName}`); } switch (capture) { case Capture.ConfigPath: { command.configPath = argValue; break; } default: { throw new MSLintError(`Unknown argument ${argName}. Use "mslint --help" to see all valid arguments.`); } } return command; } function parseArguments(args) { let command = { configPath: null, patterns: null, verbose: null, displayStats: null, displayVersion: null, displayHelp: null, reportUnusedDisableDirective: null, reportDisableDirectiveWithoutDescription: null }; let capture = Capture.None; let argIndex = 0; for (const arg of args) { if (capture !== Capture.None) { command = captureArgumentValue(command, capture, args[argIndex - 1], arg); capture = Capture.None; } else if (arg.startsWith('-')) { if (command.patterns !== null) { throw new MSLintError(`You can't add more arguments after path '${command.patterns.pop() ?? '???'}'`); } else if (arg === '--config' || arg === '-c') { if (command.configPath === null) { capture = Capture.ConfigPath; } else { throw new MSLintError('You can use [--config, -c] only once'); } } else if (arg === '--verbose' || arg === '-l') { command.verbose = true; } else if (arg === '--stats' || arg === '-s') { command.displayStats = true; } else if (arg === '--version' || arg === '-v') { command.displayVersion = true; } else if (arg === '--help' || arg === '-h') { command.displayHelp = true; } else if (arg === '--report-unused-disable-directives') { command.reportUnusedDisableDirective = true; } else if (arg === '--report-disable-directives-without-description') { command.reportDisableDirectiveWithoutDescription = true; } else { throw new MSLintError(`Unknown argument ${arg}. Use "mslint --help" to see all valid arguments.`); } } else { if (command.patterns === null) { command.patterns = [arg]; } else { command.patterns.push(arg); } } argIndex += 1; } if (capture !== Capture.None) { throw new MSLintError(`Missing value for last argument ${args[args.length - 1]}`); } return command; } async function execute(args, cwd) { const command = parseArguments(args); if (command.displayHelp === true) { output.info(CLI_HELP); return 0; } if (command.displayVersion === true) { output.info(`Version ${version}`); return 0; } // Setup config let config; if (command.configPath !== null) { config = loadConfig(command.configPath); } else { // @Todo Before creating a default config, try to search for a config file `mslint.json` in the current directory or its parent ? const rules = {}; for (const [ruleId, rule] of allRules) { rules[ruleId] = ['error', rule.meta.settings]; } config = createConfig({ cwd, rules }); } const patterns = []; for (const pattern of config.patterns) { if (!patterns.includes(pattern)) { patterns.push(pattern); } } if (command.patterns !== null) { for (const pattern of command.patterns) { if (!patterns.includes(pattern)) { patterns.push(pattern); } } } if (patterns.length === 0) { throw new MSLintError('You must provide a glob pattern to lint'); } if (command.verbose !== null) { config.verbose = command.verbose; } if (command.displayStats !== null) { config.displayStats = command.displayStats; } if (command.reportUnusedDisableDirective !== null) { config.reportUnusedDisableDirective = command.reportUnusedDisableDirective; } if (command.reportDisableDirectiveWithoutDescription !== null) { config.reportDisableDirectiveWithoutDescription = command.reportDisableDirectiveWithoutDescription; } const linter = new Linter(config); const result = await linter.lint(patterns); output.info(formatResult(result)); if (result.success) { return 0; } else { return 1; } } export { parseArguments, execute };