1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.CheckFailed = exports.run = void 0;
|
4 | const path = require("path");
|
5 | const commander = require("commander");
|
6 |
|
7 | const npmPackage = require(path.join(__dirname, '..', 'package.json'));
|
8 | const application_1 = require("./application");
|
9 | const App = require("./application");
|
10 | const chalk = require("chalk");
|
11 |
|
12 | const templateIssue = `${chalk.green('${uri}')}:${chalk.yellow('${row}:${col}')} - Unknown word (${chalk.red('${text}')})`;
|
13 | const templateIssueLegacy = `${chalk.green('${uri}')}[\${row}, \${col}]: Unknown word: ${chalk.red('${text}')}`;
|
14 | const templateIssueWordsOnly = '${text}';
|
15 | function genIssueEmitter(template) {
|
16 | return function issueEmitter(issue) {
|
17 | console.log(formatIssue(template, issue));
|
18 | };
|
19 | }
|
20 | function errorEmitter(message, error) {
|
21 | console.error(chalk.red(message), error.toString());
|
22 | }
|
23 | function infoEmitter(message, msgType) {
|
24 | switch (msgType) {
|
25 | case 'Debug':
|
26 | console.info(chalk.cyan(message));
|
27 | break;
|
28 | case 'Info':
|
29 | console.info(chalk.yellow(message));
|
30 | break;
|
31 | case 'Progress':
|
32 | console.info(chalk.white(message));
|
33 | break;
|
34 | }
|
35 | }
|
36 | function debugEmitter(message) {
|
37 | infoEmitter(message, App.MessageTypes.Debug);
|
38 | }
|
39 | function nullEmitter(_) {
|
40 |
|
41 | }
|
42 | async function asyncNullEmitter(_) {
|
43 |
|
44 | }
|
45 | function getEmitters(options) {
|
46 | const issueTemplate = options.wordsOnly
|
47 | ? templateIssueWordsOnly
|
48 | : options.legacy
|
49 | ? templateIssueLegacy
|
50 | : templateIssue;
|
51 | const { silent = false, issues } = options;
|
52 | return {
|
53 | issue: silent || !issues ? nullEmitter : genIssueEmitter(issueTemplate),
|
54 | error: silent ? asyncNullEmitter : errorEmitter,
|
55 | info: silent || !options.verbose ? nullEmitter : infoEmitter,
|
56 | debug: options.debug ? debugEmitter : nullEmitter,
|
57 | };
|
58 | }
|
59 | async function run(program, argv) {
|
60 | const prog = program || commander;
|
61 | const args = argv || process.argv;
|
62 | prog.passCommandToAction(false);
|
63 | return new Promise((resolve, rejects) => {
|
64 | let showHelp = true;
|
65 | prog.exitOverride();
|
66 | prog.version(npmPackage.version)
|
67 | .description('Spelling Checker for Code')
|
68 | .option('-c, --config <cspell.json>', 'Configuration file to use. By default cspell looks for cspell.json in the current directory.')
|
69 | .option('--no-color', 'Turn off color.')
|
70 | .option('--color', 'Force color');
|
71 | prog.option('-v, --verbose', 'display more information about the files being checked and the configuration')
|
72 | .option('--local <local>', 'Set language locals. i.e. "en,fr" for English and French, or "en-GB" for British English.')
|
73 | .option('--language-id <language>', 'Force programming language for unknown extensions. i.e. "php" or "scala"')
|
74 | .option('--languageId <language>', 'Force programming language for unknown extensions. i.e. "php" or "scala"')
|
75 | .option('--wordsOnly', 'Only output the words not found in the dictionaries.')
|
76 | .option('-u, --unique', 'Only output the first instance of a word not found in the dictionaries.')
|
77 | .option('--debug', 'Output information useful for debugging cspell.json files.')
|
78 | .option('-e, --exclude <glob>', 'Exclude files matching the glob pattern')
|
79 | .option('--no-issues', 'Do not show the spelling errors.')
|
80 | .option('--no-summary', 'Turn off summary message in console')
|
81 | .option('-s, --silent', 'Silent mode, suppress error messages')
|
82 | .option('-r, --root <root folder>', 'Root directory, defaults to current directory.')
|
83 | .option('--must-find-files', 'Error if no files are found', false)
|
84 | .option('--no-must-find-files', 'Do not error is no files are found')
|
85 |
|
86 |
|
87 |
|
88 | .option('--legacy', 'Legacy output')
|
89 | .arguments('<files...>')
|
90 | .action((files, options) => {
|
91 | const { mustFindFiles } = options;
|
92 | const emitters = getEmitters(options);
|
93 | if (!files || !files.length) {
|
94 | return;
|
95 | }
|
96 | showHelp = false;
|
97 | return App.lint(files, options, emitters).then((result) => {
|
98 | if (options.summary && !options.silent) {
|
99 | console.error('CSpell: Files checked: %d, Issues found: %d in %d files', result.files, result.issues, result.filesWithIssues.size);
|
100 | }
|
101 | if (result.issues || result.errors || (mustFindFiles && !result.files)) {
|
102 | throw new CheckFailed('check failed', 1);
|
103 | }
|
104 | });
|
105 | });
|
106 | prog.command('trace')
|
107 | .description('Trace words')
|
108 | .option('-c, --config <cspell.json>', 'Configuration file to use. By default cspell looks for cspell.json in the current directory.')
|
109 | .option('--local <local>', 'Set language locals. i.e. "en,fr" for English and French, or "en-GB" for British English.')
|
110 | .option('--languageId <language>', 'Force programming language for unknown extensions. i.e. "php" or "scala"')
|
111 | .option('--no-color', 'Turn off color.')
|
112 | .option('--color', 'Force color')
|
113 | .arguments('<words...>')
|
114 | .action((words, options) => {
|
115 | showHelp = false;
|
116 | return App.trace(words, options).then((result) => {
|
117 | result.forEach(emitTraceResult);
|
118 | });
|
119 | });
|
120 | prog.command('check <files...>')
|
121 | .description('Spell check file(s) and display the result. The full file is displayed in color.')
|
122 | .option('-c, --config <cspell.json>', 'Configuration file to use. By default cspell looks for cspell.json in the current directory.')
|
123 | .option('--no-color', 'Turn off color.')
|
124 | .option('--color', 'Force color')
|
125 | .action(async (files, options) => {
|
126 | showHelp = false;
|
127 | for (const filename of files) {
|
128 | console.log(chalk.yellowBright(`Check file: ${filename}`));
|
129 | console.log();
|
130 | try {
|
131 | const result = await application_1.checkText(filename, options);
|
132 | for (const item of result.items) {
|
133 | const fn = item.flagIE === App.IncludeExcludeFlag.EXCLUDE
|
134 | ? chalk.gray
|
135 | : item.isError
|
136 | ? chalk.red
|
137 | : chalk.whiteBright;
|
138 | const t = fn(item.text);
|
139 | process.stdout.write(t);
|
140 | }
|
141 | console.log();
|
142 | }
|
143 | catch (e) {
|
144 | console.error(`Failed to read "${filename}"`);
|
145 | }
|
146 | console.log();
|
147 | }
|
148 | });
|
149 | |
150 |
|
151 |
|
152 |
|
153 |
|
154 |
|
155 |
|
156 |
|
157 |
|
158 |
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 | const usage = `
|
165 |
|
166 | Examples:
|
167 | cspell "*.js" Check all .js files in the current directory
|
168 | cspell "**/*.js" Check all .js files from the current directory
|
169 | cspell "src/**/*.js" Only check .js under src
|
170 | cspell "**/*.txt" "**/*.js" Check both .js and .txt files.
|
171 | cat LICENSE | cspell stdin Read from stdin the contents of LICENSE
|
172 | `;
|
173 | prog.on('--help', function () {
|
174 | console.log(usage);
|
175 | showHelp = false;
|
176 | });
|
177 | function reject(e) {
|
178 | if (showHelp) {
|
179 | prog.help();
|
180 | }
|
181 | rejects(e);
|
182 | }
|
183 | try {
|
184 | prog.parseAsync(args)
|
185 | .then(() => {
|
186 | if (showHelp) {
|
187 | prog.help();
|
188 | }
|
189 | resolve();
|
190 | })
|
191 | .catch(reject);
|
192 | }
|
193 | catch (e) {
|
194 | reject(e);
|
195 | }
|
196 | });
|
197 | }
|
198 | exports.run = run;
|
199 | function emitTraceResult(r) {
|
200 | const terminalWidth = process.stdout.columns || 120;
|
201 | const widthName = 20;
|
202 | const w = chalk.green(r.word);
|
203 | const f = r.found ? chalk.whiteBright('*') : chalk.dim('-');
|
204 | const n = chalk.yellowBright(pad(r.dictName, widthName));
|
205 | const used = [r.word.length, 1, widthName].reduce((a, b) => a + b, 3);
|
206 | const widthSrc = terminalWidth - used;
|
207 | const s = chalk.white(trimMid(r.dictSource, widthSrc));
|
208 | const line = [w, f, n, s].join(' ');
|
209 | console.log(line);
|
210 | }
|
211 | function pad(s, w) {
|
212 | return (s + ' '.repeat(w)).substr(0, w);
|
213 | }
|
214 | function trimMid(s, w) {
|
215 | if (s.length <= w) {
|
216 | return s;
|
217 | }
|
218 | const l = Math.floor((w - 3) / 2);
|
219 | const r = Math.ceil((w - 3) / 2);
|
220 | return s.substr(0, l) + '...' + s.substr(-r);
|
221 | }
|
222 | function formatIssue(template, issue) {
|
223 | const { uri = '', row, col, text } = issue;
|
224 | return template
|
225 | .replace(/\$\{uri\}/, uri)
|
226 | .replace(/\$\{row\}/, row.toString())
|
227 | .replace(/\$\{col\}/, col.toString())
|
228 | .replace(/\$\{text\}/, text);
|
229 | }
|
230 | class CheckFailed extends Error {
|
231 | constructor(message, errorCode) {
|
232 | super(message);
|
233 | this.errorCode = errorCode;
|
234 | }
|
235 | }
|
236 | exports.CheckFailed = CheckFailed;
|
237 |
|
\ | No newline at end of file |