cspell 9.3.2 → 9.4.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.
package/README.md CHANGED
@@ -146,7 +146,8 @@ Options:
146
146
  the files being checked. Useful for limiting
147
147
  config inheritance.
148
148
  -v, --verbose Display more information about the files being
149
- checked and the configuration.
149
+ checked. Add more than one -v for increased
150
+ verbosity.
150
151
  --locale <locale> Set language locales. i.e. "en,fr" for English
151
152
  and French, or "en-GB" for British English.
152
153
  --language-id <file-type> Force programming language for unknown
@@ -196,6 +197,8 @@ Options:
196
197
  --gitignore-root <path> Prevent searching for .gitignore files past
197
198
  root.
198
199
  --validate-directives Validate in-document CSpell directives.
200
+ --max-file-size <size> Prevent checking large files. i.e 1MB, 50KB,
201
+ 1GB
199
202
  --color Force color.
200
203
  --no-color Turn off color.
201
204
  --no-default-configuration Do not load the default configuration and
package/dist/esm/app.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { i as LinterCliOptions } from "./options-BeJCICDB.js";
1
+ import { i as LinterCliOptions } from "./options-D_PtlSKK.js";
2
2
  import { Command } from "commander";
3
3
 
4
4
  //#region src/util/errors.d.ts
package/dist/esm/app.js CHANGED
@@ -1,11 +1,9 @@
1
- import { a as parseApplicationFeatureFlags, c as listDictionaries, d as npmPackage, h as console, i as lint, l as ReportChoicesAll, m as CheckFailed, n as checkText, o as suggestions, p as ApplicationError, r as createInit, s as trace, t as IncludeExcludeFlag, u as DEFAULT_CACHE_LOCATION } from "./application-CGIx5L0D.js";
2
- import { Option, program } from "commander";
3
- import { satisfies } from "semver";
4
- import chalk from "chalk";
1
+ import { C as console, S as CheckFailed, _ as unindent, a as parseApplicationFeatureFlags, c as listDictionaries, d as ansiWidth, f as pruneAnsiTextEnd, g as validateUnitSize, h as width, i as lint, l as ReportChoicesAll, m as pruneTextEnd, n as checkText, o as suggestions, p as pruneAnsiTextStart, r as createInit, s as trace, t as IncludeExcludeFlag, u as cvtLinterCliCommandOptionsToLinterCliOptions, v as DEFAULT_CACHE_LOCATION, x as ApplicationError, y as npmPackage } from "./application-DCyfKhGm.js";
5
2
  import { Link } from "cspell-lib";
6
- import assert from "node:assert";
7
- import { stripVTControlCharacters } from "node:util";
3
+ import chalk from "chalk";
8
4
  import * as iPath from "node:path";
5
+ import { Option, program } from "commander";
6
+ import { satisfies } from "semver";
9
7
 
10
8
  //#region src/commandCheck.ts
11
9
  function commandCheck(prog) {
@@ -77,146 +75,6 @@ function padLeft(s, w) {
77
75
  if (!p) return s;
78
76
  return s.padStart(p + s.length);
79
77
  }
80
- function isAnsiString(s) {
81
- return s.includes("\x1B") || s.includes("›");
82
- }
83
- function width(s) {
84
- assert(!s.includes("\x1B"), "String contains ANSI control characters");
85
- return s.replaceAll(/[\u0000-\u001F\u0300-\u036F]/g, "").replaceAll(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, ".").replaceAll("…", ".").replaceAll(/\p{M}/gu, "").length;
86
- }
87
- function ansiWidth(s) {
88
- return width(stripVTControlCharacters(s));
89
- }
90
- /**
91
- * Prune the end of a string to fit within a specified width, adding an ellipsis if necessary.
92
- * @param str - the text to prune - ANSI is not supported
93
- * @param maxWidth - the maximum width of the text
94
- * @param pad - the string to use for padding, default is '…'
95
- * @returns the pruned text
96
- */
97
- function pruneTextEnd(str, maxWidth$2, pad$1 = "…") {
98
- if (!maxWidth$2 || maxWidth$2 <= 0) return str;
99
- if (str.length <= maxWidth$2) return str;
100
- if (isAnsiString(str)) return pruneAnsiTextEnd(str, maxWidth$2, pad$1);
101
- const maxWidthWithPad = maxWidth$2 - width(pad$1);
102
- const letters = [...str];
103
- let len = 0;
104
- for (let i = 0; i < letters.length; i++) {
105
- const c = letters[i];
106
- len += width(c);
107
- if (len > maxWidthWithPad) {
108
- let j = i + 1;
109
- while (j < letters.length && width(letters[j]) === 0) ++j;
110
- return j === letters.length ? str : letters.slice(0, i).join("") + pad$1;
111
- }
112
- }
113
- return str;
114
- }
115
- /**
116
- * Prune the start of a string to fit within a specified width, adding an ellipsis if necessary.
117
- * @param str - the text to prune - ANSI is not supported
118
- * @param maxWidth - the maximum width of the text
119
- * @param pad - the string to use for padding, default is '…'
120
- * @returns the pruned text
121
- */
122
- function pruneTextStart(str, maxWidth$2, pad$1 = "…") {
123
- if (!maxWidth$2 || maxWidth$2 <= 0) return str;
124
- if (str.length <= maxWidth$2) return str;
125
- const maxWidthWithPad = maxWidth$2 - width(pad$1);
126
- const letters = [...str];
127
- let len = 0;
128
- for (let i = letters.length - 1; i >= 1; i--) {
129
- const c = letters[i];
130
- len += width(c);
131
- if (len > maxWidthWithPad) {
132
- i += 1;
133
- while (i < letters.length && width(letters[i]) === 0) ++i;
134
- return pad$1 + letters.slice(i).join("");
135
- }
136
- }
137
- return str;
138
- }
139
- const ansi = new RegExp("[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/\\#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/\\#&.:=?%@~_]*)*)?(?:\\u0007|\\u001B\\u005C|\\u009C))|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))", "g");
140
- function parseAnsiStr(str) {
141
- const fragments = [];
142
- let lastIndex = 0;
143
- for (const match of str.matchAll(ansi)) {
144
- if (match.index > lastIndex) fragments.push({
145
- type: "text",
146
- text: str.slice(lastIndex, match.index)
147
- });
148
- fragments.push({
149
- type: "ansi",
150
- text: match[0]
151
- });
152
- lastIndex = match.index + match[0].length;
153
- }
154
- if (lastIndex < str.length) fragments.push({
155
- type: "text",
156
- text: str.slice(lastIndex)
157
- });
158
- return fragments;
159
- }
160
- /**
161
- * Prune the end of a string to fit within a specified width, adding an ellipsis if necessary.
162
- * @param str - the text to prune - ANSI is supported
163
- * @param maxWidth - the maximum width of the text
164
- * @param pad - the string to use for padding, default is '…'
165
- * @returns the pruned text
166
- */
167
- function pruneAnsiTextEnd(str, maxWidth$2, pad$1 = "…") {
168
- if (!maxWidth$2 || maxWidth$2 <= 0) return str;
169
- if (str.length <= maxWidth$2) return str;
170
- if (ansiWidth(str) <= maxWidth$2) return str;
171
- const padWidth$1 = ansiWidth(pad$1);
172
- const fragments = parseAnsiStr(str);
173
- let remaining = maxWidth$2 - padWidth$1;
174
- for (const frag of fragments) {
175
- if (frag.type !== "text") continue;
176
- if (remaining <= 0) {
177
- frag.text = "";
178
- continue;
179
- }
180
- const pruned = pruneTextEnd(frag.text, remaining, pad$1);
181
- if (pruned !== frag.text) {
182
- frag.text = pruned;
183
- remaining = 0;
184
- continue;
185
- }
186
- remaining -= width(frag.text);
187
- }
188
- return fragments.map((frag) => frag.text).join("");
189
- }
190
- /**
191
- * Prune the start of a string to fit within a specified width, adding an ellipsis if necessary.
192
- * @param str - the text to prune - ANSI is supported
193
- * @param maxWidth - the maximum width of the text
194
- * @param pad - the string to use for padding, default is '…'
195
- * @returns the pruned text
196
- */
197
- function pruneAnsiTextStart(str, maxWidth$2, pad$1 = "…") {
198
- if (!maxWidth$2 || maxWidth$2 <= 0) return str;
199
- if (str.length <= maxWidth$2) return str;
200
- if (ansiWidth(str) <= maxWidth$2) return str;
201
- const padWidth$1 = ansiWidth(pad$1);
202
- const fragments = parseAnsiStr(str);
203
- let remaining = maxWidth$2 - padWidth$1;
204
- for (const frag of fragments.reverse()) {
205
- if (frag.type !== "text") continue;
206
- if (remaining <= 0) {
207
- frag.text = "";
208
- continue;
209
- }
210
- const pruned = pruneTextStart(frag.text, remaining, pad$1);
211
- if (pruned !== frag.text) {
212
- frag.text = pruned;
213
- remaining = 0;
214
- continue;
215
- }
216
- remaining -= width(frag.text);
217
- }
218
- return fragments.reverse().map((frag) => frag.text).join("");
219
- }
220
78
 
221
79
  //#endregion
222
80
  //#region src/util/table.ts
@@ -354,13 +212,13 @@ function trimMid(s, w) {
354
212
  const r = Math.ceil((w - 1) / 2);
355
213
  return s.slice(0, l) + "…" + s.slice(-r);
356
214
  }
357
- function formatDictionaryLocation(dictSource, maxWidth$2, { cwd, dictionaryPathFormat: format$1, iPath: iPath$1 }) {
215
+ function formatDictionaryLocation(dictSource, maxWidth$2, { cwd, dictionaryPathFormat: format, iPath: iPath$1 }) {
358
216
  let relPath = cwd ? iPath$1.relative(cwd, dictSource) : dictSource;
359
217
  const idxNodeModule = relPath.lastIndexOf("node_modules");
360
218
  const isNodeModule = idxNodeModule >= 0;
361
- if (format$1 === "hide") return "";
362
- if (format$1 === "short") return (isNodeModule ? "[node_modules]/" : relPath.startsWith(".." + iPath$1.sep + "..") ? "…/" : relPath.startsWith(".." + iPath$1.sep) ? "../" : "") + iPath$1.basename(dictSource);
363
- if (format$1 === "full") return dictSource;
219
+ if (format === "hide") return "";
220
+ if (format === "short") return (isNodeModule ? "[node_modules]/" : relPath.startsWith(".." + iPath$1.sep + "..") ? "…/" : relPath.startsWith(".." + iPath$1.sep) ? "../" : "") + iPath$1.basename(dictSource);
221
+ if (format === "full") return dictSource;
364
222
  relPath = isNodeModule ? relPath.slice(idxNodeModule) : relPath;
365
223
  return trimMidPath(relPath.length < dictSource.length ? relPath : dictSource, maxWidth$2, iPath$1.sep);
366
224
  }
@@ -555,60 +413,6 @@ function commandLink(prog) {
555
413
  return linkCommand;
556
414
  }
557
415
 
558
- //#endregion
559
- //#region src/util/unindent.ts
560
- /**
561
- * Inject values into a template string.
562
- * @param {TemplateStringsArray} template
563
- * @param {...any} values
564
- * @returns
565
- */
566
- function _inject(template, ...values) {
567
- const strings = template;
568
- const adjValues = [];
569
- for (let i = 0; i < values.length; ++i) {
570
- const prevLines = strings[i].split("\n");
571
- const currLine = prevLines[prevLines.length - 1];
572
- const padLen = padLength(currLine);
573
- const padding = " ".repeat(padLen);
574
- const value = `${values[i]}`;
575
- let pad$1 = "";
576
- const valueLines = [];
577
- for (const line of value.split("\n")) {
578
- valueLines.push(pad$1 + line);
579
- pad$1 = padding;
580
- }
581
- adjValues.push(valueLines.join("\n"));
582
- }
583
- return _unindent(String.raw({ raw: strings }, ...adjValues));
584
- }
585
- /**
586
- * Calculate the padding at the start of the string.
587
- * @param {string} s
588
- * @returns {number}
589
- */
590
- function padLength(s) {
591
- return s.length - s.trimStart().length;
592
- }
593
- function unindent(template, ...values) {
594
- if (typeof template === "string") return _unindent(template);
595
- return _inject(template, ...values);
596
- }
597
- /**
598
- * Remove the left padding from a multi-line string.
599
- * @param {string} str
600
- * @returns {string}
601
- */
602
- function _unindent(str) {
603
- const lines = str.split("\n");
604
- let curPad = str.length;
605
- for (const line of lines) {
606
- if (!line.trim()) continue;
607
- curPad = Math.min(curPad, padLength(line));
608
- }
609
- return lines.map((line) => line.slice(curPad)).join("\n");
610
- }
611
-
612
416
  //#endregion
613
417
  //#region src/commandLint.ts
614
418
  const usage = `\
@@ -661,24 +465,28 @@ References:
661
465
  `;
662
466
  function commandLint(prog, opts) {
663
467
  const spellCheckCommand = prog.command("lint", opts);
664
- spellCheckCommand.description("Check spelling").option("-c, --config <cspell.json>", "Configuration file to use. By default cspell looks for cspell.json in the current directory.").addOption(crOpt("--config-search", "Allow searching for configuration files.", void 0).hideHelp()).option("--no-config-search", "Disable automatic searching for additional configuration files in parent directories. Only the specified config file (if any) will be used.").option("--stop-config-search-at <dir>", "Specify a directory at which to stop searching for configuration files when walking up from the files being checked. Useful for limiting config inheritance.", collect).option("-v, --verbose", "Display more information about the files being checked and the configuration.").option("--locale <locale>", "Set language locales. i.e. \"en,fr\" for English and French, or \"en-GB\" for British English.").option("--language-id <file-type>", "Force programming language for unknown extensions. i.e. \"php\" or \"scala\"").addOption(crOpt("--languageId <file-type>", "Alias of \"--language-id\". Force programming language for unknown extensions. i.e. \"php\" or \"scala\"").hideHelp()).option("--words-only", "Only output the words not found in the dictionaries.").addOption(crOpt("--wordsOnly", "Only output the words not found in the dictionaries.").hideHelp()).option("-u, --unique", "Only output the first instance of a word not found in the dictionaries.").option("-e, --exclude <glob>", "Exclude files matching the glob pattern. This option can be used multiple times to add multiple globs. ", collect).option("--file-list <path or stdin>", "Specify a list of files to be spell checked. The list is filtered against the glob file patterns. Note: the format is 1 file path per line.", collect).option("--file [file...]", "Specify files to spell check. They are filtered by the [globs...].", collect).addOption(crOpt("--files [file...]", "Alias of \"--file\". Files to spell check.", collect).hideHelp()).option("--no-issues", "Do not show the spelling errors.").option("--no-progress", "Turn off progress messages").option("--no-summary", "Turn off summary message in console.").option("-s, --silent", "Silent mode, suppress error messages.").option("--no-exit-code", "Do not return an exit code if issues are found.").addOption(crOpt("--quiet", "Only show spelling issues or errors.").implies({
468
+ spellCheckCommand.description("Check spelling").option("-c, --config <cspell.json>", "Configuration file to use. By default cspell looks for cspell.json in the current directory.").addOption(crOpt("--config-search", "Allow searching for configuration files.", void 0).hideHelp()).option("--no-config-search", "Disable automatic searching for additional configuration files in parent directories. Only the specified config file (if any) will be used.").option("--stop-config-search-at <dir>", "Specify a directory at which to stop searching for configuration files when walking up from the files being checked. Useful for limiting config inheritance.", collect).option("-v, --verbose", "Display more information about the files being checked. Add more than one -v for increased verbosity.", increaseVerbosity, 0).option("--locale <locale>", "Set language locales. i.e. \"en,fr\" for English and French, or \"en-GB\" for British English.").option("--language-id <file-type>", "Force programming language for unknown extensions. i.e. \"php\" or \"scala\"").addOption(crOpt("--languageId <file-type>", "Alias of \"--language-id\". Force programming language for unknown extensions. i.e. \"php\" or \"scala\"").hideHelp()).option("--words-only", "Only output the words not found in the dictionaries.").addOption(crOpt("--wordsOnly", "Only output the words not found in the dictionaries.").hideHelp()).option("-u, --unique", "Only output the first instance of a word not found in the dictionaries.").option("-e, --exclude <glob>", "Exclude files matching the glob pattern. This option can be used multiple times to add multiple globs. ", collect).option("--file-list <path or stdin>", "Specify a list of files to be spell checked. The list is filtered against the glob file patterns. Note: the format is 1 file path per line.", collect).option("--file [file...]", "Specify files to spell check. They are filtered by the [globs...].", collect).addOption(crOpt("--files [file...]", "Alias of \"--file\". Files to spell check.", collect).hideHelp()).option("--no-issues", "Do not show the spelling errors.").option("--no-progress", "Turn off progress messages").option("--no-summary", "Turn off summary message in console.").option("-s, --silent", "Silent mode, suppress error messages.").option("--no-exit-code", "Do not return an exit code if issues are found.").addOption(crOpt("--quiet", "Only show spelling issues or errors.").implies({
665
469
  summary: false,
666
470
  progress: false
667
- })).option("--fail-fast", "Exit after first file with an issue or error.").addOption(crOpt("--no-fail-fast", "Process all files even if there is an error.").hideHelp()).option("--continue-on-error", "Continue processing files even if there is a configuration error.").option("-r, --root <root folder>", "Root directory, defaults to current directory.").addOption(crOpt("--relative", "Issues are displayed relative to the root.").default(true).hideHelp()).option("--no-relative", "Issues are displayed with absolute path instead of relative to the root.").option("--show-context", "Show the surrounding text around an issue.").option("--show-suggestions", "Show spelling suggestions.").addOption(crOpt("--no-show-suggestions", "Do not show spelling suggestions or fixes.").default(void 0)).addOption(crOpt("--must-find-files", "Error if no files are found.").default(true).hideHelp()).option("--no-must-find-files", "Do not error if no files are found.").addOption(crOpt("--legacy", "Legacy output").hideHelp()).addOption(crOpt("--local <local>", "Deprecated -- Use: --locale").hideHelp()).option("--cache", "Use cache to only check changed files.").option("--no-cache", "Do not use cache.").option("--cache-reset", "Reset the cache file.").addOption(crOpt("--cache-strategy <strategy>", "Strategy to use for detecting changed files.").choices(["content", "metadata"]).default("content")).option("--cache-location <path>", `Path to the cache file or directory. (default: "${DEFAULT_CACHE_LOCATION}")`).option("--dot", "Include files and directories starting with `.` (period) when matching globs.").option("--gitignore", "Ignore files matching glob patterns found in .gitignore files.").option("--no-gitignore", "Do NOT use .gitignore files.").option("--gitignore-root <path>", "Prevent searching for .gitignore files past root.", collect).option("--validate-directives", "Validate in-document CSpell directives.").addOption(crOpt("--no-validate-directives", "Do not validate in-document CSpell directives.").hideHelp()).addOption(crOpt("--color", "Force color.").default(void 0)).addOption(crOpt("--no-color", "Turn off color.").default(void 0)).addOption(crOpt("--default-configuration", "Load the default configuration and dictionaries.").hideHelp()).addOption(crOpt("--no-default-configuration", "Do not load the default configuration and dictionaries.")).option("--dictionary <name>", "Enable a dictionary by name.", collect).option("--disable-dictionary <name>", "Disable a dictionary by name.", collect).option("--reporter <module|path>", "Specify one or more reporters to use.", collect).addOption(crOpt("--report <level>", "Set how unknown words are reported").choices(ReportChoicesAll)).addOption(crOpt("--skip-validation", "Collect and process documents, but do not spell check.").implies({ cache: false }).hideHelp()).addOption(crOpt("--issues-summary-report", "Output a summary of issues found.").hideHelp()).addOption(crOpt("--show-perf-summary", "Output a performance summary report.").hideHelp()).option("--issue-template [template]", "Use a custom issue template. See --help --issue-template for details.").addOption(crOpt("--debug", "Output information useful for debugging cspell.json files.").hideHelp()).usage(usage).addHelpText("after", augmentCommandHelp).arguments("[globs...]").action(async (fileGlobs, options) => {
668
- const useExitCode = options.exitCode ?? true;
669
- if (options.skipValidation) options.cache = false;
670
- options.color ??= canUseColor(options.color);
671
- const { mustFindFiles, fileList, files, file } = options;
672
- const result = await lint(fileGlobs, options);
673
- if (!fileGlobs.length && !result.files && !result.errors && !fileList && !files?.length && !file?.length) {
674
- spellCheckCommand.outputHelp();
675
- throw new CheckFailed("outputHelp", 1);
676
- }
677
- if (result.errors || mustFindFiles && !result.files) throw new CheckFailed("check failed", 1);
678
- if (result.issues) throw new CheckFailed("check failed", useExitCode ? 1 : 0);
679
- });
471
+ })).option("--fail-fast", "Exit after first file with an issue or error.").addOption(crOpt("--no-fail-fast", "Process all files even if there is an error.").hideHelp()).option("--continue-on-error", "Continue processing files even if there is a configuration error.").option("-r, --root <root folder>", "Root directory, defaults to current directory.").addOption(crOpt("--relative", "Issues are displayed relative to the root.").default(true).hideHelp()).option("--no-relative", "Issues are displayed with absolute path instead of relative to the root.").option("--show-context", "Show the surrounding text around an issue.").option("--show-suggestions", "Show spelling suggestions.").addOption(crOpt("--no-show-suggestions", "Do not show spelling suggestions or fixes.").default(void 0)).addOption(crOpt("--must-find-files", "Error if no files are found.").default(true).hideHelp()).option("--no-must-find-files", "Do not error if no files are found.").addOption(crOpt("--legacy", "Legacy output").hideHelp()).addOption(crOpt("--local <local>", "Deprecated -- Use: --locale").hideHelp()).option("--cache", "Use cache to only check changed files.").option("--no-cache", "Do not use cache.").option("--cache-reset", "Reset the cache file.").addOption(crOpt("--cache-strategy <strategy>", "Strategy to use for detecting changed files.").choices(["content", "metadata"]).default("content")).option("--cache-location <path>", `Path to the cache file or directory. (default: "${DEFAULT_CACHE_LOCATION}")`).option("--dot", "Include files and directories starting with `.` (period) when matching globs.").option("--gitignore", "Ignore files matching glob patterns found in .gitignore files.").option("--no-gitignore", "Do NOT use .gitignore files.").option("--gitignore-root <path>", "Prevent searching for .gitignore files past root.", collect).option("--validate-directives", "Validate in-document CSpell directives.").addOption(crOpt("--no-validate-directives", "Do not validate in-document CSpell directives.").hideHelp()).option("--max-file-size <size>", "Prevent checking large files. i.e 1MB, 50KB, 1GB").addOption(crOpt("--color", "Force color.").default(void 0)).addOption(crOpt("--no-color", "Turn off color.").default(void 0)).addOption(crOpt("--default-configuration", "Load the default configuration and dictionaries.").hideHelp()).addOption(crOpt("--no-default-configuration", "Do not load the default configuration and dictionaries.")).option("--dictionary <name>", "Enable a dictionary by name.", collect).option("--disable-dictionary <name>", "Disable a dictionary by name.", collect).option("--reporter <module|path>", "Specify one or more reporters to use.", collect).addOption(crOpt("--report <level>", "Set how unknown words are reported").choices(ReportChoicesAll)).addOption(crOpt("--skip-validation", "Collect and process documents, but do not spell check.").implies({ cache: false }).hideHelp()).addOption(crOpt("--issues-summary-report", "Output a summary of issues found.").hideHelp()).addOption(crOpt("--show-perf-summary", "Output a performance summary report.").hideHelp()).option("--issue-template [template]", "Use a custom issue template. See --help --issue-template for details.").addOption(crOpt("--debug", "Output information useful for debugging cspell.json files.").hideHelp()).usage(usage).addHelpText("after", augmentCommandHelp).arguments("[globs...]").action(action);
680
472
  return spellCheckCommand;
681
473
  }
474
+ async function action(fileGlobs, cliOptions) {
475
+ const options = cvtLinterCliCommandOptionsToLinterCliOptions(cliOptions);
476
+ const useExitCode = options.exitCode ?? true;
477
+ if (options.skipValidation) options.cache = false;
478
+ options.color ??= canUseColor(options.color);
479
+ const maxFileSizeErr = validateMaxFileSize(options.maxFileSize);
480
+ if (maxFileSizeErr) this.error(`error: invalid option value for --max-file-size: ${maxFileSizeErr}`);
481
+ const { mustFindFiles, fileList, files, file } = options;
482
+ const result = await lint(fileGlobs, options);
483
+ if (!fileGlobs.length && !result.files && !result.errors && !fileList && !files?.length && !file?.length) {
484
+ this.outputHelp();
485
+ throw new CheckFailed("outputHelp", 1);
486
+ }
487
+ if (result.errors || mustFindFiles && !result.files) throw new CheckFailed("check failed", 1);
488
+ if (result.issues) throw new CheckFailed("check failed", useExitCode ? 1 : 0);
489
+ }
682
490
  function helpIssueTemplate(opts) {
683
491
  if (!("issueTemplate" in opts)) return "";
684
492
  return unindent`
@@ -733,6 +541,13 @@ function augmentCommandHelp(context) {
733
541
  output.push(...hiddenHelp, advanced);
734
542
  return helpIssueTemplate(opts) + output.join("\n");
735
543
  }
544
+ function validateMaxFileSize(size) {
545
+ if (!size) return void 0;
546
+ return validateUnitSize(size);
547
+ }
548
+ function increaseVerbosity(_dummyValue, previous) {
549
+ return previous + 1;
550
+ }
736
551
 
737
552
  //#endregion
738
553
  //#region src/emitters/suggestionsEmitter.ts
@@ -1,4 +1,4 @@
1
- import { a as SuggestionOptions, i as LinterCliOptions, n as DictionariesOptions, o as TraceOptions, r as LegacyOptions, t as BaseOptions } from "./options-BeJCICDB.js";
1
+ import { a as SuggestionOptions, i as LinterCliOptions, n as DictionariesOptions, o as TraceOptions, r as LegacyOptions, t as BaseOptions } from "./options-D_PtlSKK.js";
2
2
  import { CheckTextInfo, FeatureFlags, IncludeExcludeFlag, SuggestionsForWordResult, TraceResult, TraceWordResult } from "cspell-lib";
3
3
  import { CSpellReporter, RunResult } from "@cspell/cspell-types";
4
4
 
@@ -113,4 +113,4 @@ declare function createInit(options: InitOptions): Promise<void>;
113
113
  declare function parseApplicationFeatureFlags(flags: string[] | undefined): FeatureFlags;
114
114
  //#endregion
115
115
  export { checkText as a, parseApplicationFeatureFlags as c, listDictionaries as d, TraceResult as i, suggestions as l, CheckTextResult as n, createInit as o, IncludeExcludeFlag as r, lint as s, AppError as t, trace as u };
116
- //# sourceMappingURL=application-B84gvlDU.d.ts.map
116
+ //# sourceMappingURL=application-Ce_s5c1d.d.ts.map
@@ -1,11 +1,11 @@
1
1
  import { createRequire } from "node:module";
2
- import chalk, { Chalk } from "chalk";
3
2
  import { isAsyncIterable, opFilter, opMap, opTap, operators, pipeAsync, pipeAsync as asyncPipe, toAsyncIterable, toAsyncIterable as mergeAsyncIterables } from "@cspell/cspell-pipe";
4
3
  import * as cspell from "cspell-lib";
5
4
  import { ENV_CSPELL_GLOB_ROOT, IncludeExcludeFlag, SuggestionError, Text, checkTextDocument, combineTextAndLanguageSettings, createPerfTimer, extractDependencies, extractImportErrors, fileToDocument, getDefaultSettings, getDictionary, getGlobalSettingsAsync, getSystemFeatureFlags, isBinaryFile, isSpellingDictionaryLoadError, mergeSettings, setLogger, shouldCheckDocument, spellCheckDocument, suggestionsForWords, traceWordsAsync } from "cspell-lib";
6
5
  import assert from "node:assert";
7
- import { format, formatWithOptions } from "node:util";
6
+ import { format, formatWithOptions, stripVTControlCharacters } from "node:util";
8
7
  import { isUrlLike, toFileDirURL, toFilePathOrHref, toFileURL, urlRelative } from "@cspell/url";
8
+ import chalk, { Chalk } from "chalk";
9
9
  import { makeTemplate } from "chalk-template";
10
10
  import fs, { stat } from "node:fs/promises";
11
11
  import { MutableCSpellConfigFile, createReaderWriter, cspellConfigFileSchema, isCfgArrayNode } from "cspell-config-lib";
@@ -20,11 +20,12 @@ import { GitIgnore, findRepoRoot } from "cspell-gitignore";
20
20
  import { GlobMatcher, fileOrGlobToGlob, workaroundPicomatchBug } from "cspell-glob";
21
21
  import crypto from "node:crypto";
22
22
  import streamConsumers from "node:stream/consumers";
23
- import { readFileText, toURL } from "cspell-io";
23
+ import { getStat, readFileText, toURL } from "cspell-io";
24
24
  import { glob } from "tinyglobby";
25
25
  import * as readline from "node:readline";
26
26
  import { parse, stringify } from "flatted";
27
27
  import { dynamicImport } from "@cspell/dynamic-import";
28
+ import ansiRegex from "ansi-regex";
28
29
 
29
30
  //#region src/console.ts
30
31
  var ImplChannel = class {
@@ -199,9 +200,10 @@ function reportProgressFileComplete(io, p, cwd, options) {
199
200
  const { idx, filename } = determineFilename(io, p, cwd);
200
201
  const { verbose, debug } = options;
201
202
  const time = reportTime(io, p.elapsedTimeMs, !!p.cached);
202
- const skipped = p.processed === false ? " skipped" : "";
203
+ const skippedReason = p.skippedReason ? ` (${p.skippedReason})` : "";
204
+ const skipped = p.processed === false ? ` skipped${skippedReason}` : "";
203
205
  const hasErrors = p.numErrors ? io.chalk.red` X` : "";
204
- const msg = `${idx} ${filename} ${time}${skipped}${hasErrors}${(skipped && (verbose || debug) || hasErrors || isSlow(p.elapsedTimeMs) || io.getColorLevel() < 1 ? "\n" : "") || "\r"}`;
206
+ const msg = `${idx} ${filename} ${time}${skipped}${hasErrors}${(verbose || debug || hasErrors || isSlow(p.elapsedTimeMs) || io.getColorLevel() < 1 ? "\n" : "") || "\r"}`;
205
207
  io.write(msg);
206
208
  }
207
209
  function reportTime(io, elapsedTimeMs, cached) {
@@ -275,7 +277,7 @@ function getReporter(options, config) {
275
277
  }
276
278
  const resultEmitter = (result) => {
277
279
  if (!fileGlobs.length && !result.files) return;
278
- const { files, issues: issues$1, cachedFiles, filesWithIssues, errors } = result;
280
+ const { files, issues: issues$1, cachedFiles, filesWithIssues, errors, skippedFiles } = result;
279
281
  const numFilesWithIssues = filesWithIssues.size;
280
282
  if (stderr.getColorLevel() > 0) {
281
283
  stderr.write("\r");
@@ -286,9 +288,11 @@ function getReporter(options, config) {
286
288
  consoleError("Issues found:");
287
289
  issuesCollection.forEach((issue) => consoleError(issue));
288
290
  }
291
+ const filesChecked = files - (skippedFiles || 0);
289
292
  const cachedFilesText = cachedFiles ? ` (${cachedFiles} from cache)` : "";
293
+ const skippedFilesText = skippedFiles ? `, skipped: ${skippedFiles}` : "";
290
294
  const withErrorsText = errors ? ` with ${errors} error${errors === 1 ? "" : "s"}` : "";
291
- consoleError(`CSpell\u003A Files checked: ${files}${cachedFilesText}, Issues found: ${issues$1} in ${numFilesWithIssues === 1 ? "1 file" : `${numFilesWithIssues} files`}${withErrorsText}.`);
295
+ consoleError(`CSpell\u003A Files checked: ${filesChecked}${cachedFilesText}${skippedFilesText}, Issues found: ${issues$1} in ${numFilesWithIssues === 1 ? "1 file" : `${numFilesWithIssues} files`}${withErrorsText}.`);
292
296
  if (errorCollection?.length && issues$1 > 5) {
293
297
  consoleError("-------------------------------------------");
294
298
  consoleError("Errors:");
@@ -766,7 +770,7 @@ const pkgDir = _dirname;
766
770
  //#endregion
767
771
  //#region src/pkgInfo.ts
768
772
  const name = "cspell";
769
- const version$1 = "9.3.2";
773
+ const version$1 = "9.4.0";
770
774
  const engines = { node: ">=20" };
771
775
  const npmPackage = {
772
776
  name,
@@ -999,6 +1003,11 @@ function readFileInfo(filename, encoding = UTF8, handleNotFound = false) {
999
1003
  }) : Promise.reject(new IOError(`Error reading file: "${filename}"`, error));
1000
1004
  });
1001
1005
  }
1006
+ async function getFileSize(filename) {
1007
+ const s = await getStat(filename);
1008
+ if (!(s instanceof Error)) return s.size;
1009
+ throw s;
1010
+ }
1002
1011
  function readFile(filename, encoding = UTF8) {
1003
1012
  return readFileInfo(filename, encoding).then((info) => info.text);
1004
1013
  }
@@ -1376,7 +1385,7 @@ var DiskCache = class {
1376
1385
  cached
1377
1386
  };
1378
1387
  }
1379
- async setCachedLintResults({ fileInfo, elapsedTimeMs: _, cached: __,...result }, dependsUponFiles) {
1388
+ async setCachedLintResults({ fileInfo, elapsedTimeMs: _, cached: __, ...result }, dependsUponFiles) {
1380
1389
  const fileDescriptor = await this.fileEntryCache.getFileDescriptor(fileInfo.filename);
1381
1390
  const meta = fileDescriptor.meta;
1382
1391
  if (fileDescriptor.notFound || !meta) return;
@@ -1397,7 +1406,7 @@ var DiskCache = class {
1397
1406
  this.ocCacheFileResult = new ShallowObjectCollection();
1398
1407
  }
1399
1408
  normalizeResult(result) {
1400
- const { issues, processed, errors, configErrors, reportIssueOptions,...rest } = result;
1409
+ const { issues, processed, errors, configErrors, reportIssueOptions, ...rest } = result;
1401
1410
  if (!Object.keys(rest).length) return this.ocCacheFileResult.get(result);
1402
1411
  return this.ocCacheFileResult.get({
1403
1412
  issues,
@@ -1852,6 +1861,7 @@ var LintReporter = class {
1852
1861
  filename,
1853
1862
  elapsedTimeMs: result.elapsedTimeMs,
1854
1863
  processed: result.processed,
1864
+ skippedReason: result.skippedReason,
1855
1865
  numErrors: numIssues || result.errors,
1856
1866
  cached: result.cached,
1857
1867
  perf: result.perf,
@@ -1872,6 +1882,300 @@ function getTimeMeasurer() {
1872
1882
  return () => timer.elapsed;
1873
1883
  }
1874
1884
 
1885
+ //#endregion
1886
+ //#region src/util/unindent.ts
1887
+ /**
1888
+ * Indent each line of a multi-line string.
1889
+ * @param str - multi-line string to left pad
1890
+ * @param padding - the padding to use for all lines except the first.
1891
+ * @param firstLinePadding - optional padding of first line.
1892
+ * @returns
1893
+ */
1894
+ function indent(str, padding, firstLinePadding = "") {
1895
+ let pad = firstLinePadding;
1896
+ const lines = [];
1897
+ for (const line of str.split("\n")) {
1898
+ lines.push(pad + line);
1899
+ pad = padding;
1900
+ }
1901
+ return lines.join("\n");
1902
+ }
1903
+ /**
1904
+ * Inject values into a template string while keeping indentation of multi-line values.
1905
+ * @param template - template string
1906
+ * @param values- values to inject
1907
+ * @returns the injected string
1908
+ */
1909
+ function keepIndent(template, ...values) {
1910
+ const strings = template;
1911
+ const adjValues = [];
1912
+ for (let i = 0; i < values.length; ++i) {
1913
+ const prevLines = strings[i].split("\n");
1914
+ const currLine = prevLines[prevLines.length - 1];
1915
+ const padLen = padLength(currLine);
1916
+ const padding = " ".repeat(padLen);
1917
+ adjValues.push(indent(`${values[i]}`, padding));
1918
+ }
1919
+ return String.raw({ raw: strings }, ...adjValues);
1920
+ }
1921
+ /**
1922
+ * Calculate the padding at the start of the string.
1923
+ * @param s - string to evaluate
1924
+ * @returns number of padding characters
1925
+ */
1926
+ function padLength(s) {
1927
+ return s.length - s.trimStart().length;
1928
+ }
1929
+ function unindent(templateOrString, ...values) {
1930
+ return unindentString(typeof templateOrString === "string" ? templateOrString : keepIndent(templateOrString, ...values));
1931
+ }
1932
+ function unindentString(str) {
1933
+ const lines = str.split("\n");
1934
+ let curPad = str.length;
1935
+ for (const line of lines) {
1936
+ if (!line.trim()) continue;
1937
+ curPad = Math.min(curPad, padLength(line));
1938
+ }
1939
+ return lines.map((line) => line.slice(curPad)).join("\n");
1940
+ }
1941
+
1942
+ //#endregion
1943
+ //#region src/util/unitNumbers.ts
1944
+ const regexUnitNumber = /^((?:\d+(?:\.\d*)?)|(?:\.\d+))([a-z]*)$/i;
1945
+ const unitSizes = {
1946
+ "": 1,
1947
+ b: 1,
1948
+ k: 1024,
1949
+ kb: 1024,
1950
+ m: 1 << 20,
1951
+ mb: 1 << 20,
1952
+ g: 1 << 30,
1953
+ gb: 1 << 30
1954
+ };
1955
+ function parseUnitSize(size) {
1956
+ const match = size.match(regexUnitNumber);
1957
+ const digits = match?.[1] || "";
1958
+ const units = (match?.[2] || "").toLowerCase();
1959
+ if (!match) return {
1960
+ size,
1961
+ digits,
1962
+ units,
1963
+ error: "Invalid size."
1964
+ };
1965
+ if (!units || units in unitSizes) return {
1966
+ size,
1967
+ digits,
1968
+ units
1969
+ };
1970
+ return {
1971
+ size,
1972
+ digits,
1973
+ units,
1974
+ error: `Unknown units. Valid units are: ${Object.keys(unitSizes).filter(Boolean).join(", ").toUpperCase()}.`
1975
+ };
1976
+ }
1977
+ function validateUnitSize(size) {
1978
+ return parseUnitSize(size).error;
1979
+ }
1980
+ function sizeToNumber(size) {
1981
+ const p = parseUnitSize(size);
1982
+ if (p.error) return NaN;
1983
+ return Number.parseFloat(p.digits) * (unitSizes[p.units] || 1);
1984
+ }
1985
+
1986
+ //#endregion
1987
+ //#region src/util/ansi.ts
1988
+ function isAnsiString(s) {
1989
+ return s.includes("\x1B") || s.includes("›");
1990
+ }
1991
+ /**
1992
+ *
1993
+ * @param s - the string to measure - should NOT contains ANSI codes
1994
+ * @param tabWidth -
1995
+ * @returns
1996
+ */
1997
+ function width(s, tabWidth = 1) {
1998
+ return s.replaceAll("…", ".").replaceAll(" ", " ".repeat(tabWidth)).replaceAll(/\p{M}/gu, "").replaceAll(/\p{L}/gu, ".").replaceAll(/[\u0000-\u001F\u0300-\u036F]/g, "").replaceAll(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, ".").length;
1999
+ }
2000
+ /**
2001
+ * Measure the width of a string containing ANSI control characters.
2002
+ * @param s - string to measure with width in characters.
2003
+ * @returns the approximate number of screen characters.
2004
+ */
2005
+ function ansiWidth(s) {
2006
+ return width(stripVTControlCharacters(s));
2007
+ }
2008
+ function fragmentString(str, splitOnRegex, sType) {
2009
+ const fragments = [];
2010
+ let lastIndex = 0;
2011
+ for (const match of str.matchAll(new RegExp(splitOnRegex))) {
2012
+ if (match.index > lastIndex) fragments.push({
2013
+ type: "text",
2014
+ text: str.slice(lastIndex, match.index)
2015
+ });
2016
+ fragments.push({
2017
+ type: sType,
2018
+ text: match[0]
2019
+ });
2020
+ lastIndex = match.index + match[0].length;
2021
+ }
2022
+ if (lastIndex < str.length) fragments.push({
2023
+ type: "text",
2024
+ text: str.slice(lastIndex)
2025
+ });
2026
+ return fragments;
2027
+ }
2028
+ const ansi = ansiRegex();
2029
+ function parseAnsiStr(str) {
2030
+ return fragmentString(str, ansi, "ansi");
2031
+ }
2032
+ /**
2033
+ * Prune the end of a string to fit within a specified width, adding an ellipsis if necessary.
2034
+ * @param str - the text to prune - ANSI is supported
2035
+ * @param maxWidth - the maximum width of the text
2036
+ * @param pad - the string to use for padding, default is '…'
2037
+ * @returns the pruned text
2038
+ */
2039
+ function pruneAnsiTextEnd(str, maxWidth, pad = "…") {
2040
+ if (!maxWidth || maxWidth <= 0) return str;
2041
+ if (str.length <= maxWidth) return str;
2042
+ if (ansiWidth(str) <= maxWidth) return str;
2043
+ const padWidth = ansiWidth(pad);
2044
+ const fragments = parseAnsiStr(str);
2045
+ let remaining = maxWidth - padWidth;
2046
+ for (const frag of fragments) {
2047
+ if (frag.type !== "text") continue;
2048
+ if (remaining <= 0) {
2049
+ frag.text = "";
2050
+ continue;
2051
+ }
2052
+ const pruned = pruneTextEnd(frag.text, remaining, pad);
2053
+ if (pruned !== frag.text) {
2054
+ frag.text = pruned;
2055
+ remaining = 0;
2056
+ continue;
2057
+ }
2058
+ remaining -= width(frag.text);
2059
+ }
2060
+ return fragments.map((frag) => frag.text).join("");
2061
+ }
2062
+ /**
2063
+ * Prune the start of a string to fit within a specified width, adding an ellipsis if necessary.
2064
+ * @param str - the text to prune - ANSI is supported
2065
+ * @param maxWidth - the maximum width of the text
2066
+ * @param pad - the string to use for padding, default is '…'
2067
+ * @returns the pruned text
2068
+ */
2069
+ function pruneAnsiTextStart(str, maxWidth, pad = "…") {
2070
+ if (!maxWidth || maxWidth <= 0) return str;
2071
+ if (str.length <= maxWidth) return str;
2072
+ if (ansiWidth(str) <= maxWidth) return str;
2073
+ const padWidth = ansiWidth(pad);
2074
+ const fragments = parseAnsiStr(str);
2075
+ let remaining = maxWidth - padWidth;
2076
+ for (const frag of fragments.reverse()) {
2077
+ if (frag.type !== "text") continue;
2078
+ if (remaining <= 0) {
2079
+ frag.text = "";
2080
+ continue;
2081
+ }
2082
+ const pruned = pruneTextStart(frag.text, remaining, pad);
2083
+ if (pruned !== frag.text) {
2084
+ frag.text = pruned;
2085
+ remaining = 0;
2086
+ continue;
2087
+ }
2088
+ remaining -= width(frag.text);
2089
+ }
2090
+ return fragments.reverse().map((frag) => frag.text).join("");
2091
+ }
2092
+ /**
2093
+ * Prune the end of a string to fit within a specified width, adding an ellipsis if necessary.
2094
+ * @param str - the text to prune - ANSI is not supported
2095
+ * @param maxWidth - the maximum width of the text
2096
+ * @param pad - the string to use for padding, default is '…'
2097
+ * @returns the pruned text
2098
+ */
2099
+ function pruneTextEnd(str, maxWidth, pad = "…") {
2100
+ if (!maxWidth || maxWidth <= 0) return str;
2101
+ if (str.length <= maxWidth) return str;
2102
+ if (isAnsiString(str)) return pruneAnsiTextEnd(str, maxWidth, pad);
2103
+ const maxWidthWithPad = maxWidth - width(pad);
2104
+ const letters = [...str];
2105
+ let len = 0;
2106
+ for (let i = 0; i < letters.length; i++) {
2107
+ const c = letters[i];
2108
+ len += width(c);
2109
+ if (len > maxWidthWithPad) {
2110
+ let j = i + 1;
2111
+ while (j < letters.length && width(letters[j]) === 0) ++j;
2112
+ return j === letters.length ? str : letters.slice(0, i).join("") + pad;
2113
+ }
2114
+ }
2115
+ return str;
2116
+ }
2117
+ /**
2118
+ * Prune the start of a string to fit within a specified width, adding an ellipsis if necessary.
2119
+ * @param str - the text to prune - ANSI is not supported
2120
+ * @param maxWidth - the maximum width of the text
2121
+ * @param pad - the string to use for padding, default is '…'
2122
+ * @returns the pruned text
2123
+ */
2124
+ function pruneTextStart(str, maxWidth, pad = "…") {
2125
+ if (!maxWidth || maxWidth <= 0) return str;
2126
+ if (str.length <= maxWidth) return str;
2127
+ const maxWidthWithPad = maxWidth - width(pad);
2128
+ const letters = [...str];
2129
+ let len = 0;
2130
+ for (let i = letters.length - 1; i >= 1; i--) {
2131
+ const c = letters[i];
2132
+ len += width(c);
2133
+ if (len > maxWidthWithPad) {
2134
+ i += 1;
2135
+ while (i < letters.length && width(letters[i]) === 0) ++i;
2136
+ return pad + letters.slice(i).join("");
2137
+ }
2138
+ }
2139
+ return str;
2140
+ }
2141
+
2142
+ //#endregion
2143
+ //#region src/util/wrap.ts
2144
+ const wrapSep = /\s+|(?<=,)|\.(?=\w)/g;
2145
+ function wordWrapAnsiText(str, maxWidth, indent$1 = "", sep$1 = wrapSep) {
2146
+ if (!maxWidth || maxWidth <= 0) return str;
2147
+ if (str.length <= maxWidth) return str;
2148
+ if (str.includes("\n")) return str.split("\n").map((line$1) => wordWrapAnsiText(line$1, maxWidth, indent$1)).join("\n");
2149
+ const fragments = fragmentString(str, sep$1, "sep");
2150
+ const lines = [];
2151
+ let line = "";
2152
+ for (const text of joinFragments(fragments)) {
2153
+ const lineWidth = ansiWidth(line);
2154
+ const textWidth = ansiWidth(text);
2155
+ if (line && lineWidth + textWidth > maxWidth) {
2156
+ if (line) lines.push(line);
2157
+ line = indent$1 + text.trimStart();
2158
+ continue;
2159
+ }
2160
+ line += text;
2161
+ }
2162
+ if (line) lines.push(line);
2163
+ return lines.join("\n");
2164
+ }
2165
+ function* joinFragments(fragments) {
2166
+ let last;
2167
+ for (const frag of fragments) {
2168
+ if (frag.type === "sep") {
2169
+ if (last) yield last.text;
2170
+ last = frag;
2171
+ continue;
2172
+ }
2173
+ yield last ? last.text + frag.text : frag.text;
2174
+ last = void 0;
2175
+ }
2176
+ if (last) yield last.text;
2177
+ }
2178
+
1875
2179
  //#endregion
1876
2180
  //#region src/util/writeFile.ts
1877
2181
  async function writeFileOrStream(filename, data) {
@@ -1903,6 +2207,8 @@ const { opFilterAsync } = operators;
1903
2207
  async function runLint(cfg) {
1904
2208
  const reporter = new LintReporter(cfg.reporter, cfg.options);
1905
2209
  const configErrors = /* @__PURE__ */ new Set();
2210
+ const verboseLevel = calcVerboseLevel(cfg.options);
2211
+ const useColor = cfg.options.color ?? true;
1906
2212
  const timer = getTimeMeasurer();
1907
2213
  const logDictRequests = truthy(getEnvironmentVariable("CSPELL_ENABLE_DICTIONARY_LOGGING"));
1908
2214
  if (logDictRequests) _debug.cacheDictionaryEnableLogging(true);
@@ -1915,7 +2221,10 @@ async function runLint(cfg) {
1915
2221
  function prefetch(filename, configInfo, cache) {
1916
2222
  if (isBinaryFile$1(filename, cfg.root)) return {
1917
2223
  filename,
1918
- result: Promise.resolve({ skip: true })
2224
+ result: Promise.resolve({
2225
+ skip: true,
2226
+ skipReason: "Binary file."
2227
+ })
1919
2228
  };
1920
2229
  const reportIssueOptions = extractReporterIssueOptions(configInfo.config);
1921
2230
  async function fetch$1() {
@@ -1929,7 +2238,18 @@ async function runLint(cfg) {
1929
2238
  } };
1930
2239
  }
1931
2240
  const uri = filenameToUri(filename, cfg.root).href;
1932
- if (!(await shouldCheckDocument({ uri }, {}, configInfo.config)).shouldCheck) return { skip: true };
2241
+ const checkResult = await shouldCheckDocument({ uri }, {}, configInfo.config);
2242
+ if (!checkResult.shouldCheck) return {
2243
+ skip: true,
2244
+ skipReason: checkResult.reason || "Ignored by configuration."
2245
+ };
2246
+ const maxFileSize = processMaxFileSize(cfg.maxFileSize ?? checkResult.settings.maxFileSize);
2247
+ if (maxFileSize) {
2248
+ if (await getFileSize(filename) > maxFileSize) return {
2249
+ skip: true,
2250
+ skipReason: `File exceeded max file size of ${maxFileSize.toLocaleString()}`
2251
+ };
2252
+ }
1933
2253
  return {
1934
2254
  fileInfo: await readFileInfo(filename, void 0, true),
1935
2255
  reportIssueOptions
@@ -1937,7 +2257,7 @@ async function runLint(cfg) {
1937
2257
  }
1938
2258
  return {
1939
2259
  filename,
1940
- result: fetch$1()
2260
+ result: fetch$1().catch((e) => toApplicationError(e))
1941
2261
  };
1942
2262
  }
1943
2263
  async function processFile(filename, configInfo, cache, prefetch$1) {
@@ -1978,7 +2298,6 @@ async function runLint(cfg) {
1978
2298
  const { text } = fileInfo;
1979
2299
  result.fileInfo = fileInfo;
1980
2300
  let spellResult = {};
1981
- reporter.info(`Checking: ${filename}, File type: ${doc.languageId ?? "auto"}, Language: ${doc.locale ?? "default"}`, MessageTypes.Info);
1982
2301
  try {
1983
2302
  const { showSuggestions: generateSuggestions, validateDirectives, skipValidation } = cfg.options;
1984
2303
  const numSuggestions = configInfo.config.numSuggestions ?? 5;
@@ -2000,29 +2319,39 @@ async function runLint(cfg) {
2000
2319
  const config = spellResult.settingsUsed ?? {};
2001
2320
  result.reportIssueOptions = mergeReportIssueOptions(spellResult.settingsUsed || configInfo.config, reportIssueOptions);
2002
2321
  result.configErrors += await reportConfigurationErrors(config);
2003
- const elapsed$1 = result.elapsedTimeMs;
2004
- const dictionaries = config.dictionaries || [];
2005
- reporter.info(`Checked: ${filename}, File type: ${config.languageId}, Language: ${config.language} ... Issues: ${result.issues.length} ${elapsed$1.toFixed(2)}ms`, MessageTypes.Info);
2006
- reporter.info(`Config file Used: ${spellResult.localConfigFilepath || configInfo.source}`, MessageTypes.Info);
2007
- reporter.info(`Dictionaries Used: ${dictionaries.join(", ")}`, MessageTypes.Info);
2008
- if (cfg.options.debug) {
2009
- const { id: _id, name: _name, __imports, __importRef,...cfg$1 } = config;
2010
- const debugCfg = {
2011
- filename,
2012
- languageId: doc.languageId ?? cfg$1.languageId ?? "default",
2013
- config: {
2014
- ...cfg$1,
2015
- source: null
2016
- },
2017
- source: spellResult.localConfigFilepath
2018
- };
2019
- reporter.debug(JSON.stringify(debugCfg, void 0, 2));
2020
- }
2322
+ reportCheckResult(result, doc, spellResult, configInfo, config);
2021
2323
  const dep = calcDependencies(config);
2022
2324
  await cache.setCachedLintResults(result, dep.files);
2023
2325
  return result;
2024
2326
  }
2025
- function mapIssue({ doc: _,...tdo }) {
2327
+ function reportCheckResult(result, _doc, spellResult, configInfo, config) {
2328
+ const elapsed$1 = result.elapsedTimeMs || 0;
2329
+ const dictionaries = config.dictionaries || [];
2330
+ if (verboseLevel > 1) {
2331
+ const dictsUsed = [...dictionaries].sort().map((name$1) => chalk.green(name$1)).join(", ");
2332
+ const msg = unindent`
2333
+ File type: ${config.languageId}, Language: ${config.language}, Issues: ${result.issues.length} ${elapsed$1.toFixed(2)}ms
2334
+ Config file Used: ${relativeToCwd(spellResult.localConfigFilepath || configInfo.source, cfg.root)}
2335
+ Dictionaries Used:
2336
+ ${wordWrapAnsiText(dictsUsed, 70)}`;
2337
+ reporter.info(indent(msg, " "), MessageTypes.Info);
2338
+ }
2339
+ if (cfg.options.debug) {
2340
+ const { enabled, language, languageId, dictionaries: dictionaries$1 } = config;
2341
+ const msg = unindent`\
2342
+ Debug Config: ${formatWithOptions({
2343
+ depth: 2,
2344
+ colors: useColor
2345
+ }, {
2346
+ languageId,
2347
+ enabled,
2348
+ language,
2349
+ dictionaries: dictionaries$1
2350
+ })}`;
2351
+ reporter.debug(msg);
2352
+ }
2353
+ }
2354
+ function mapIssue({ doc: _, ...tdo }) {
2026
2355
  const context = cfg.showContext ? extractContext(tdo, cfg.showContext) : void 0;
2027
2356
  return clean({
2028
2357
  ...tdo,
@@ -2054,6 +2383,7 @@ async function runLint(cfg) {
2054
2383
  const { filename, result: pFetchResult } = pf;
2055
2384
  const getElapsedTimeMs = getTimeMeasurer();
2056
2385
  const fetchResult = await pFetchResult;
2386
+ if (fetchResult instanceof Error) throw fetchResult;
2057
2387
  reporter.emitProgressBegin(filename, index, fileCount ?? index);
2058
2388
  if (fetchResult?.skip) return {
2059
2389
  filename,
@@ -2061,7 +2391,8 @@ async function runLint(cfg) {
2061
2391
  result: {
2062
2392
  ...emptyResult,
2063
2393
  fileInfo: { filename },
2064
- elapsedTimeMs: getElapsedTimeMs()
2394
+ elapsedTimeMs: getElapsedTimeMs(),
2395
+ skippedReason: fetchResult.skipReason
2065
2396
  }
2066
2397
  };
2067
2398
  return {
@@ -2082,6 +2413,7 @@ async function runLint(cfg) {
2082
2413
  const { filename, fileNum, result } = fileP;
2083
2414
  status.files += 1;
2084
2415
  status.cachedFiles = (status.cachedFiles || 0) + (result.cached ? 1 : 0);
2416
+ status.skippedFiles = (status.skippedFiles || 0) + (result.processed ? 0 : 1);
2085
2417
  const numIssues = reporter.emitProgressComplete(filename, fileNum, fileCount ?? fileNum, result);
2086
2418
  if (numIssues || result.errors) {
2087
2419
  status.filesWithIssues.add(relativeToCwd(filename, cfg.root));
@@ -2139,14 +2471,14 @@ async function runLint(cfg) {
2139
2471
  const reporters = cfg.options.reporter ?? configInfo.config.reporters;
2140
2472
  reporter.config = reporterConfig;
2141
2473
  await reporter.loadReportersAndFinalize(reporters);
2142
- setLogger(getLoggerFromReporter(reporter));
2474
+ setLogger(getLoggerFromReporter(reporter, useColor));
2143
2475
  const globInfo = await determineGlobs(configInfo, cfg);
2144
2476
  const { fileGlobs, excludeGlobs } = globInfo;
2145
2477
  const hasFileLists = !!cfg.fileLists.length;
2146
2478
  if (!fileGlobs.length && !hasFileLists && !cfg.files?.length) return runResult();
2147
2479
  header(fileGlobs, excludeGlobs);
2148
2480
  checkGlobs(fileGlobs, reporter);
2149
- reporter.info(`Config Files Found:\n ${configInfo.source}\n`, MessageTypes.Info);
2481
+ if (verboseLevel > 1) reporter.info(`Config Files Found:\n ${relativeToCwd(configInfo.source)}\n`, MessageTypes.Info);
2150
2482
  const configErrors$1 = await countConfigErrors(configInfo);
2151
2483
  if (configErrors$1 && cfg.options.exitCode !== false && !cfg.options.continueOnError) return runResult({ errors: configErrors$1 });
2152
2484
  const { root } = cfg;
@@ -2165,18 +2497,19 @@ async function runLint(cfg) {
2165
2497
  }
2166
2498
  }
2167
2499
  function header(files, cliExcludes) {
2500
+ if (verboseLevel < 2) return;
2168
2501
  const formattedFiles = files.length > 100 ? [...files.slice(0, 100), "..."] : files;
2169
- reporter.info(`
2170
- cspell;
2171
- Date: ${(/* @__PURE__ */ new Date()).toUTCString()}
2172
- Options:
2173
- verbose: ${yesNo(!!cfg.options.verbose)}
2174
- config: ${cfg.configFile || "default"}
2175
- exclude: ${cliExcludes.join("\n ")}
2176
- files: ${formattedFiles}
2177
- wordsOnly: ${yesNo(!!cfg.options.wordsOnly)}
2178
- unique: ${yesNo(!!cfg.options.unique)}
2179
- `, MessageTypes.Info);
2502
+ reporter.info(unindent`
2503
+ cspell;
2504
+ Date: ${(/* @__PURE__ */ new Date()).toUTCString()}
2505
+ Options:
2506
+ verbose: ${yesNo(!!cfg.options.verbose)}
2507
+ config: ${cfg.configFile || "default"}
2508
+ exclude: ${wordWrapAnsiText(cliExcludes.join(", "), 60, " ")}
2509
+ files: ${formattedFiles}
2510
+ wordsOnly: ${yesNo(!!cfg.options.wordsOnly)}
2511
+ unique: ${yesNo(!!cfg.options.unique)}
2512
+ `, MessageTypes.Info);
2180
2513
  }
2181
2514
  }
2182
2515
  function checkGlobs(globs, reporter) {
@@ -2234,13 +2567,13 @@ async function determineFilesToCheck(configInfo, cfg, reporter, globInfo) {
2234
2567
  const r = globMatcherExclude.matchEx(absFilename);
2235
2568
  if (r.matched) {
2236
2569
  const { glob: glob$2, source } = extractGlobSource(r.pattern);
2237
- reporter.info(`Excluded File: ${path$1.relative(root, absFilename)}; Excluded by ${glob$2} from ${source}`, MessageTypes.Info);
2570
+ if (calcVerboseLevel(cfg.options) > 1) reporter.info(`Excluded File: ${path$1.relative(root, absFilename)}; Excluded by ${glob$2} from ${source}`, MessageTypes.Info);
2238
2571
  }
2239
2572
  return r.matched;
2240
2573
  }
2241
2574
  function filterOutExcludedFilesFn(globMatcherExclude) {
2242
2575
  const excludeInfo = globMatcherExclude.patterns.map(extractGlobSource).map(({ glob: glob$2, source }) => `Glob: ${glob$2} from ${source}`).filter(uniqueFn());
2243
- reporter.info(`Exclusion Globs: \n ${excludeInfo.join("\n ")}\n`, MessageTypes.Info);
2576
+ if (calcVerboseLevel(cfg.options) > 1) reporter.info(`Exclusion Globs: \n ${excludeInfo.join("\n ")}\n`, MessageTypes.Info);
2244
2577
  return (filename) => !isExcluded(filename, globMatcherExclude);
2245
2578
  }
2246
2579
  return _determineFilesToCheck();
@@ -2265,13 +2598,14 @@ function runResult(init = {}) {
2265
2598
  function yesNo(value) {
2266
2599
  return value ? "Yes" : "No";
2267
2600
  }
2268
- function getLoggerFromReporter(reporter) {
2601
+ function getLoggerFromReporter(reporter, useColor) {
2602
+ const inspectOptions = { colors: useColor };
2269
2603
  const log = (...params) => {
2270
- const msg = format(...params);
2604
+ const msg = formatWithOptions(inspectOptions, ...params);
2271
2605
  reporter.info(msg, "Info");
2272
2606
  };
2273
2607
  const error = (...params) => {
2274
- const msg = format(...params);
2608
+ const msg = formatWithOptions(inspectOptions, ...params);
2275
2609
  reporter.error(msg, {
2276
2610
  message: "",
2277
2611
  name: "error",
@@ -2279,7 +2613,7 @@ function getLoggerFromReporter(reporter) {
2279
2613
  });
2280
2614
  };
2281
2615
  const warn = (...params) => {
2282
- const msg = format(...params);
2616
+ const msg = formatWithOptions(inspectOptions, ...params);
2283
2617
  reporter.info(msg, "Warning");
2284
2618
  };
2285
2619
  return {
@@ -2333,6 +2667,16 @@ var LinterError = class extends Error {
2333
2667
  return this.message;
2334
2668
  }
2335
2669
  };
2670
+ function calcVerboseLevel(options) {
2671
+ return options.verboseLevel ?? (options.verbose ? 1 : 0);
2672
+ }
2673
+ function processMaxFileSize(value) {
2674
+ if (!value) return void 0;
2675
+ if (typeof value === "number") return value;
2676
+ const num = sizeToNumber(value);
2677
+ if (Number.isNaN(num)) throw new ApplicationError(`Invalid max file size: "${value}"`);
2678
+ return num;
2679
+ }
2336
2680
 
2337
2681
  //#endregion
2338
2682
  //#region src/lint/LintRequest.ts
@@ -2347,6 +2691,7 @@ var LintRequest = class {
2347
2691
  fileLists;
2348
2692
  files;
2349
2693
  cspellSettingsFromCliOptions;
2694
+ maxFileSize;
2350
2695
  constructor(fileGlobs, options, reporter) {
2351
2696
  this.fileGlobs = fileGlobs;
2352
2697
  this.options = options;
@@ -2370,6 +2715,7 @@ var LintRequest = class {
2370
2715
  ...extractUnknownWordsConfig(options),
2371
2716
  languageSettings
2372
2717
  };
2718
+ this.maxFileSize = options.maxFileSize ? sizeToNumber(options.maxFileSize) : void 0;
2373
2719
  }
2374
2720
  };
2375
2721
  function mergeFiles(a, b) {
@@ -2411,10 +2757,19 @@ const ReportChoicesAll = [
2411
2757
  "flagged"
2412
2758
  ];
2413
2759
  function fixLegacy(opts) {
2414
- const { local,...rest } = opts;
2760
+ const { local, ...rest } = opts;
2415
2761
  if (local && !rest.locale) rest.locale = local;
2416
2762
  return rest;
2417
2763
  }
2764
+ function cvtLinterCliCommandOptionsToLinterCliOptions(options) {
2765
+ const { verbose: verboseLevel, ...optionsRest } = options;
2766
+ const cliOptions = { ...optionsRest };
2767
+ if (verboseLevel) {
2768
+ cliOptions.verboseLevel = verboseLevel;
2769
+ cliOptions.verbose = true;
2770
+ }
2771
+ return cliOptions;
2772
+ }
2418
2773
 
2419
2774
  //#endregion
2420
2775
  //#region src/repl/index.ts
@@ -2655,5 +3010,5 @@ function parseApplicationFeatureFlags(flags) {
2655
3010
  }
2656
3011
 
2657
3012
  //#endregion
2658
- export { parseApplicationFeatureFlags as a, listDictionaries as c, npmPackage as d, getReporter as f, console as h, lint as i, ReportChoicesAll as l, CheckFailed as m, checkText as n, suggestions as o, ApplicationError as p, createInit as r, trace as s, IncludeExcludeFlag as t, DEFAULT_CACHE_LOCATION as u };
2659
- //# sourceMappingURL=application-CGIx5L0D.js.map
3013
+ export { console as C, CheckFailed as S, unindent as _, parseApplicationFeatureFlags as a, getReporter as b, listDictionaries as c, ansiWidth as d, pruneAnsiTextEnd as f, validateUnitSize as g, width as h, lint as i, ReportChoicesAll as l, pruneTextEnd as m, checkText as n, suggestions as o, pruneAnsiTextStart as p, createInit as r, trace as s, IncludeExcludeFlag as t, cvtLinterCliCommandOptionsToLinterCliOptions as u, DEFAULT_CACHE_LOCATION as v, ApplicationError as x, npmPackage as y };
3014
+ //# sourceMappingURL=application-DCyfKhGm.js.map
@@ -1,3 +1,3 @@
1
- import "./options-BeJCICDB.js";
2
- import { a as checkText, c as parseApplicationFeatureFlags, d as listDictionaries, i as TraceResult, l as suggestions, n as CheckTextResult, o as createInit, r as IncludeExcludeFlag, s as lint, t as AppError, u as trace } from "./application-B84gvlDU.js";
1
+ import "./options-D_PtlSKK.js";
2
+ import { a as checkText, c as parseApplicationFeatureFlags, d as listDictionaries, i as TraceResult, l as suggestions, n as CheckTextResult, o as createInit, r as IncludeExcludeFlag, s as lint, t as AppError, u as trace } from "./application-Ce_s5c1d.js";
3
3
  export { AppError, CheckTextResult, IncludeExcludeFlag, TraceResult, checkText, createInit, lint, listDictionaries, parseApplicationFeatureFlags, suggestions, trace };
@@ -1,3 +1,3 @@
1
- import { a as parseApplicationFeatureFlags, c as listDictionaries, i as lint, n as checkText, o as suggestions, r as createInit, s as trace, t as IncludeExcludeFlag } from "./application-CGIx5L0D.js";
1
+ import { a as parseApplicationFeatureFlags, c as listDictionaries, i as lint, n as checkText, o as suggestions, r as createInit, s as trace, t as IncludeExcludeFlag } from "./application-DCyfKhGm.js";
2
2
 
3
3
  export { IncludeExcludeFlag, checkText, createInit, lint, listDictionaries, parseApplicationFeatureFlags, suggestions, trace };
@@ -1,5 +1,5 @@
1
- import { i as LinterCliOptions, o as TraceOptions, t as BaseOptions } from "./options-BeJCICDB.js";
2
- import { a as checkText, c as parseApplicationFeatureFlags, d as listDictionaries, i as TraceResult, l as suggestions, n as CheckTextResult, o as createInit, r as IncludeExcludeFlag, s as lint, t as AppError, u as trace } from "./application-B84gvlDU.js";
1
+ import { i as LinterCliOptions, o as TraceOptions, t as BaseOptions } from "./options-D_PtlSKK.js";
2
+ import { a as checkText, c as parseApplicationFeatureFlags, d as listDictionaries, i as TraceResult, l as suggestions, n as CheckTextResult, o as createInit, r as IncludeExcludeFlag, s as lint, t as AppError, u as trace } from "./application-Ce_s5c1d.js";
3
3
  import "chalk";
4
4
  import { CSpellReporter, CSpellSettings, ReporterConfiguration, RunResult } from "@cspell/cspell-types";
5
5
  import { WriteStream } from "node:tty";
@@ -42,7 +42,7 @@ interface CSpellReporterModule {
42
42
  type FinalizedReporter = Required<CSpellReporter>;
43
43
  //#endregion
44
44
  //#region src/cli-reporter.d.ts
45
- interface ReporterOptions extends Pick<LinterCliOptions, "color" | "debug" | "issues" | "issuesSummaryReport" | "legacy" | "progress" | "relative" | "root" | "showContext" | "showPerfSummary" | "showSuggestions" | "silent" | "summary" | "verbose" | "wordsOnly"> {
45
+ interface ReporterOptions extends Pick<LinterCliOptions, "color" | "debug" | "issues" | "issuesSummaryReport" | "legacy" | "progress" | "relative" | "root" | "showContext" | "showPerfSummary" | "showSuggestions" | "silent" | "summary" | "verbose" | "verboseLevel" | "wordsOnly"> {
46
46
  fileGlobs: string[];
47
47
  }
48
48
  declare function getReporter(options: ReporterOptions, config?: CSpellReporterConfiguration): FinalizedReporter;
package/dist/esm/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as parseApplicationFeatureFlags, c as listDictionaries, f as getReporter, i as lint, n as checkText, o as suggestions, r as createInit, s as trace, t as IncludeExcludeFlag } from "./application-CGIx5L0D.js";
1
+ import { a as parseApplicationFeatureFlags, b as getReporter, c as listDictionaries, i as lint, n as checkText, o as suggestions, r as createInit, s as trace, t as IncludeExcludeFlag } from "./application-DCyfKhGm.js";
2
2
 
3
3
  export * from "@cspell/cspell-types"
4
4
 
@@ -44,6 +44,10 @@ interface LinterOptions extends Omit<BaseOptions, "config">, Omit<CacheOptions,
44
44
  */
45
45
  verbose?: boolean;
46
46
  /**
47
+ * Level of verbosity (higher number = more verbose).
48
+ */
49
+ verboseLevel?: number;
50
+ /**
47
51
  * Show extensive output.
48
52
  */
49
53
  debug?: boolean;
@@ -142,6 +146,13 @@ interface LinterOptions extends Omit<BaseOptions, "config">, Omit<CacheOptions,
142
146
  * Path to configuration file.
143
147
  */
144
148
  config?: string | CSpellConfigFile;
149
+ /**
150
+ * Specify the maximum file size to be checked.
151
+ * The value can include a units suffix: `KB`, `MB`, `B`, `GB`.
152
+ * The numeric value can include a decimal.
153
+ * Example: 1.5MB
154
+ */
155
+ maxFileSize?: string | undefined;
145
156
  }
146
157
  interface TraceOptions extends BaseOptions {
147
158
  /**
@@ -387,4 +398,4 @@ interface CSpellConfigFile {
387
398
  }
388
399
  //#endregion
389
400
  export { SuggestionOptions as a, LinterCliOptions as i, DictionariesOptions as n, TraceOptions as o, LegacyOptions as r, BaseOptions as t };
390
- //# sourceMappingURL=options-BeJCICDB.d.ts.map
401
+ //# sourceMappingURL=options-D_PtlSKK.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cspell",
3
- "version": "9.3.2",
3
+ "version": "9.4.0",
4
4
  "description": "A Spelling Checker for Code!",
5
5
  "funding": "https://github.com/streetsidesoftware/cspell?sponsor=1",
6
6
  "bin": {
@@ -83,20 +83,21 @@
83
83
  },
84
84
  "homepage": "https://cspell.org/",
85
85
  "dependencies": {
86
- "@cspell/cspell-json-reporter": "9.3.2",
87
- "@cspell/cspell-pipe": "9.3.2",
88
- "@cspell/cspell-types": "9.3.2",
89
- "@cspell/dynamic-import": "9.3.2",
90
- "@cspell/url": "9.3.2",
86
+ "@cspell/cspell-json-reporter": "9.4.0",
87
+ "@cspell/cspell-pipe": "9.4.0",
88
+ "@cspell/cspell-types": "9.4.0",
89
+ "@cspell/dynamic-import": "9.4.0",
90
+ "@cspell/url": "9.4.0",
91
+ "ansi-regex": "^6.2.2",
91
92
  "chalk": "^5.6.2",
92
93
  "chalk-template": "^1.1.2",
93
94
  "commander": "^14.0.2",
94
- "cspell-config-lib": "9.3.2",
95
- "cspell-dictionary": "9.3.2",
96
- "cspell-gitignore": "9.3.2",
97
- "cspell-glob": "9.3.2",
98
- "cspell-io": "9.3.2",
99
- "cspell-lib": "9.3.2",
95
+ "cspell-config-lib": "9.4.0",
96
+ "cspell-dictionary": "9.4.0",
97
+ "cspell-gitignore": "9.4.0",
98
+ "cspell-glob": "9.4.0",
99
+ "cspell-io": "9.4.0",
100
+ "cspell-lib": "9.4.0",
100
101
  "fast-json-stable-stringify": "^2.1.0",
101
102
  "flatted": "^3.3.3",
102
103
  "semver": "^7.7.3",
@@ -112,5 +113,5 @@
112
113
  "micromatch": "^4.0.8",
113
114
  "minimatch": "^9.0.5"
114
115
  },
115
- "gitHead": "595bde79b4a5abf3256b71129995ec3601454b02"
116
+ "gitHead": "12dba3d8b880384d1401c765cb2186647f5a266f"
116
117
  }