"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CheckFailed = exports.run = void 0; const path = require("path"); const commander = require("commander"); // eslint-disable-next-line @typescript-eslint/no-var-requires const npmPackage = require(path.join(__dirname, '..', 'package.json')); const application_1 = require("./application"); const App = require("./application"); const chalk = require("chalk"); // interface InitOptions extends Options {} const templateIssue = `${chalk.green('${uri}')}:${chalk.yellow('${row}:${col}')} - Unknown word (${chalk.red('${text}')})`; const templateIssueLegacy = `${chalk.green('${uri}')}[\${row}, \${col}]: Unknown word: ${chalk.red('${text}')}`; const templateIssueWordsOnly = '${text}'; function genIssueEmitter(template) { return function issueEmitter(issue) { console.log(formatIssue(template, issue)); }; } function errorEmitter(message, error) { console.error(chalk.red(message), error.toString()); } function infoEmitter(message, msgType) { switch (msgType) { case 'Debug': console.info(chalk.cyan(message)); break; case 'Info': console.info(chalk.yellow(message)); break; case 'Progress': console.info(chalk.white(message)); break; } } function debugEmitter(message) { infoEmitter(message, App.MessageTypes.Debug); } function nullEmitter(_) { /* empty */ } async function asyncNullEmitter(_) { /* empty */ } function getEmitters(options) { const issueTemplate = options.wordsOnly ? templateIssueWordsOnly : options.legacy ? templateIssueLegacy : templateIssue; const { silent = false, issues } = options; return { issue: silent || !issues ? nullEmitter : genIssueEmitter(issueTemplate), error: silent ? asyncNullEmitter : errorEmitter, info: silent || !options.verbose ? nullEmitter : infoEmitter, debug: options.debug ? debugEmitter : nullEmitter, }; } async function run(program, argv) { const prog = program || commander; const args = argv || process.argv; prog.exitOverride(); prog.version(npmPackage.version) .description('Spelling Checker for Code') .option('-c, --config ', 'Configuration file to use. By default cspell looks for cspell.json in the current directory.') .option('--no-color', 'Turn off color.') .option('--color', 'Force color'); prog.option('-v, --verbose', 'display more information about the files being checked and the configuration') .option('--local ', 'Set language locals. i.e. "en,fr" for English and French, or "en-GB" for British English.') .option('--language-id ', 'Force programming language for unknown extensions. i.e. "php" or "scala"') .option('--languageId ', 'Force programming language for unknown extensions. i.e. "php" or "scala"') .option('--wordsOnly', 'Only output the words not found in the dictionaries.') .option('-u, --unique', 'Only output the first instance of a word not found in the dictionaries.') .option('--debug', 'Output information useful for debugging cspell.json files.') .option('-e, --exclude ', 'Exclude files matching the glob pattern') .option('--no-issues', 'Do not show the spelling errors.') .option('--no-summary', 'Turn off summary message in console') .option('-s, --silent', 'Silent mode, suppress error messages') .option('-r, --root ', 'Root directory, defaults to current directory.') .option('--must-find-files', 'Error if no files are found', false) .option('--no-must-find-files', 'Do not error is no files are found') // The following options are planned features // .option('-w, --watch', 'Watch for any changes to the matching files and report any errors') // .option('--force', 'Force the exit value to always be 0') .option('--legacy', 'Legacy output') .addHelpText('after', usage) .arguments('[files...]') .action((files, options) => { const { mustFindFiles } = options; const emitters = getEmitters(options); if (!files || !files.length) { prog.help(); return; } return App.lint(files, options, emitters).then((result) => { if (options.summary && !options.silent) { console.error('CSpell: Files checked: %d, Issues found: %d in %d files', result.files, result.issues, result.filesWithIssues.size); } if (result.issues || result.errors || (mustFindFiles && !result.files)) { throw new CheckFailed('check failed', 1); } }); }); prog.command('trace') .description('Trace words') .option('-c, --config ', 'Configuration file to use. By default cspell looks for cspell.json in the current directory.') .option('--local ', 'Set language locals. i.e. "en,fr" for English and French, or "en-GB" for British English.') .option('--languageId ', 'Force programming language for unknown extensions. i.e. "php" or "scala"') .option('--no-color', 'Turn off color.') .option('--color', 'Force color') .arguments('') .action(async (words, options) => { const results = await App.trace(words, options); results.forEach(emitTraceResult); const numFound = results.reduce((n, r) => n + (r.found ? 1 : 0), 0); if (!numFound) { console.error('No matches found'); throw new CheckFailed('no matches', 1); } }); prog.command('check ') .description('Spell check file(s) and display the result. The full file is displayed in color.') .option('-c, --config ', 'Configuration file to use. By default cspell looks for cspell.json in the current directory.') .option('--no-color', 'Turn off color.') .option('--color', 'Force color') .action(async (files, options) => { let issueCount = 0; let fileCount = 0; for (const filename of files) { console.log(chalk.yellowBright(`Check file: ${filename}`)); console.log(); try { fileCount++; const result = await application_1.checkText(filename, options); for (const item of result.items) { const fn = item.flagIE === App.IncludeExcludeFlag.EXCLUDE ? chalk.gray : item.isError ? chalk.red : chalk.whiteBright; const t = fn(item.text); process.stdout.write(t); issueCount += item.isError ? 1 : 0; } console.log(); } catch (e) { console.error(`File not found "${filename}"`); throw new CheckFailed('File not found', 1); } console.log(); } if (issueCount) { throw new CheckFailed('Issues found', 1); } if (!fileCount) { console.error('No files found'); throw new CheckFailed('No files found', 1); } }); /* program .command('init') .description('(Alpha) Initialize a cspell.json file.') .option('-o, --output ', 'define where to write file.') .option('--extends ', 'extend an existing cspell.json file.') .action((options: InitOptions) => { CSpellApplication.createInit(options).then( () => process.exit(0), () => process.exit(1) ); console.log('Init'); }); */ return prog.parseAsync(args).then(() => { return; }); } exports.run = run; const usage = ` Examples: cspell "*.js" Check all .js files in the current directory cspell "**/*.js" Check all .js files from the current directory cspell "src/**/*.js" Only check .js under src cspell "**/*.txt" "**/*.js" Check both .js and .txt files. cat LICENSE | cspell stdin Read from stdin the contents of LICENSE `; function emitTraceResult(r) { const terminalWidth = process.stdout.columns || 120; const widthName = 20; const w = chalk.green(r.word); const f = r.found ? chalk.whiteBright('*') : chalk.dim('-'); const n = chalk.yellowBright(pad(r.dictName, widthName)); const used = [r.word.length, 1, widthName].reduce((a, b) => a + b, 3); const widthSrc = terminalWidth - used; const s = chalk.white(trimMid(r.dictSource, widthSrc)); const line = [w, f, n, s].join(' '); console.log(line); } function pad(s, w) { return (s + ' '.repeat(w)).substr(0, w); } function trimMid(s, w) { if (s.length <= w) { return s; } const l = Math.floor((w - 3) / 2); const r = Math.ceil((w - 3) / 2); return s.substr(0, l) + '...' + s.substr(-r); } function formatIssue(template, issue) { const { uri = '', row, col, text } = issue; return template .replace(/\$\{uri\}/, uri) .replace(/\$\{row\}/, row.toString()) .replace(/\$\{col\}/, col.toString()) .replace(/\$\{text\}/, text); } class CheckFailed extends Error { constructor(message, exitCode = 1) { super(message); this.exitCode = exitCode; } } exports.CheckFailed = CheckFailed; //# sourceMappingURL=app.js.map