cspell 8.7.0 → 8.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +1 -2
  2. package/bin.mjs +1 -1
  3. package/dist/esm/cli-reporter.d.mts +1 -1
  4. package/dist/esm/cli-reporter.d.ts +1 -1
  5. package/dist/esm/cli-reporter.js +54 -5
  6. package/dist/esm/cli-reporter.mjs +54 -5
  7. package/dist/esm/commandCheck.js +1 -1
  8. package/dist/esm/commandCheck.mjs +1 -1
  9. package/dist/esm/commandLint.js +30 -5
  10. package/dist/esm/commandLint.mjs +30 -5
  11. package/dist/esm/commandSuggestion.js +3 -3
  12. package/dist/esm/commandSuggestion.mjs +3 -3
  13. package/dist/esm/emitters/suggestionsEmitter.js +3 -2
  14. package/dist/esm/emitters/suggestionsEmitter.mjs +3 -2
  15. package/dist/esm/emitters/traceEmitter.js +2 -2
  16. package/dist/esm/emitters/traceEmitter.mjs +2 -2
  17. package/dist/esm/featureFlags/featureFlags.js +1 -1
  18. package/dist/esm/featureFlags/featureFlags.mjs +1 -1
  19. package/dist/esm/lint/LintRequest.js +1 -1
  20. package/dist/esm/lint/LintRequest.mjs +1 -1
  21. package/dist/esm/lint/lint.js +10 -8
  22. package/dist/esm/lint/lint.mjs +10 -8
  23. package/dist/esm/options.d.mts +4 -0
  24. package/dist/esm/options.d.ts +4 -0
  25. package/dist/esm/repl/index.js +1 -1
  26. package/dist/esm/repl/index.mjs +1 -1
  27. package/dist/esm/util/cache/DiskCache.js +5 -5
  28. package/dist/esm/util/cache/DiskCache.mjs +5 -5
  29. package/dist/esm/util/cache/ObjectCollection.js +1 -1
  30. package/dist/esm/util/cache/ObjectCollection.mjs +1 -1
  31. package/dist/esm/util/cache/createCache.js +3 -3
  32. package/dist/esm/util/cache/createCache.mjs +3 -3
  33. package/dist/esm/util/cache/fileEntryCache.js +3 -3
  34. package/dist/esm/util/cache/fileEntryCache.mjs +3 -3
  35. package/dist/esm/util/errors.js +1 -1
  36. package/dist/esm/util/errors.mjs +1 -1
  37. package/dist/esm/util/fileHelper.d.mts +2 -2
  38. package/dist/esm/util/fileHelper.d.ts +2 -2
  39. package/dist/esm/util/fileHelper.js +5 -5
  40. package/dist/esm/util/fileHelper.mjs +5 -5
  41. package/dist/esm/util/glob.js +10 -10
  42. package/dist/esm/util/glob.mjs +10 -10
  43. package/dist/esm/util/prefetch.js +3 -4
  44. package/dist/esm/util/prefetch.mjs +3 -4
  45. package/dist/esm/util/stdin.js +1 -1
  46. package/dist/esm/util/stdin.mjs +1 -1
  47. package/dist/esm/util/util.js +2 -2
  48. package/dist/esm/util/util.mjs +2 -2
  49. package/dist/lib/pkgInfo.cjs +0 -1
  50. package/package.json +11 -11
package/README.md CHANGED
@@ -138,7 +138,7 @@ Options:
138
138
  checked and the configuration.
139
139
  --locale <locale> Set language locales. i.e. "en,fr" for English
140
140
  and French, or "en-GB" for British English.
141
- --language-id <language> Force programming language for unknown
141
+ --language-id <file-type> Force programming language for unknown
142
142
  extensions. i.e. "php" or "scala"
143
143
  --words-only Only output the words not found in the
144
144
  dictionaries.
@@ -181,7 +181,6 @@ Options:
181
181
  --gitignore-root <path> Prevent searching for .gitignore files past
182
182
  root.
183
183
  --validate-directives Validate in-document CSpell directives.
184
- --no-validate-directives Do not validate in-document CSpell directives.
185
184
  --no-color Turn off color.
186
185
  --color Force color.
187
186
  --no-default-configuration Do not load the default configuration and
package/bin.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { program, CommanderError } from 'commander';
2
+ import { CommanderError, program } from 'commander';
3
3
 
4
4
  import * as app from './dist/esm/app.mjs';
5
5
 
@@ -4,7 +4,7 @@ import type { FinalizedReporter } from './util/reporters.mjs';
4
4
  export interface ReporterIssue extends Issue {
5
5
  filename: string;
6
6
  }
7
- export interface ReporterOptions extends Pick<LinterCliOptions, 'debug' | 'issues' | 'legacy' | 'progress' | 'relative' | 'root' | 'showContext' | 'showSuggestions' | 'silent' | 'summary' | 'verbose' | 'wordsOnly'> {
7
+ export interface ReporterOptions extends Pick<LinterCliOptions, 'debug' | 'issues' | 'legacy' | 'progress' | 'relative' | 'root' | 'showContext' | 'showPerfSummary' | 'showSuggestions' | 'silent' | 'summary' | 'verbose' | 'wordsOnly'> {
8
8
  fileGlobs: string[];
9
9
  }
10
10
  export declare function getReporter(options: ReporterOptions, config?: ReporterConfiguration): FinalizedReporter;
@@ -4,7 +4,7 @@ import type { FinalizedReporter } from './util/reporters.js';
4
4
  export interface ReporterIssue extends Issue {
5
5
  filename: string;
6
6
  }
7
- export interface ReporterOptions extends Pick<LinterCliOptions, 'debug' | 'issues' | 'legacy' | 'progress' | 'relative' | 'root' | 'showContext' | 'showSuggestions' | 'silent' | 'summary' | 'verbose' | 'wordsOnly'> {
7
+ export interface ReporterOptions extends Pick<LinterCliOptions, 'debug' | 'issues' | 'legacy' | 'progress' | 'relative' | 'root' | 'showContext' | 'showPerfSummary' | 'showSuggestions' | 'silent' | 'summary' | 'verbose' | 'wordsOnly'> {
8
8
  fileGlobs: string[];
9
9
  }
10
10
  export declare function getReporter(options: ReporterOptions, config?: ReporterConfiguration): FinalizedReporter;
@@ -83,6 +83,13 @@ function reportTime(elapsedTimeMs, cached) {
83
83
  return color(elapsedTimeMs.toFixed(2) + 'ms');
84
84
  }
85
85
  export function getReporter(options, config) {
86
+ const perfStats = {
87
+ filesProcessed: 0,
88
+ filesSkipped: 0,
89
+ filesCached: 0,
90
+ elapsedTimeMs: 0,
91
+ perf: Object.create(null),
92
+ };
86
93
  const uniqueIssues = config?.unique || false;
87
94
  const issueTemplate = options.wordsOnly
88
95
  ? templateIssueWordsOnly
@@ -97,7 +104,7 @@ export function getReporter(options, config) {
97
104
  : options.showSuggestions === false
98
105
  ? templateIssueNoFix
99
106
  : templateIssue;
100
- const { fileGlobs, silent, summary, issues, progress, verbose, debug } = options;
107
+ const { fileGlobs, silent, summary, issues, progress: showProgress, verbose, debug } = options;
101
108
  const emitters = {
102
109
  Debug: !silent && debug ? (s) => console.info(chalk.cyan(s)) : nullEmitter,
103
110
  Info: !silent && verbose ? (s) => console.info(chalk.yellow(s)) : nullEmitter,
@@ -118,7 +125,7 @@ export function getReporter(options, config) {
118
125
  fn(r);
119
126
  };
120
127
  }
121
- const issuesCollection = progress ? [] : undefined;
128
+ const issuesCollection = showProgress ? [] : undefined;
122
129
  const errorCollection = [];
123
130
  function errorEmitter(message, error) {
124
131
  if (isSpellingDictionaryLoadError(error)) {
@@ -144,20 +151,62 @@ export function getReporter(options, config) {
144
151
  const cachedFilesText = cachedFiles ? ` (${cachedFiles} from cache)` : '';
145
152
  const withErrorsText = errors ? ` with ${errors} error${errors === 1 ? '' : 's'}` : '';
146
153
  const numFilesWidthIssuesText = numFilesWithIssues === 1 ? '1 file' : `${numFilesWithIssues} files`;
147
- const summaryMessage = `CSpell\x3a Files checked: ${files}${cachedFilesText}, Issues found: ${issues} in ${numFilesWidthIssuesText}${withErrorsText}.`;
154
+ const summaryMessage = `CSpell\u003A Files checked: ${files}${cachedFilesText}, Issues found: ${issues} in ${numFilesWidthIssuesText}${withErrorsText}.`;
148
155
  console.error(summaryMessage);
149
156
  if (errorCollection?.length && issues > 5) {
150
157
  console.error('-------------------------------------------');
151
158
  console.error('Errors:');
152
159
  errorCollection.forEach((error) => console.error(error));
153
160
  }
161
+ if (options.showPerfSummary) {
162
+ console.error('-------------------------------------------');
163
+ console.error('Performance Summary:');
164
+ console.error(` Files Processed: ${perfStats.filesProcessed.toString().padStart(6)}`);
165
+ console.error(` Files Skipped : ${perfStats.filesSkipped.toString().padStart(6)}`);
166
+ console.error(` Files Cached : ${perfStats.filesCached.toString().padStart(6)}`);
167
+ console.error(` Processing Time: ${perfStats.elapsedTimeMs.toFixed(2).padStart(9)}ms`);
168
+ console.error('Stats:');
169
+ const stats = Object.entries(perfStats.perf)
170
+ .filter((p) => !!p[1])
171
+ .map(([key, value]) => [key, value.toFixed(2)]);
172
+ const padName = Math.max(...stats.map((s) => s[0].length));
173
+ const padValue = Math.max(...stats.map((s) => s[1].length));
174
+ stats.sort((a, b) => a[0].localeCompare(b[0]));
175
+ for (const [key, value] of stats) {
176
+ value && console.error(` ${key.padEnd(padName)}: ${value.padStart(padValue)}ms`);
177
+ }
178
+ }
154
179
  };
180
+ function collectPerfStats(p) {
181
+ if (p.cached) {
182
+ perfStats.filesCached++;
183
+ return;
184
+ }
185
+ perfStats.filesProcessed += p.processed ? 1 : 0;
186
+ perfStats.filesSkipped += !p.processed ? 1 : 0;
187
+ perfStats.elapsedTimeMs += p.elapsedTimeMs || 0;
188
+ if (!p.perf)
189
+ return;
190
+ for (const [key, value] of Object.entries(p.perf)) {
191
+ if (typeof value === 'number') {
192
+ perfStats.perf[key] = (perfStats.perf[key] || 0) + value;
193
+ }
194
+ }
195
+ }
196
+ function progress(p) {
197
+ if (!silent && showProgress) {
198
+ reportProgress(p, fsPathRoot);
199
+ }
200
+ if (p.type === 'ProgressFileComplete') {
201
+ collectPerfStats(p);
202
+ }
203
+ }
155
204
  return {
156
205
  issue: relativeIssue(silent || !issues ? nullEmitter : genIssueEmitter(issueTemplate, uniqueIssues, issuesCollection)),
157
206
  error: silent ? nullEmitter : errorEmitter,
158
207
  info: infoEmitter,
159
208
  debug: emitters.Debug,
160
- progress: !silent && progress ? (p) => reportProgress(p, fsPathRoot) : nullEmitter,
209
+ progress,
161
210
  result: !silent && summary ? resultEmitter : nullEmitter,
162
211
  };
163
212
  }
@@ -190,7 +239,7 @@ function formatIssue(templateStr, issue, maxIssueTextWidth) {
190
239
  $uri: uri,
191
240
  $quickFix: formatQuickFix(issue),
192
241
  };
193
- const t = template(templateStr.replace(/\$message/g, message));
242
+ const t = template(templateStr.replaceAll('$message', message));
194
243
  return substitute(chalkTemplate(t), substitutions).trimEnd();
195
244
  }
196
245
  function formatSuggestions(issue) {
@@ -83,6 +83,13 @@ function reportTime(elapsedTimeMs, cached) {
83
83
  return color(elapsedTimeMs.toFixed(2) + 'ms');
84
84
  }
85
85
  export function getReporter(options, config) {
86
+ const perfStats = {
87
+ filesProcessed: 0,
88
+ filesSkipped: 0,
89
+ filesCached: 0,
90
+ elapsedTimeMs: 0,
91
+ perf: Object.create(null),
92
+ };
86
93
  const uniqueIssues = config?.unique || false;
87
94
  const issueTemplate = options.wordsOnly
88
95
  ? templateIssueWordsOnly
@@ -97,7 +104,7 @@ export function getReporter(options, config) {
97
104
  : options.showSuggestions === false
98
105
  ? templateIssueNoFix
99
106
  : templateIssue;
100
- const { fileGlobs, silent, summary, issues, progress, verbose, debug } = options;
107
+ const { fileGlobs, silent, summary, issues, progress: showProgress, verbose, debug } = options;
101
108
  const emitters = {
102
109
  Debug: !silent && debug ? (s) => console.info(chalk.cyan(s)) : nullEmitter,
103
110
  Info: !silent && verbose ? (s) => console.info(chalk.yellow(s)) : nullEmitter,
@@ -118,7 +125,7 @@ export function getReporter(options, config) {
118
125
  fn(r);
119
126
  };
120
127
  }
121
- const issuesCollection = progress ? [] : undefined;
128
+ const issuesCollection = showProgress ? [] : undefined;
122
129
  const errorCollection = [];
123
130
  function errorEmitter(message, error) {
124
131
  if (isSpellingDictionaryLoadError(error)) {
@@ -144,20 +151,62 @@ export function getReporter(options, config) {
144
151
  const cachedFilesText = cachedFiles ? ` (${cachedFiles} from cache)` : '';
145
152
  const withErrorsText = errors ? ` with ${errors} error${errors === 1 ? '' : 's'}` : '';
146
153
  const numFilesWidthIssuesText = numFilesWithIssues === 1 ? '1 file' : `${numFilesWithIssues} files`;
147
- const summaryMessage = `CSpell\x3a Files checked: ${files}${cachedFilesText}, Issues found: ${issues} in ${numFilesWidthIssuesText}${withErrorsText}.`;
154
+ const summaryMessage = `CSpell\u003A Files checked: ${files}${cachedFilesText}, Issues found: ${issues} in ${numFilesWidthIssuesText}${withErrorsText}.`;
148
155
  console.error(summaryMessage);
149
156
  if (errorCollection?.length && issues > 5) {
150
157
  console.error('-------------------------------------------');
151
158
  console.error('Errors:');
152
159
  errorCollection.forEach((error) => console.error(error));
153
160
  }
161
+ if (options.showPerfSummary) {
162
+ console.error('-------------------------------------------');
163
+ console.error('Performance Summary:');
164
+ console.error(` Files Processed: ${perfStats.filesProcessed.toString().padStart(6)}`);
165
+ console.error(` Files Skipped : ${perfStats.filesSkipped.toString().padStart(6)}`);
166
+ console.error(` Files Cached : ${perfStats.filesCached.toString().padStart(6)}`);
167
+ console.error(` Processing Time: ${perfStats.elapsedTimeMs.toFixed(2).padStart(9)}ms`);
168
+ console.error('Stats:');
169
+ const stats = Object.entries(perfStats.perf)
170
+ .filter((p) => !!p[1])
171
+ .map(([key, value]) => [key, value.toFixed(2)]);
172
+ const padName = Math.max(...stats.map((s) => s[0].length));
173
+ const padValue = Math.max(...stats.map((s) => s[1].length));
174
+ stats.sort((a, b) => a[0].localeCompare(b[0]));
175
+ for (const [key, value] of stats) {
176
+ value && console.error(` ${key.padEnd(padName)}: ${value.padStart(padValue)}ms`);
177
+ }
178
+ }
154
179
  };
180
+ function collectPerfStats(p) {
181
+ if (p.cached) {
182
+ perfStats.filesCached++;
183
+ return;
184
+ }
185
+ perfStats.filesProcessed += p.processed ? 1 : 0;
186
+ perfStats.filesSkipped += !p.processed ? 1 : 0;
187
+ perfStats.elapsedTimeMs += p.elapsedTimeMs || 0;
188
+ if (!p.perf)
189
+ return;
190
+ for (const [key, value] of Object.entries(p.perf)) {
191
+ if (typeof value === 'number') {
192
+ perfStats.perf[key] = (perfStats.perf[key] || 0) + value;
193
+ }
194
+ }
195
+ }
196
+ function progress(p) {
197
+ if (!silent && showProgress) {
198
+ reportProgress(p, fsPathRoot);
199
+ }
200
+ if (p.type === 'ProgressFileComplete') {
201
+ collectPerfStats(p);
202
+ }
203
+ }
155
204
  return {
156
205
  issue: relativeIssue(silent || !issues ? nullEmitter : genIssueEmitter(issueTemplate, uniqueIssues, issuesCollection)),
157
206
  error: silent ? nullEmitter : errorEmitter,
158
207
  info: infoEmitter,
159
208
  debug: emitters.Debug,
160
- progress: !silent && progress ? (p) => reportProgress(p, fsPathRoot) : nullEmitter,
209
+ progress,
161
210
  result: !silent && summary ? resultEmitter : nullEmitter,
162
211
  };
163
212
  }
@@ -190,7 +239,7 @@ function formatIssue(templateStr, issue, maxIssueTextWidth) {
190
239
  $uri: uri,
191
240
  $quickFix: formatQuickFix(issue),
192
241
  };
193
- const t = template(templateStr.replace(/\$message/g, message));
242
+ const t = template(templateStr.replaceAll('$message', message));
194
243
  return substitute(chalkTemplate(t), substitutions).trimEnd();
195
244
  }
196
245
  function formatSuggestions(issue) {
@@ -36,7 +36,7 @@ export function commandCheck(prog) {
36
36
  }
37
37
  console.log();
38
38
  }
39
- catch (e) {
39
+ catch {
40
40
  console.error(`File not found "${filename}"`);
41
41
  throw new CheckFailed('File not found', 1);
42
42
  }
@@ -36,7 +36,7 @@ export function commandCheck(prog) {
36
36
  }
37
37
  console.log();
38
38
  }
39
- catch (e) {
39
+ catch {
40
40
  console.error(`File not found "${filename}"`);
41
41
  throw new CheckFailed('File not found', 1);
42
42
  }
@@ -59,8 +59,8 @@ export function commandLint(prog) {
59
59
  .option('-c, --config <cspell.json>', 'Configuration file to use. By default cspell looks for cspell.json in the current directory.')
60
60
  .option('-v, --verbose', 'Display more information about the files being checked and the configuration.')
61
61
  .option('--locale <locale>', 'Set language locales. i.e. "en,fr" for English and French, or "en-GB" for British English.')
62
- .option('--language-id <language>', 'Force programming language for unknown extensions. i.e. "php" or "scala"')
63
- .addOption(crOpt('--languageId <language>', 'Force programming language for unknown extensions. i.e. "php" or "scala"').hideHelp())
62
+ .option('--language-id <file-type>', 'Force programming language for unknown extensions. i.e. "php" or "scala"')
63
+ .addOption(crOpt('--languageId <file-type>', 'Alias of "--language-id". Force programming language for unknown extensions. i.e. "php" or "scala"').hideHelp())
64
64
  .option('--words-only', 'Only output the words not found in the dictionaries.')
65
65
  .addOption(crOpt('--wordsOnly', 'Only output the words not found in the dictionaries.').hideHelp())
66
66
  .option('-u, --unique', 'Only output the first instance of a word not found in the dictionaries.')
@@ -70,7 +70,7 @@ export function commandLint(prog) {
70
70
  ' The list is filtered against the glob file patterns.' +
71
71
  ' Note: the format is 1 file path per line.', collect)
72
72
  .option('--file [file...]', 'Specify files to spell check. They are filtered by the [globs...].', collect)
73
- .addOption(crOpt('--files [file...]', 'Files to spell check.', collect).hideHelp())
73
+ .addOption(crOpt('--files [file...]', 'Alias of "--file". Files to spell check.', collect).hideHelp())
74
74
  .option('--no-issues', 'Do not show the spelling errors.')
75
75
  .option('--no-progress', 'Turn off progress messages')
76
76
  .option('--no-summary', 'Turn off summary message in console.')
@@ -114,7 +114,7 @@ export function commandLint(prog) {
114
114
  .option('--no-gitignore', 'Do NOT use .gitignore files.')
115
115
  .option('--gitignore-root <path>', 'Prevent searching for .gitignore files past root.', collect)
116
116
  .option('--validate-directives', 'Validate in-document CSpell directives.')
117
- .option('--no-validate-directives', 'Do not validate in-document CSpell directives.')
117
+ .addOption(crOpt('--no-validate-directives', 'Do not validate in-document CSpell directives.').hideHelp())
118
118
  .option('--no-color', 'Turn off color.')
119
119
  .option('--color', 'Force color.')
120
120
  .addOption(crOpt('--default-configuration', 'Load the default configuration and dictionaries.').hideHelp())
@@ -125,12 +125,13 @@ export function commandLint(prog) {
125
125
  .implies({ cache: false })
126
126
  .hideHelp())
127
127
  .addOption(crOpt('--issues-summary-report', 'Output a summary of issues found.').hideHelp())
128
+ .addOption(crOpt('--show-perf-summary', 'Output a performance summary report.').hideHelp())
128
129
  // Planned options
129
130
  // .option('--dictionary <dictionary name>', 'Enable a dictionary by name.', collect)
130
131
  // .option('--no-dictionary <dictionary name>', 'Disable a dictionary by name.', collect)
131
132
  // .option('--import', 'Import a configuration file.', collect)
132
133
  .usage(usage)
133
- .addHelpText('after', advanced)
134
+ .addHelpText('after', augmentCommandHelp)
134
135
  .arguments('[globs...]')
135
136
  .action(async (fileGlobs, options) => {
136
137
  // console.error('lint: %o', { fileGlobs, options });
@@ -156,6 +157,30 @@ export function commandLint(prog) {
156
157
  });
157
158
  return spellCheckCommand;
158
159
  }
160
+ /**
161
+ * Add additional help text to the command.
162
+ * When the verbose flag is set, show the hidden options.
163
+ * @param context
164
+ * @returns
165
+ */
166
+ function augmentCommandHelp(context) {
167
+ const output = [];
168
+ const command = context.command;
169
+ const showHidden = !!command.opts().verbose;
170
+ const hiddenHelp = [];
171
+ const help = command.createHelp();
172
+ const hiddenOptions = command.options.filter((opt) => opt.hidden && showHidden);
173
+ const flagColWidth = Math.max(...command.options.map((opt) => opt.flags.length), 0);
174
+ const indent = flagColWidth + 4;
175
+ for (const options of hiddenOptions) {
176
+ if (!hiddenHelp.length) {
177
+ hiddenHelp.push('\nHidden Options:');
178
+ }
179
+ hiddenHelp.push(help.wrap(` ${options.flags.padEnd(flagColWidth)} ${options.description}`, process.stdout.columns || 80, indent));
180
+ }
181
+ output.push(...hiddenHelp, advanced);
182
+ return output.join('\n');
183
+ }
159
184
  /**
160
185
  * Create Option - a helper function to create a commander option.
161
186
  * @param name - the name of the option
@@ -59,8 +59,8 @@ export function commandLint(prog) {
59
59
  .option('-c, --config <cspell.json>', 'Configuration file to use. By default cspell looks for cspell.json in the current directory.')
60
60
  .option('-v, --verbose', 'Display more information about the files being checked and the configuration.')
61
61
  .option('--locale <locale>', 'Set language locales. i.e. "en,fr" for English and French, or "en-GB" for British English.')
62
- .option('--language-id <language>', 'Force programming language for unknown extensions. i.e. "php" or "scala"')
63
- .addOption(crOpt('--languageId <language>', 'Force programming language for unknown extensions. i.e. "php" or "scala"').hideHelp())
62
+ .option('--language-id <file-type>', 'Force programming language for unknown extensions. i.e. "php" or "scala"')
63
+ .addOption(crOpt('--languageId <file-type>', 'Alias of "--language-id". Force programming language for unknown extensions. i.e. "php" or "scala"').hideHelp())
64
64
  .option('--words-only', 'Only output the words not found in the dictionaries.')
65
65
  .addOption(crOpt('--wordsOnly', 'Only output the words not found in the dictionaries.').hideHelp())
66
66
  .option('-u, --unique', 'Only output the first instance of a word not found in the dictionaries.')
@@ -70,7 +70,7 @@ export function commandLint(prog) {
70
70
  ' The list is filtered against the glob file patterns.' +
71
71
  ' Note: the format is 1 file path per line.', collect)
72
72
  .option('--file [file...]', 'Specify files to spell check. They are filtered by the [globs...].', collect)
73
- .addOption(crOpt('--files [file...]', 'Files to spell check.', collect).hideHelp())
73
+ .addOption(crOpt('--files [file...]', 'Alias of "--file". Files to spell check.', collect).hideHelp())
74
74
  .option('--no-issues', 'Do not show the spelling errors.')
75
75
  .option('--no-progress', 'Turn off progress messages')
76
76
  .option('--no-summary', 'Turn off summary message in console.')
@@ -114,7 +114,7 @@ export function commandLint(prog) {
114
114
  .option('--no-gitignore', 'Do NOT use .gitignore files.')
115
115
  .option('--gitignore-root <path>', 'Prevent searching for .gitignore files past root.', collect)
116
116
  .option('--validate-directives', 'Validate in-document CSpell directives.')
117
- .option('--no-validate-directives', 'Do not validate in-document CSpell directives.')
117
+ .addOption(crOpt('--no-validate-directives', 'Do not validate in-document CSpell directives.').hideHelp())
118
118
  .option('--no-color', 'Turn off color.')
119
119
  .option('--color', 'Force color.')
120
120
  .addOption(crOpt('--default-configuration', 'Load the default configuration and dictionaries.').hideHelp())
@@ -125,12 +125,13 @@ export function commandLint(prog) {
125
125
  .implies({ cache: false })
126
126
  .hideHelp())
127
127
  .addOption(crOpt('--issues-summary-report', 'Output a summary of issues found.').hideHelp())
128
+ .addOption(crOpt('--show-perf-summary', 'Output a performance summary report.').hideHelp())
128
129
  // Planned options
129
130
  // .option('--dictionary <dictionary name>', 'Enable a dictionary by name.', collect)
130
131
  // .option('--no-dictionary <dictionary name>', 'Disable a dictionary by name.', collect)
131
132
  // .option('--import', 'Import a configuration file.', collect)
132
133
  .usage(usage)
133
- .addHelpText('after', advanced)
134
+ .addHelpText('after', augmentCommandHelp)
134
135
  .arguments('[globs...]')
135
136
  .action(async (fileGlobs, options) => {
136
137
  // console.error('lint: %o', { fileGlobs, options });
@@ -156,6 +157,30 @@ export function commandLint(prog) {
156
157
  });
157
158
  return spellCheckCommand;
158
159
  }
160
+ /**
161
+ * Add additional help text to the command.
162
+ * When the verbose flag is set, show the hidden options.
163
+ * @param context
164
+ * @returns
165
+ */
166
+ function augmentCommandHelp(context) {
167
+ const output = [];
168
+ const command = context.command;
169
+ const showHidden = !!command.opts().verbose;
170
+ const hiddenHelp = [];
171
+ const help = command.createHelp();
172
+ const hiddenOptions = command.options.filter((opt) => opt.hidden && showHidden);
173
+ const flagColWidth = Math.max(...command.options.map((opt) => opt.flags.length), 0);
174
+ const indent = flagColWidth + 4;
175
+ for (const options of hiddenOptions) {
176
+ if (!hiddenHelp.length) {
177
+ hiddenHelp.push('\nHidden Options:');
178
+ }
179
+ hiddenHelp.push(help.wrap(` ${options.flags.padEnd(flagColWidth)} ${options.description}`, process.stdout.columns || 80, indent));
180
+ }
181
+ output.push(...hiddenHelp, advanced);
182
+ return output.join('\n');
183
+ }
159
184
  /**
160
185
  * Create Option - a helper function to create a commander option.
161
186
  * @param name - the name of the option
@@ -7,13 +7,13 @@ function collect(value, previous) {
7
7
  if (!previous) {
8
8
  return [value];
9
9
  }
10
- return previous.concat([value]);
10
+ return [...previous, value];
11
11
  }
12
12
  function count(_, previous) {
13
13
  return (previous || 0) + 1;
14
14
  }
15
15
  function asNumber(value, prev) {
16
- return parseInt(value, 10) ?? prev;
16
+ return Number.parseInt(value, 10) ?? prev;
17
17
  }
18
18
  export function commandSuggestion(prog) {
19
19
  const suggestionCommand = prog.command('suggestions');
@@ -56,6 +56,6 @@ function mergeArrays(a, b) {
56
56
  return b;
57
57
  if (b === undefined)
58
58
  return a;
59
- return a.concat(b);
59
+ return [...a, ...b];
60
60
  }
61
61
  //# sourceMappingURL=commandSuggestion.js.map
@@ -7,13 +7,13 @@ function collect(value, previous) {
7
7
  if (!previous) {
8
8
  return [value];
9
9
  }
10
- return previous.concat([value]);
10
+ return [...previous, value];
11
11
  }
12
12
  function count(_, previous) {
13
13
  return (previous || 0) + 1;
14
14
  }
15
15
  function asNumber(value, prev) {
16
- return parseInt(value, 10) ?? prev;
16
+ return Number.parseInt(value, 10) ?? prev;
17
17
  }
18
18
  export function commandSuggestion(prog) {
19
19
  const suggestionCommand = prog.command('suggestions');
@@ -56,6 +56,6 @@ function mergeArrays(a, b) {
56
56
  return b;
57
57
  if (b === undefined)
58
58
  return a;
59
- return a.concat(b);
59
+ return [...a, ...b];
60
60
  }
61
61
  //# sourceMappingURL=commandSuggestion.mjs.map
@@ -1,8 +1,9 @@
1
1
  import chalk from 'chalk';
2
2
  import { padLeft, padWidth, width } from '../util/util.js';
3
- const regExpRTL = /([\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC י]+)/g;
3
+ // eslint-disable-next-line no-misleading-character-class
4
+ const regExpRTL = /([ \u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC]+)/g;
4
5
  function reverseRtlText(s) {
5
- return s.replace(regExpRTL, (s) => s.split('').reverse().join(''));
6
+ return s.replaceAll(regExpRTL, (s) => [...s].reverse().join(''));
6
7
  }
7
8
  export function emitSuggestionResult(result, options) {
8
9
  const { word, suggestions } = result;
@@ -1,8 +1,9 @@
1
1
  import chalk from 'chalk';
2
2
  import { padLeft, padWidth, width } from '../util/util.mjs';
3
- const regExpRTL = /([\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC י]+)/g;
3
+ // eslint-disable-next-line no-misleading-character-class
4
+ const regExpRTL = /([ \u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC]+)/g;
4
5
  function reverseRtlText(s) {
5
- return s.replace(regExpRTL, (s) => s.split('').reverse().join(''));
6
+ return s.replaceAll(regExpRTL, (s) => [...s].reverse().join(''));
6
7
  }
7
8
  export function emitSuggestionResult(result, options) {
8
9
  const { word, suggestions } = result;
@@ -1,5 +1,5 @@
1
+ import * as iPath from 'node:path';
1
2
  import chalk from 'chalk';
2
- import * as iPath from 'path';
3
3
  import strip from 'strip-ansi';
4
4
  import { pad, width } from '../util/util.js';
5
5
  const colWidthDictionaryName = 20;
@@ -35,7 +35,7 @@ function emitTraceResult(r, colWidths, options) {
35
35
  const { word: wordColWidth, terminalWidth, dictName: widthName } = colWidths;
36
36
  const errors = r.errors?.map((e) => e.message)?.join('\n\t') || '';
37
37
  const word = pad(r.foundWord || r.word, wordColWidth);
38
- const cWord = word.replace(/[+]/g, chalk.yellow('+'));
38
+ const cWord = word.replaceAll('+', chalk.yellow('+'));
39
39
  const w = r.forbidden ? chalk.red(cWord) : chalk.green(cWord);
40
40
  const f = calcFoundChar(r);
41
41
  const a = r.dictActive ? '*' : ' ';
@@ -1,5 +1,5 @@
1
+ import * as iPath from 'node:path';
1
2
  import chalk from 'chalk';
2
- import * as iPath from 'path';
3
3
  import strip from 'strip-ansi';
4
4
  import { pad, width } from '../util/util.mjs';
5
5
  const colWidthDictionaryName = 20;
@@ -35,7 +35,7 @@ function emitTraceResult(r, colWidths, options) {
35
35
  const { word: wordColWidth, terminalWidth, dictName: widthName } = colWidths;
36
36
  const errors = r.errors?.map((e) => e.message)?.join('\n\t') || '';
37
37
  const word = pad(r.foundWord || r.word, wordColWidth);
38
- const cWord = word.replace(/[+]/g, chalk.yellow('+'));
38
+ const cWord = word.replaceAll('+', chalk.yellow('+'));
39
39
  const w = r.forbidden ? chalk.red(cWord) : chalk.green(cWord);
40
40
  const f = calcFoundChar(r);
41
41
  const a = r.dictActive ? '*' : ' ';
@@ -11,7 +11,7 @@ export function parseFeatureFlags(flags, featureFlags = getFeatureFlags()) {
11
11
  try {
12
12
  featureFlags.setFlag(name, value);
13
13
  }
14
- catch (e) {
14
+ catch {
15
15
  console.warn(`Unknown flag: "${name}"`);
16
16
  }
17
17
  }
@@ -11,7 +11,7 @@ export function parseFeatureFlags(flags, featureFlags = getFeatureFlags()) {
11
11
  try {
12
12
  featureFlags.setFlag(name, value);
13
13
  }
14
- catch (e) {
14
+ catch {
15
15
  console.warn(`Unknown flag: "${name}"`);
16
16
  }
17
17
  }
@@ -1,4 +1,4 @@
1
- import * as path from 'path';
1
+ import * as path from 'node:path';
2
2
  import { calcExcludeGlobInfo } from '../util/glob.js';
3
3
  const defaultContextRange = 20;
4
4
  export class LintRequest {
@@ -1,4 +1,4 @@
1
- import * as path from 'path';
1
+ import * as path from 'node:path';
2
2
  import { calcExcludeGlobInfo } from '../util/glob.mjs';
3
3
  const defaultContextRange = 20;
4
4
  export class LintRequest {