cspell 9.1.3 → 9.2.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 (152) hide show
  1. package/README.md +29 -21
  2. package/bin.mjs +1 -1
  3. package/dist/esm/app.d.ts +19 -0
  4. package/dist/esm/app.js +1033 -0
  5. package/dist/esm/application-D8WjsMdV.d.ts +116 -0
  6. package/dist/esm/application-_MFvh02K.js +2761 -0
  7. package/dist/esm/application.d.ts +3 -0
  8. package/dist/esm/application.js +3 -0
  9. package/dist/esm/index.d.ts +55 -0
  10. package/dist/esm/index.js +5 -0
  11. package/dist/esm/options-ChaXtdFn.d.ts +387 -0
  12. package/package.json +28 -27
  13. package/dist/esm/app.d.mts +0 -5
  14. package/dist/esm/app.mjs +0 -34
  15. package/dist/esm/application.d.mts +0 -17
  16. package/dist/esm/application.mjs +0 -99
  17. package/dist/esm/cli-reporter.d.ts +0 -38
  18. package/dist/esm/cli-reporter.js +0 -386
  19. package/dist/esm/commandCheck.d.ts +0 -3
  20. package/dist/esm/commandCheck.js +0 -52
  21. package/dist/esm/commandConfig.d.ts +0 -3
  22. package/dist/esm/commandConfig.js +0 -18
  23. package/dist/esm/commandDictionaries.d.ts +0 -3
  24. package/dist/esm/commandDictionaries.js +0 -40
  25. package/dist/esm/commandHelpers.d.ts +0 -18
  26. package/dist/esm/commandHelpers.js +0 -30
  27. package/dist/esm/commandInit.d.ts +0 -3
  28. package/dist/esm/commandInit.js +0 -25
  29. package/dist/esm/commandLink.d.ts +0 -3
  30. package/dist/esm/commandLink.js +0 -48
  31. package/dist/esm/commandLint.d.ts +0 -3
  32. package/dist/esm/commandLint.js +0 -226
  33. package/dist/esm/commandSuggestion.d.ts +0 -3
  34. package/dist/esm/commandSuggestion.js +0 -61
  35. package/dist/esm/commandTrace.d.ts +0 -3
  36. package/dist/esm/commandTrace.js +0 -91
  37. package/dist/esm/config/adjustConfig.d.ts +0 -7
  38. package/dist/esm/config/adjustConfig.js +0 -137
  39. package/dist/esm/config/config.d.ts +0 -5
  40. package/dist/esm/config/config.js +0 -18
  41. package/dist/esm/config/configInit.d.ts +0 -3
  42. package/dist/esm/config/configInit.js +0 -104
  43. package/dist/esm/config/constants.d.ts +0 -17
  44. package/dist/esm/config/constants.js +0 -23
  45. package/dist/esm/config/index.d.ts +0 -3
  46. package/dist/esm/config/index.js +0 -2
  47. package/dist/esm/config/options.d.ts +0 -62
  48. package/dist/esm/config/options.js +0 -2
  49. package/dist/esm/config/updateConfig.d.ts +0 -3
  50. package/dist/esm/config/updateConfig.js +0 -2
  51. package/dist/esm/console.d.ts +0 -25
  52. package/dist/esm/console.js +0 -53
  53. package/dist/esm/dictionaries/index.d.ts +0 -3
  54. package/dist/esm/dictionaries/index.js +0 -2
  55. package/dist/esm/dictionaries/listDictionaries.d.ts +0 -33
  56. package/dist/esm/dictionaries/listDictionaries.js +0 -131
  57. package/dist/esm/dirname.d.ts +0 -2
  58. package/dist/esm/dirname.js +0 -13
  59. package/dist/esm/emitters/DictionaryPathFormat.d.ts +0 -3
  60. package/dist/esm/emitters/DictionaryPathFormat.js +0 -12
  61. package/dist/esm/emitters/dictionaryListEmitter.d.ts +0 -19
  62. package/dist/esm/emitters/dictionaryListEmitter.js +0 -82
  63. package/dist/esm/emitters/helpers.d.ts +0 -14
  64. package/dist/esm/emitters/helpers.js +0 -67
  65. package/dist/esm/emitters/suggestionsEmitter.d.ts +0 -13
  66. package/dist/esm/emitters/suggestionsEmitter.js +0 -79
  67. package/dist/esm/emitters/traceEmitter.d.ts +0 -19
  68. package/dist/esm/emitters/traceEmitter.js +0 -87
  69. package/dist/esm/environment.d.ts +0 -39
  70. package/dist/esm/environment.js +0 -30
  71. package/dist/esm/featureFlags/featureFlags.d.ts +0 -4
  72. package/dist/esm/featureFlags/featureFlags.js +0 -21
  73. package/dist/esm/featureFlags/index.d.ts +0 -2
  74. package/dist/esm/featureFlags/index.js +0 -2
  75. package/dist/esm/index.d.mts +0 -6
  76. package/dist/esm/index.mjs +0 -4
  77. package/dist/esm/link.d.ts +0 -8
  78. package/dist/esm/link.js +0 -39
  79. package/dist/esm/lint/LintRequest.d.ts +0 -26
  80. package/dist/esm/lint/LintRequest.js +0 -83
  81. package/dist/esm/lint/index.d.ts +0 -3
  82. package/dist/esm/lint/index.js +0 -3
  83. package/dist/esm/lint/lint.d.ts +0 -8
  84. package/dist/esm/lint/lint.js +0 -515
  85. package/dist/esm/models.d.ts +0 -15
  86. package/dist/esm/models.js +0 -2
  87. package/dist/esm/options.d.ts +0 -353
  88. package/dist/esm/options.js +0 -9
  89. package/dist/esm/pkgInfo.d.ts +0 -14
  90. package/dist/esm/pkgInfo.js +0 -7
  91. package/dist/esm/repl/index.d.ts +0 -18
  92. package/dist/esm/repl/index.js +0 -52
  93. package/dist/esm/util/InMemoryReporter.d.ts +0 -31
  94. package/dist/esm/util/InMemoryReporter.js +0 -49
  95. package/dist/esm/util/LintFileResult.d.ts +0 -14
  96. package/dist/esm/util/LintFileResult.js +0 -2
  97. package/dist/esm/util/async.d.ts +0 -3
  98. package/dist/esm/util/async.js +0 -4
  99. package/dist/esm/util/cache/CSpellLintResultCache.d.ts +0 -20
  100. package/dist/esm/util/cache/CSpellLintResultCache.js +0 -2
  101. package/dist/esm/util/cache/CacheOptions.d.ts +0 -34
  102. package/dist/esm/util/cache/CacheOptions.js +0 -2
  103. package/dist/esm/util/cache/DiskCache.d.ts +0 -63
  104. package/dist/esm/util/cache/DiskCache.js +0 -214
  105. package/dist/esm/util/cache/DummyCache.d.ts +0 -11
  106. package/dist/esm/util/cache/DummyCache.js +0 -18
  107. package/dist/esm/util/cache/ObjectCollection.d.ts +0 -17
  108. package/dist/esm/util/cache/ObjectCollection.js +0 -127
  109. package/dist/esm/util/cache/createCache.d.ts +0 -31
  110. package/dist/esm/util/cache/createCache.js +0 -69
  111. package/dist/esm/util/cache/file-entry-cache.d.mts +0 -4
  112. package/dist/esm/util/cache/file-entry-cache.mjs +0 -5
  113. package/dist/esm/util/cache/fileEntryCache.d.ts +0 -9
  114. package/dist/esm/util/cache/fileEntryCache.js +0 -79
  115. package/dist/esm/util/cache/index.d.ts +0 -4
  116. package/dist/esm/util/cache/index.js +0 -2
  117. package/dist/esm/util/canUseColor.d.ts +0 -2
  118. package/dist/esm/util/canUseColor.js +0 -10
  119. package/dist/esm/util/configFileHelper.d.ts +0 -15
  120. package/dist/esm/util/configFileHelper.js +0 -43
  121. package/dist/esm/util/constants.d.ts +0 -6
  122. package/dist/esm/util/constants.js +0 -6
  123. package/dist/esm/util/errors.d.ts +0 -24
  124. package/dist/esm/util/errors.js +0 -60
  125. package/dist/esm/util/extractContext.d.ts +0 -5
  126. package/dist/esm/util/extractContext.js +0 -75
  127. package/dist/esm/util/fileHelper.d.ts +0 -44
  128. package/dist/esm/util/fileHelper.js +0 -165
  129. package/dist/esm/util/glob.d.ts +0 -45
  130. package/dist/esm/util/glob.js +0 -147
  131. package/dist/esm/util/pad.d.ts +0 -45
  132. package/dist/esm/util/pad.js +0 -191
  133. package/dist/esm/util/prefetch.d.ts +0 -2
  134. package/dist/esm/util/prefetch.js +0 -15
  135. package/dist/esm/util/reporters.d.ts +0 -30
  136. package/dist/esm/util/reporters.js +0 -209
  137. package/dist/esm/util/stdin.d.ts +0 -2
  138. package/dist/esm/util/stdin.js +0 -5
  139. package/dist/esm/util/stdinUrl.d.ts +0 -9
  140. package/dist/esm/util/stdinUrl.js +0 -26
  141. package/dist/esm/util/table.d.ts +0 -41
  142. package/dist/esm/util/table.js +0 -115
  143. package/dist/esm/util/timer.d.ts +0 -4
  144. package/dist/esm/util/timer.js +0 -9
  145. package/dist/esm/util/types.d.ts +0 -7
  146. package/dist/esm/util/types.js +0 -5
  147. package/dist/esm/util/unindent.d.ts +0 -14
  148. package/dist/esm/util/unindent.js +0 -55
  149. package/dist/esm/util/util.d.ts +0 -14
  150. package/dist/esm/util/util.js +0 -30
  151. package/dist/esm/util/writeFile.d.ts +0 -3
  152. package/dist/esm/util/writeFile.js +0 -30
@@ -0,0 +1,2761 @@
1
+ import { createRequire } from "node:module";
2
+ import chalk, { Chalk } from "chalk";
3
+ import { isAsyncIterable, opFilter, opMap, opTap, operators, pipeAsync, pipeAsync as asyncPipe, toAsyncIterable, toAsyncIterable as mergeAsyncIterables } from "@cspell/cspell-pipe";
4
+ import * as cspell from "cspell-lib";
5
+ 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
+ import assert from "node:assert";
7
+ import { format, formatWithOptions } from "node:util";
8
+ import { isUrlLike, toFileDirURL, toFilePathOrHref, toFileURL, urlRelative } from "@cspell/url";
9
+ import { makeTemplate } from "chalk-template";
10
+ import fs, { stat } from "node:fs/promises";
11
+ import { MutableCSpellConfigFile, createReaderWriter, cspellConfigFileSchema, isCfgArrayNode } from "cspell-config-lib";
12
+ import { promises } from "node:fs";
13
+ import { fileURLToPath } from "node:url";
14
+ import * as path$1 from "node:path";
15
+ import path, { isAbsolute, posix, relative, resolve, sep } from "node:path";
16
+ import { opMap as opMap$1, pipe } from "@cspell/cspell-pipe/sync";
17
+ import { IssueType, MessageTypes, unknownWordsChoices } from "@cspell/cspell-types";
18
+ import { _debug } from "cspell-dictionary";
19
+ import { GitIgnore, findRepoRoot } from "cspell-gitignore";
20
+ import { GlobMatcher, fileOrGlobToGlob, workaroundPicomatchBug } from "cspell-glob";
21
+ import crypto from "node:crypto";
22
+ import streamConsumers from "node:stream/consumers";
23
+ import { readFileText, toURL } from "cspell-io";
24
+ import { glob } from "tinyglobby";
25
+ import * as readline from "node:readline";
26
+ import { parse, stringify } from "flatted";
27
+ import { dynamicImport } from "@cspell/dynamic-import";
28
+
29
+ //#region src/console.ts
30
+ var ImplChannel = class {
31
+ constructor(stream) {
32
+ this.stream = stream;
33
+ }
34
+ write = (msg) => this.stream.write(msg);
35
+ writeLine = (msg) => this.write(msg + "\n");
36
+ clearLine = (dir, callback) => this.stream.clearLine?.(dir, callback) ?? false;
37
+ printLine = (...params) => this.writeLine(params.length && formatWithOptions({ colors: this.stream.hasColors?.() }, ...params) || "");
38
+ getColorLevel = () => getColorLevel(this.stream);
39
+ };
40
+ var Console = class {
41
+ stderrChannel;
42
+ stdoutChannel;
43
+ constructor(stdout = process.stdout, stderr = process.stderr) {
44
+ this.stdout = stdout;
45
+ this.stderr = stderr;
46
+ this.stderrChannel = new ImplChannel(this.stderr);
47
+ this.stdoutChannel = new ImplChannel(this.stdout);
48
+ }
49
+ log = (...p) => this.stdoutChannel.printLine(...p);
50
+ error = (...p) => this.stderrChannel.printLine(...p);
51
+ info = this.log;
52
+ warn = this.error;
53
+ };
54
+ const console = new Console();
55
+ function getColorLevel(stream) {
56
+ const depth = stream.getColorDepth?.() || 0;
57
+ switch (depth) {
58
+ case 1: return 1;
59
+ case 4: return 2;
60
+ case 24: return 3;
61
+ default: return 0;
62
+ }
63
+ }
64
+
65
+ //#endregion
66
+ //#region src/util/errors.ts
67
+ var CheckFailed = class extends Error {
68
+ constructor(message, exitCode = 1) {
69
+ super(message);
70
+ this.exitCode = exitCode;
71
+ }
72
+ };
73
+ var ApplicationError = class extends Error {
74
+ constructor(message, exitCode = 1, cause) {
75
+ super(message);
76
+ this.exitCode = exitCode;
77
+ this.cause = cause;
78
+ }
79
+ };
80
+ var IOError = class extends ApplicationError {
81
+ constructor(message, cause) {
82
+ super(message, void 0, cause);
83
+ this.cause = cause;
84
+ }
85
+ get code() {
86
+ return this.cause.code;
87
+ }
88
+ isNotFound() {
89
+ return this.cause.code === "ENOENT";
90
+ }
91
+ };
92
+ function toError(e) {
93
+ if (isError(e)) return e;
94
+ if (isErrorLike(e)) {
95
+ const ex = new Error(e.message, { cause: e });
96
+ if (e.code !== void 0) ex.code = e.code;
97
+ return ex;
98
+ }
99
+ const message = format(e);
100
+ return new Error(message);
101
+ }
102
+ function isError(e) {
103
+ return e instanceof Error;
104
+ }
105
+ function isErrorLike(e) {
106
+ if (e instanceof Error) return true;
107
+ if (!e || typeof e !== "object") return false;
108
+ const ex = e;
109
+ return typeof ex.message === "string";
110
+ }
111
+ function toApplicationError(e, message) {
112
+ if (e instanceof ApplicationError && !message) return e;
113
+ const err = toError(e);
114
+ return new ApplicationError(message ?? err.message, void 0, err);
115
+ }
116
+
117
+ //#endregion
118
+ //#region src/util/util.ts
119
+ const uniqueFn = uniqueFilterFnGenerator;
120
+ function uniqueFilterFnGenerator(extractFn) {
121
+ const values = /* @__PURE__ */ new Set();
122
+ const extractor = extractFn || ((a) => a);
123
+ return (v) => {
124
+ const vv = extractor(v);
125
+ const ret = !values.has(vv);
126
+ values.add(vv);
127
+ return ret;
128
+ };
129
+ }
130
+ /**
131
+ * Removed all properties with a value of `undefined` from the object.
132
+ * @param src - the object to clean.
133
+ * @returns the same object with all properties with a value of `undefined` removed.
134
+ */
135
+ function clean(src) {
136
+ const r = src;
137
+ for (const key of Object.keys(r)) if (r[key] === void 0) delete r[key];
138
+ return r;
139
+ }
140
+
141
+ //#endregion
142
+ //#region src/cli-reporter.ts
143
+ const templateIssue = `{green $filename}:{yellow $row:$col} - $message ({red $text}) $quickFix`;
144
+ const templateIssueNoFix = `{green $filename}:{yellow $row:$col} - $message ({red $text})`;
145
+ const templateIssueWithSuggestions = `{green $filename}:{yellow $row:$col} - $message ({red $text}) Suggestions: {yellow [$suggestions]}`;
146
+ const templateIssueWithContext = `{green $filename}:{yellow $row:$col} $padRowCol- $message ({red $text})$padContext -- {gray $contextLeft}{red {underline $text}}{gray $contextRight}`;
147
+ const templateIssueWithContextWithSuggestions = `{green $filename}:{yellow $row:$col} $padRowCol- $message ({red $text})$padContext -- {gray $contextLeft}{red {underline $text}}{gray $contextRight}\n\t Suggestions: {yellow [$suggestions]}`;
148
+ const templateIssueLegacy = `{green $filename}[$row, $col]: $message: {red $text}`;
149
+ const templateIssueWordsOnly = "$text";
150
+ assert(true);
151
+ /**
152
+ *
153
+ * @param template - The template to use for the issue.
154
+ * @param uniqueIssues - If true, only unique issues will be reported.
155
+ * @param reportedIssuesCollection - optional collection to store reported issues.
156
+ * @returns issueEmitter function
157
+ */
158
+ function genIssueEmitter(stdIO, errIO, template, uniqueIssues, reportedIssuesCollection) {
159
+ const uniqueFilter = uniqueIssues ? uniqueFilterFnGenerator((issue) => issue.text) : () => true;
160
+ const defaultWidth = 10;
161
+ let maxWidth = defaultWidth;
162
+ let uri;
163
+ return function issueEmitter(issue) {
164
+ if (!uniqueFilter(issue)) return;
165
+ if (uri !== issue.uri) {
166
+ maxWidth = defaultWidth;
167
+ uri = issue.uri;
168
+ }
169
+ maxWidth = Math.max(maxWidth * .999, issue.text.length, 10);
170
+ const issueText = formatIssue(stdIO, template, issue, Math.ceil(maxWidth));
171
+ reportedIssuesCollection?.push(formatIssue(errIO, template, issue, Math.ceil(maxWidth)));
172
+ stdIO.writeLine(issueText);
173
+ };
174
+ }
175
+ function nullEmitter() {}
176
+ function relativeUriFilename(uri, rootURL) {
177
+ const url = toFileURL(uri);
178
+ const rel = urlRelative(rootURL, url);
179
+ if (rel.startsWith("..")) return toFilePathOrHref(url);
180
+ return rel;
181
+ }
182
+ function reportProgress(io, p, cwdURL, options) {
183
+ if (p.type === "ProgressFileComplete") return reportProgressFileComplete(io, p, cwdURL, options);
184
+ if (p.type === "ProgressFileBegin") return reportProgressFileBegin(io, p, cwdURL);
185
+ }
186
+ function determineFilename(io, p, cwd) {
187
+ const fc = "" + p.fileCount;
188
+ const fn = (" ".repeat(fc.length) + p.fileNum).slice(-fc.length);
189
+ const idx = fn + "/" + fc;
190
+ const filename = io.chalk.gray(relativeUriFilename(p.filename, cwd));
191
+ return {
192
+ idx,
193
+ filename
194
+ };
195
+ }
196
+ function reportProgressFileBegin(io, p, cwdURL) {
197
+ const { idx, filename } = determineFilename(io, p, cwdURL);
198
+ if (io.getColorLevel() > 0) {
199
+ io.clearLine?.(0);
200
+ io.write(`${idx} ${filename}\r`);
201
+ }
202
+ }
203
+ function reportProgressFileComplete(io, p, cwd, options) {
204
+ const { idx, filename } = determineFilename(io, p, cwd);
205
+ const { verbose, debug } = options;
206
+ const time = reportTime(io, p.elapsedTimeMs, !!p.cached);
207
+ const skipped = p.processed === false ? " skipped" : "";
208
+ const hasErrors = p.numErrors ? io.chalk.red` X` : "";
209
+ const newLine = skipped && (verbose || debug) || hasErrors || isSlow(p.elapsedTimeMs) || io.getColorLevel() < 1 ? "\n" : "";
210
+ const msg = `${idx} ${filename} ${time}${skipped}${hasErrors}${newLine || "\r"}`;
211
+ io.write(msg);
212
+ }
213
+ function reportTime(io, elapsedTimeMs, cached) {
214
+ if (cached) return io.chalk.green("cached");
215
+ if (elapsedTimeMs === void 0) return "-";
216
+ const slow = isSlow(elapsedTimeMs);
217
+ const color = !slow ? io.chalk.white : slow === 1 ? io.chalk.yellow : io.chalk.redBright;
218
+ return color(elapsedTimeMs.toFixed(2) + "ms");
219
+ }
220
+ function isSlow(elapsedTmeMs) {
221
+ if (!elapsedTmeMs || elapsedTmeMs < 1e3) return 0;
222
+ if (elapsedTmeMs < 2e3) return 1;
223
+ return 2;
224
+ }
225
+ function getReporter(options, config) {
226
+ const perfStats = {
227
+ filesProcessed: 0,
228
+ filesSkipped: 0,
229
+ filesCached: 0,
230
+ elapsedTimeMs: 0,
231
+ perf: Object.create(null)
232
+ };
233
+ const noColor = options.color === false;
234
+ const forceColor = options.color === true;
235
+ const uniqueIssues = config?.unique || false;
236
+ const defaultIssueTemplate = options.wordsOnly ? templateIssueWordsOnly : options.legacy ? templateIssueLegacy : options.showContext ? options.showSuggestions ? templateIssueWithContextWithSuggestions : templateIssueWithContext : options.showSuggestions ? templateIssueWithSuggestions : options.showSuggestions === false ? templateIssueNoFix : templateIssue;
237
+ const { fileGlobs, silent, summary, issues, progress: showProgress, verbose, debug } = options;
238
+ const issueTemplate = config?.issueTemplate || defaultIssueTemplate;
239
+ assertCheckTemplate(issueTemplate);
240
+ const console$1 = config?.console || console;
241
+ const colorLevel = noColor ? 0 : forceColor ? 2 : console$1.stdoutChannel.getColorLevel();
242
+ const stdio = {
243
+ ...console$1.stdoutChannel,
244
+ chalk: new Chalk({ level: colorLevel })
245
+ };
246
+ const stderr = {
247
+ ...console$1.stderrChannel,
248
+ chalk: new Chalk({ level: colorLevel })
249
+ };
250
+ const consoleError = (msg) => stderr.writeLine(msg);
251
+ function createInfoLog(wrap) {
252
+ return (msg) => console$1.info(wrap(msg));
253
+ }
254
+ const emitters = {
255
+ Debug: !silent && debug ? createInfoLog(stdio.chalk.cyan) : nullEmitter,
256
+ Info: !silent && verbose ? createInfoLog(stdio.chalk.yellow) : nullEmitter,
257
+ Warning: createInfoLog(stdio.chalk.yellow)
258
+ };
259
+ function infoEmitter(message, msgType) {
260
+ emitters[msgType]?.(message);
261
+ }
262
+ const rootURL = toFileDirURL(options.root || process.cwd());
263
+ function relativeIssue(fn) {
264
+ const fnFilename = options.relative ? (uri) => relativeUriFilename(uri, rootURL) : (uri) => toFilePathOrHref(toFileURL(uri, rootURL));
265
+ return (i) => {
266
+ const fullFilename = i.uri ? toFilePathOrHref(toFileURL(i.uri, rootURL)) : "";
267
+ const filename = i.uri ? fnFilename(i.uri) : "";
268
+ const r = {
269
+ ...i,
270
+ filename,
271
+ fullFilename
272
+ };
273
+ fn(r);
274
+ };
275
+ }
276
+ const repeatIssues = false;
277
+ const issuesCollection = void 0;
278
+ const errorCollection = [];
279
+ function errorEmitter(message, error) {
280
+ if (isSpellingDictionaryLoadError(error)) error = error.cause;
281
+ const errorText = formatWithOptions({ colors: stderr.stream.hasColors?.() }, stderr.chalk.red(message), debug ? error : error.toString());
282
+ errorCollection?.push(errorText);
283
+ consoleError(errorText);
284
+ }
285
+ const resultEmitter = (result) => {
286
+ if (!fileGlobs.length && !result.files) return;
287
+ const { files, issues: issues$1, cachedFiles, filesWithIssues, errors } = result;
288
+ const numFilesWithIssues = filesWithIssues.size;
289
+ if (stderr.getColorLevel() > 0) {
290
+ stderr.write("\r");
291
+ stderr.clearLine(0);
292
+ }
293
+ if (issuesCollection?.length || errorCollection?.length) consoleError("-------------------------------------------");
294
+ if (issuesCollection?.length) {
295
+ consoleError("Issues found:");
296
+ issuesCollection.forEach((issue) => consoleError(issue));
297
+ }
298
+ const cachedFilesText = cachedFiles ? ` (${cachedFiles} from cache)` : "";
299
+ const withErrorsText = errors ? ` with ${errors} error${errors === 1 ? "" : "s"}` : "";
300
+ const numFilesWidthIssuesText = numFilesWithIssues === 1 ? "1 file" : `${numFilesWithIssues} files`;
301
+ const summaryMessage = `CSpell\u003A Files checked: ${files}${cachedFilesText}, Issues found: ${issues$1} in ${numFilesWidthIssuesText}${withErrorsText}.`;
302
+ consoleError(summaryMessage);
303
+ if (errorCollection?.length && issues$1 > 5) {
304
+ consoleError("-------------------------------------------");
305
+ consoleError("Errors:");
306
+ errorCollection.forEach((error) => consoleError(error));
307
+ }
308
+ if (options.showPerfSummary) {
309
+ consoleError("-------------------------------------------");
310
+ consoleError("Performance Summary:");
311
+ consoleError(` Files Processed: ${perfStats.filesProcessed.toString().padStart(6)}`);
312
+ consoleError(` Files Skipped : ${perfStats.filesSkipped.toString().padStart(6)}`);
313
+ consoleError(` Files Cached : ${perfStats.filesCached.toString().padStart(6)}`);
314
+ consoleError(` Processing Time: ${perfStats.elapsedTimeMs.toFixed(2).padStart(9)}ms`);
315
+ consoleError("Stats:");
316
+ const stats = Object.entries(perfStats.perf).filter((p) => !!p[1]).map(([key, value]) => [key, value.toFixed(2)]);
317
+ const padName = Math.max(...stats.map((s) => s[0].length));
318
+ const padValue = Math.max(...stats.map((s) => s[1].length));
319
+ stats.sort((a, b) => a[0].localeCompare(b[0]));
320
+ for (const [key, value] of stats) value && consoleError(` ${key.padEnd(padName)}: ${value.padStart(padValue)}ms`);
321
+ }
322
+ };
323
+ function collectPerfStats(p) {
324
+ if (p.cached) {
325
+ perfStats.filesCached++;
326
+ return;
327
+ }
328
+ perfStats.filesProcessed += p.processed ? 1 : 0;
329
+ perfStats.filesSkipped += !p.processed ? 1 : 0;
330
+ perfStats.elapsedTimeMs += p.elapsedTimeMs || 0;
331
+ if (!p.perf) return;
332
+ for (const [key, value] of Object.entries(p.perf)) if (typeof value === "number") perfStats.perf[key] = (perfStats.perf[key] || 0) + value;
333
+ }
334
+ function progress(p) {
335
+ if (!silent && showProgress) reportProgress(stderr, p, rootURL, options);
336
+ if (p.type === "ProgressFileComplete") collectPerfStats(p);
337
+ }
338
+ return {
339
+ issue: relativeIssue(silent || !issues ? nullEmitter : genIssueEmitter(stdio, stderr, issueTemplate, uniqueIssues, issuesCollection)),
340
+ error: silent ? nullEmitter : errorEmitter,
341
+ info: infoEmitter,
342
+ debug: emitters.Debug,
343
+ progress,
344
+ result: !silent && summary ? resultEmitter : nullEmitter,
345
+ features: void 0
346
+ };
347
+ }
348
+ function formatIssue(io, templateStr, issue, maxIssueTextWidth) {
349
+ function clean$1(t$1) {
350
+ return t$1.replace(/\s+/, " ");
351
+ }
352
+ const { uri = "", filename, row, col, text, context = issue.line, offset } = issue;
353
+ const contextLeft = clean$1(context.text.slice(0, offset - context.offset));
354
+ const contextRight = clean$1(context.text.slice(offset + text.length - context.offset));
355
+ const contextFull = clean$1(context.text);
356
+ const padContext = " ".repeat(Math.max(maxIssueTextWidth - text.length, 0));
357
+ const rowText = row.toString();
358
+ const colText = col.toString();
359
+ const padRowCol = " ".repeat(Math.max(1, 8 - (rowText.length + colText.length)));
360
+ const suggestions$1 = formatSuggestions(io, issue);
361
+ const msg = issue.message || (issue.isFlagged ? "Forbidden word" : "Unknown word");
362
+ const messageColored = issue.isFlagged ? `{yellow ${msg}}` : msg;
363
+ const substitutions = {
364
+ $col: colText,
365
+ $contextFull: contextFull,
366
+ $contextLeft: contextLeft,
367
+ $contextRight: contextRight,
368
+ $filename: filename,
369
+ $padContext: padContext,
370
+ $padRowCol: padRowCol,
371
+ $row: rowText,
372
+ $suggestions: suggestions$1,
373
+ $text: text,
374
+ $uri: uri,
375
+ $quickFix: formatQuickFix(io, issue),
376
+ $message: msg,
377
+ $messageColored: messageColored
378
+ };
379
+ const t = templateStr.replaceAll("$messageColored", messageColored);
380
+ const chalkTemplate = makeTemplate(io.chalk);
381
+ return substitute(chalkTemplate(t), substitutions).trimEnd();
382
+ }
383
+ function formatSuggestions(io, issue) {
384
+ if (issue.suggestionsEx) return issue.suggestionsEx.map((sug) => sug.isPreferred ? io.chalk.italic(io.chalk.bold(sug.wordAdjustedToMatchCase || sug.word)) + "*" : sug.wordAdjustedToMatchCase || sug.word).join(", ");
385
+ if (issue.suggestions) return issue.suggestions.join(", ");
386
+ return "";
387
+ }
388
+ function formatQuickFix(io, issue) {
389
+ if (!issue.suggestionsEx?.length) return "";
390
+ const preferred = issue.suggestionsEx.filter((sug) => sug.isPreferred).map((sug) => sug.wordAdjustedToMatchCase || sug.word);
391
+ if (!preferred.length) return "";
392
+ const fixes = preferred.map((w) => io.chalk.italic(io.chalk.yellow(w)));
393
+ return `fix: (${fixes.join(", ")})`;
394
+ }
395
+ function substitute(text, substitutions) {
396
+ const subs = [];
397
+ for (const [match, replaceWith] of Object.entries(substitutions)) {
398
+ const len = match.length;
399
+ for (let i$1 = text.indexOf(match); i$1 >= 0; i$1 = text.indexOf(match, i$1)) {
400
+ const end = i$1 + len;
401
+ const reg = /\b/y;
402
+ reg.lastIndex = end;
403
+ if (reg.test(text)) subs.push([
404
+ i$1,
405
+ end,
406
+ replaceWith
407
+ ]);
408
+ i$1 = end;
409
+ }
410
+ }
411
+ subs.sort((a, b) => a[0] - b[0]);
412
+ let i = 0;
413
+ function sub(r) {
414
+ const [a, b, t] = r;
415
+ const prefix = text.slice(i, a);
416
+ i = b;
417
+ return prefix + t;
418
+ }
419
+ const parts = subs.map(sub);
420
+ return parts.join("") + text.slice(i);
421
+ }
422
+ function assertCheckTemplate(template) {
423
+ const r = checkTemplate(template);
424
+ if (r instanceof Error) throw r;
425
+ }
426
+ function checkTemplate(template) {
427
+ const chalk$1 = new Chalk();
428
+ const chalkTemplate = makeTemplate(chalk$1);
429
+ const substitutions = {
430
+ $col: "<col>",
431
+ $contextFull: "<contextFull>",
432
+ $contextLeft: "<contextLeft>",
433
+ $contextRight: "<contextRight>",
434
+ $filename: "<filename>",
435
+ $padContext: "<padContext>",
436
+ $padRowCol: "<padRowCol>",
437
+ $row: "<row>",
438
+ $suggestions: "<suggestions>",
439
+ $text: "<text>",
440
+ $uri: "<uri>",
441
+ $quickFix: "<quickFix>",
442
+ $message: "<message>",
443
+ $messageColored: "<messageColored>"
444
+ };
445
+ try {
446
+ const t = chalkTemplate(template);
447
+ const result = substitute(t, substitutions);
448
+ const problems = [...result.matchAll(/\$[a-z]+/gi)].map((m) => m[0]);
449
+ if (problems.length) throw new Error(`Unresolved template variable${problems.length > 1 ? "s" : ""}: ${problems.map((v) => `'${v}'`).join(", ")}`);
450
+ return true;
451
+ } catch (e) {
452
+ const msg = e instanceof Error ? e.message : `${e}`;
453
+ return new ApplicationError(msg);
454
+ }
455
+ }
456
+
457
+ //#endregion
458
+ //#region src/config/adjustConfig.ts
459
+ async function fileExists(url) {
460
+ if (url.protocol !== "file:") return false;
461
+ try {
462
+ const stats = await promises.stat(url);
463
+ return stats.isFile();
464
+ } catch (e) {
465
+ const err = toError(e);
466
+ if (err.code === "ENOENT") return false;
467
+ throw e;
468
+ }
469
+ }
470
+ async function resolveImports(configFile, imports) {
471
+ const fromConfigDir = new URL("./", configFile.url);
472
+ const fromCurrentDir = toFileDirURL("./");
473
+ const require = createRequire(fromConfigDir);
474
+ function isPackageName(name$1) {
475
+ try {
476
+ require.resolve(name$1, { paths: [fileURLToPath(fromConfigDir)] });
477
+ return true;
478
+ } catch {
479
+ return false;
480
+ }
481
+ }
482
+ const _imports = [];
483
+ for (const imp of imports) {
484
+ const url = new URL(imp, fromCurrentDir);
485
+ if (url.protocol !== "file:") {
486
+ _imports.push(imp);
487
+ continue;
488
+ }
489
+ if (await fileExists(url)) {
490
+ let rel = urlRelative(fromConfigDir, url);
491
+ if (!(rel.startsWith("./") || rel.startsWith("../"))) rel = "./" + rel;
492
+ _imports.push(rel);
493
+ continue;
494
+ }
495
+ if (url.protocol !== "file:") {
496
+ _imports.push(url.href);
497
+ continue;
498
+ }
499
+ if (isPackageName(imp)) {
500
+ _imports.push(imp);
501
+ continue;
502
+ }
503
+ throw new Error(`Cannot resolve import: ${imp}`);
504
+ }
505
+ return _imports;
506
+ }
507
+ function addImportsToMutableConfigFile(configFile, resolvedImports, comment) {
508
+ let importNode = configFile.getNode("import", []);
509
+ if (importNode.type === "scalar") {
510
+ configFile.setValue("import", [importNode.value]);
511
+ importNode = configFile.getNode("import", []);
512
+ }
513
+ assert(isCfgArrayNode(importNode));
514
+ const knownImports = new Set(importNode.value);
515
+ for (const imp of resolvedImports) {
516
+ if (knownImports.has(imp)) continue;
517
+ importNode.push(imp);
518
+ }
519
+ if (comment) configFile.setComment("import", comment);
520
+ }
521
+ async function addImportsToConfigFile(configFile, imports, comment) {
522
+ const resolvedImports = await resolveImports(configFile, imports);
523
+ if (configFile instanceof MutableCSpellConfigFile) return addImportsToMutableConfigFile(configFile, resolvedImports, comment);
524
+ const settings = configFile.settings;
525
+ let importNode = settings.import;
526
+ if (!Array.isArray(importNode)) {
527
+ importNode = typeof importNode === "string" ? [importNode] : [];
528
+ settings.import = importNode;
529
+ if (comment) configFile.setComment("import", comment);
530
+ }
531
+ assert(Array.isArray(importNode));
532
+ const knownImports = new Set(importNode);
533
+ for (const imp of resolvedImports) {
534
+ if (knownImports.has(imp)) continue;
535
+ importNode.push(imp);
536
+ }
537
+ }
538
+ function setConfigFieldValue(configFile, key, value, comment) {
539
+ configFile.setValue(key, value);
540
+ if (comment !== void 0) configFile.setComment(key, comment);
541
+ }
542
+ function addDictionariesToConfigFile(configFile, dictionaries, comment) {
543
+ if (configFile instanceof MutableCSpellConfigFile) {
544
+ const found = configFile.getValue("dictionaries");
545
+ const dicts$1 = configFile.getNode("dictionaries", []);
546
+ assert(isCfgArrayNode(dicts$1));
547
+ const knownDicts$1 = new Set(dicts$1.value);
548
+ for (const dict of dictionaries) if (!knownDicts$1.has(dict)) {
549
+ dicts$1.push(dict);
550
+ knownDicts$1.add(dict);
551
+ }
552
+ if (!found && comment) configFile.setComment("dictionaries", comment);
553
+ return;
554
+ }
555
+ const settings = configFile.settings;
556
+ const dicts = settings.dictionaries || [];
557
+ const knownDicts = new Set(dicts);
558
+ for (const dict of dictionaries) if (!knownDicts.has(dict)) {
559
+ dicts.push(dict);
560
+ knownDicts.add(dict);
561
+ }
562
+ setConfigFieldValue(configFile, "dictionaries", dicts, comment);
563
+ }
564
+
565
+ //#endregion
566
+ //#region src/config/config.ts
567
+ function applyValuesToConfigFile(config, settings, defaultValues, addComments) {
568
+ const currentSettings = config.settings || {};
569
+ for (const [k, entry] of Object.entries(defaultValues)) {
570
+ const { value: defaultValue, comment } = entry;
571
+ const key = k;
572
+ const newValue = settings[key];
573
+ const oldValue = currentSettings[key];
574
+ const value = newValue ?? oldValue ?? defaultValue;
575
+ if (newValue === void 0 && oldValue !== void 0 || value === void 0) continue;
576
+ const useComment = addComments && oldValue === void 0 && comment || void 0;
577
+ setConfigFieldValue(config, key, value, useComment);
578
+ }
579
+ return config;
580
+ }
581
+
582
+ //#endregion
583
+ //#region src/config/constants.ts
584
+ const defaultConfig = {
585
+ $schema: {
586
+ value: void 0,
587
+ comment: " The schema for the configuration file."
588
+ },
589
+ version: {
590
+ value: "0.2",
591
+ comment: " The version of the configuration file format."
592
+ },
593
+ name: {
594
+ value: void 0,
595
+ comment: " The name of the configuration. Use for display purposes only."
596
+ },
597
+ description: {
598
+ value: void 0,
599
+ comment: " A description of the configuration."
600
+ },
601
+ language: {
602
+ value: "en",
603
+ comment: " The locale to use when spell checking. (e.g., en, en-GB, de-DE"
604
+ },
605
+ import: {
606
+ value: void 0,
607
+ comment: " Configuration or packages to import."
608
+ },
609
+ dictionaryDefinitions: {
610
+ value: void 0,
611
+ comment: " Define user dictionaries."
612
+ },
613
+ dictionaries: {
614
+ value: void 0,
615
+ comment: " Enable the dictionaries."
616
+ },
617
+ ignorePaths: {
618
+ value: void 0,
619
+ comment: " Glob patterns of files to be skipped."
620
+ },
621
+ files: {
622
+ value: void 0,
623
+ comment: " Glob patterns of files to be included."
624
+ },
625
+ words: {
626
+ value: void 0,
627
+ comment: " Words to be considered correct."
628
+ },
629
+ ignoreWords: {
630
+ value: void 0,
631
+ comment: " Words to be ignored."
632
+ },
633
+ flagWords: {
634
+ value: void 0,
635
+ comment: " Words to be flagged as incorrect."
636
+ },
637
+ overrides: {
638
+ value: void 0,
639
+ comment: " Set configuration based upon file globs."
640
+ },
641
+ languageSettings: {
642
+ value: void 0,
643
+ comment: " Define language specific settings."
644
+ },
645
+ enabledFileTypes: {
646
+ value: void 0,
647
+ comment: " Enable for specific file types."
648
+ },
649
+ caseSensitive: {
650
+ value: void 0,
651
+ comment: " Enable case sensitive spell checking."
652
+ },
653
+ patterns: {
654
+ value: void 0,
655
+ comment: " Regular expression patterns."
656
+ },
657
+ ignoreRegExpList: {
658
+ value: void 0,
659
+ comment: " Regular expressions / patterns of text to be ignored."
660
+ },
661
+ includeRegExpList: {
662
+ value: void 0,
663
+ comment: " Regular expressions / patterns of text to be included."
664
+ }
665
+ };
666
+
667
+ //#endregion
668
+ //#region src/config/configInit.ts
669
+ const schemaRef = cspellConfigFileSchema;
670
+ const defaultConfigJson = `\
671
+ {
672
+ }
673
+ `;
674
+ const defaultConfigYaml = `
675
+ `;
676
+ async function configInit(options) {
677
+ const rw = createReaderWriter();
678
+ const url = determineFileNameURL(options);
679
+ const configFile = await createConfigFile(rw, url, options);
680
+ await applyOptionsToConfigFile(configFile, options);
681
+ await fs.mkdir(new URL("./", configFile.url), { recursive: true });
682
+ if (options.stdout) console.stdoutChannel.write(rw.serialize(configFile));
683
+ else await rw.writeConfig(configFile);
684
+ }
685
+ async function applyOptionsToConfigFile(configFile, options) {
686
+ const settings = {};
687
+ const addComments = options.comments || options.comments === void 0 && !options.removeComments && !configFile.url.pathname.endsWith(".json");
688
+ if (options.comments === false) configFile.removeAllComments();
689
+ if (options.schema ?? true) configFile.setSchema(schemaRef);
690
+ if (options.locale) settings.language = options.locale;
691
+ applyValuesToConfigFile(configFile, settings, defaultConfig, addComments);
692
+ if (options.import) await addImportsToConfigFile(configFile, options.import, addComments && defaultConfig.import?.comment || void 0);
693
+ if (options.dictionary) addDictionariesToConfigFile(configFile, options.dictionary, addComments && defaultConfig.dictionaries?.comment || void 0);
694
+ return configFile;
695
+ }
696
+ function determineFileNameURL(options) {
697
+ if (options.config) return toFileURL(options.config);
698
+ const defaultFileName = determineDefaultFileName(options);
699
+ const outputUrl = toFileURL(options.output || defaultFileName);
700
+ const path$2 = outputUrl.pathname;
701
+ if (path$2.endsWith(".json") || path$2.endsWith(".jsonc") || path$2.endsWith(".yaml") || path$2.endsWith(".yml")) return outputUrl;
702
+ if (/\.{m,c}?{j,t}s$/.test(path$2)) throw new Error(`Unsupported file extension: ${path$2}`);
703
+ return new URL(defaultFileName, toFileDirURL(outputUrl));
704
+ }
705
+ function determineDefaultFileName(options) {
706
+ switch (options.format || "yaml") {
707
+ case "json": return "cspell.json";
708
+ case "jsonc": return "cspell.jsonc";
709
+ case "yaml": return "cspell.config.yaml";
710
+ case "yml": return "cspell.config.yml";
711
+ }
712
+ throw new Error(`Unsupported format: ${options.format}`);
713
+ }
714
+ function getDefaultContent(options) {
715
+ switch (options.format) {
716
+ case void 0:
717
+ case "yaml": return defaultConfigYaml;
718
+ case "json":
719
+ case "jsonc": return defaultConfigJson;
720
+ default: throw new Error(`Unsupported format: ${options.format}`);
721
+ }
722
+ }
723
+ async function createConfigFile(rw, url, options) {
724
+ if (url.pathname.endsWith("package.json")) return rw.readConfig(url);
725
+ const content = await fs.readFile(url, "utf8").catch(() => getDefaultContent(options));
726
+ return rw.parse({
727
+ url,
728
+ content
729
+ });
730
+ }
731
+
732
+ //#endregion
733
+ //#region src/featureFlags/featureFlags.ts
734
+ function getFeatureFlags() {
735
+ return getSystemFeatureFlags();
736
+ }
737
+ function parseFeatureFlags(flags, featureFlags = getFeatureFlags()) {
738
+ if (!flags) return featureFlags;
739
+ const flagsKvP = flags.map((f) => f.split(":", 2));
740
+ for (const flag of flagsKvP) {
741
+ const [name$1, value] = flag;
742
+ try {
743
+ featureFlags.setFlag(name$1, value);
744
+ } catch {
745
+ console.warn(`Unknown flag: "${name$1}"`);
746
+ }
747
+ }
748
+ return featureFlags;
749
+ }
750
+
751
+ //#endregion
752
+ //#region src/environment.ts
753
+ const environmentKeys = {
754
+ CSPELL_ENABLE_DICTIONARY_LOGGING: "CSPELL_ENABLE_DICTIONARY_LOGGING",
755
+ CSPELL_ENABLE_DICTIONARY_LOG_FILE: "CSPELL_ENABLE_DICTIONARY_LOG_FILE",
756
+ CSPELL_ENABLE_DICTIONARY_LOG_FIELDS: "CSPELL_ENABLE_DICTIONARY_LOG_FIELDS",
757
+ CSPELL_GLOB_ROOT: "CSPELL_GLOB_ROOT",
758
+ CSPELL_CONFIG_PATH: "CSPELL_CONFIG_PATH",
759
+ CSPELL_DEFAULT_CONFIG_PATH: "CSPELL_DEFAULT_CONFIG_PATH"
760
+ };
761
+ function setEnvironmentVariable(key, value) {
762
+ process.env[key] = value;
763
+ }
764
+ function getEnvironmentVariable(key) {
765
+ return process.env[key];
766
+ }
767
+ function truthy(value) {
768
+ switch (value?.toLowerCase().trim()) {
769
+ case "t":
770
+ case "true":
771
+ case "on":
772
+ case "yes":
773
+ case "1": return true;
774
+ }
775
+ return false;
776
+ }
777
+
778
+ //#endregion
779
+ //#region src/dirname.ts
780
+ let _dirname;
781
+ try {
782
+ if (typeof import.meta.url !== "string") throw new Error("assert");
783
+ _dirname = fileURLToPath(new URL(".", import.meta.url));
784
+ } catch {
785
+ _dirname = __dirname;
786
+ }
787
+ const pkgDir = _dirname;
788
+
789
+ //#endregion
790
+ //#region src/pkgInfo.ts
791
+ const name = "cspell";
792
+ const version$1 = "9.2.0";
793
+ const engines = { node: ">=20" };
794
+ const npmPackage = {
795
+ name,
796
+ version: version$1,
797
+ engines
798
+ };
799
+
800
+ //#endregion
801
+ //#region src/util/async.ts
802
+ const asyncMap = operators.opMapAsync;
803
+ const asyncFilter = operators.opFilterAsync;
804
+ const asyncAwait = operators.opAwaitAsync;
805
+ const asyncFlatten = operators.opFlattenAsync;
806
+
807
+ //#endregion
808
+ //#region src/util/constants.ts
809
+ const UTF8 = "utf8";
810
+ const STDIN = "stdin";
811
+ const STDINProtocol = "stdin:";
812
+ const STDINUrlPrefix = "stdin://";
813
+ const FileUrlPrefix = "file://";
814
+ const FileUrlAbsPrefix = "file:///";
815
+
816
+ //#endregion
817
+ //#region src/util/glob.ts
818
+ const defaultExcludeGlobs = ["node_modules/**"];
819
+ /**
820
+ *
821
+ * @param pattern - glob patterns and NOT file paths. It can be a file path turned into a glob.
822
+ * @param options - search options.
823
+ */
824
+ async function globP(pattern, options) {
825
+ const cwd = options?.root || options?.cwd || process.cwd();
826
+ const ignoreRaw = typeof options?.ignore === "string" ? [options.ignore] : options?.ignore;
827
+ const ignore = ignoreRaw?.filter((g) => !g.startsWith("../"));
828
+ const onlyFiles = options?.nodir;
829
+ const dot = options?.dot;
830
+ const patterns = typeof pattern === "string" ? [pattern] : pattern;
831
+ const useOptions = clean({
832
+ cwd,
833
+ onlyFiles,
834
+ dot,
835
+ ignore,
836
+ absolute: true,
837
+ followSymbolicLinks: false,
838
+ expandDirectories: false
839
+ });
840
+ const compare$1 = new Intl.Collator("en").compare;
841
+ const absolutePaths = (await glob$1(patterns, useOptions)).sort(compare$1);
842
+ const relativePaths = absolutePaths.map((absFilename) => path$1.relative(cwd, absFilename));
843
+ return relativePaths;
844
+ }
845
+ function calcGlobs(commandLineExclude) {
846
+ const globs = new Set((commandLineExclude || []).flatMap((glob$2) => glob$2.split(/(?<!\\)\s+/g)).map((g) => g.replaceAll("\\ ", " ")));
847
+ const commandLineExcludes = {
848
+ globs: [...globs],
849
+ source: "arguments"
850
+ };
851
+ const defaultExcludes = {
852
+ globs: defaultExcludeGlobs,
853
+ source: "default"
854
+ };
855
+ return commandLineExcludes.globs.length ? commandLineExcludes : defaultExcludes;
856
+ }
857
+ function extractPatterns(globs) {
858
+ const r = globs.reduce((info, g) => {
859
+ const source = g.source;
860
+ const patterns = g.matcher.patternsNormalizedToRoot;
861
+ return [...info, ...patterns.map((glob$2) => ({
862
+ glob: glob$2,
863
+ source
864
+ }))];
865
+ }, []);
866
+ return r;
867
+ }
868
+ function calcExcludeGlobInfo(root, commandLineExclude) {
869
+ commandLineExclude = typeof commandLineExclude === "string" ? [commandLineExclude] : commandLineExclude;
870
+ const choice = calcGlobs(commandLineExclude);
871
+ const matcher = new GlobMatcher(choice.globs, {
872
+ root,
873
+ dot: true
874
+ });
875
+ return [{
876
+ matcher,
877
+ source: choice.source
878
+ }];
879
+ }
880
+ /**
881
+ * Build GlobMatcher from command line or config file globs.
882
+ * @param globs Glob patterns or file paths
883
+ * @param root - directory to use as the root
884
+ */
885
+ function buildGlobMatcher(globs, root, isExclude) {
886
+ const withRoots = globs.map((g) => {
887
+ const source = typeof g === "string" ? "command line" : void 0;
888
+ return {
889
+ source,
890
+ ...fileOrGlobToGlob(g, root)
891
+ };
892
+ });
893
+ return new GlobMatcher(withRoots, {
894
+ root,
895
+ mode: isExclude ? "exclude" : "include"
896
+ });
897
+ }
898
+ function extractGlobsFromMatcher(globMatcher) {
899
+ return globMatcher.patternsNormalizedToRoot.map((g) => g.glob);
900
+ }
901
+ function normalizeGlobsToRoot(globs, root, isExclude) {
902
+ const urls = globs.filter((g) => typeof g === "string" && isPossibleUrlRegExp.test(g));
903
+ const onlyGlobs = globs.filter((g) => typeof g !== "string" || !isPossibleUrlRegExp.test(g));
904
+ return [urls, extractGlobsFromMatcher(buildGlobMatcher(onlyGlobs, root, isExclude))].flat();
905
+ }
906
+ const isPossibleGlobRegExp = /[()*?[{}]/;
907
+ const isPossibleUrlRegExp = /^[\d_a-z-]{3,}:\/\//;
908
+ /**
909
+ * If a 'glob' is a path to a directory, then append `**` so that
910
+ * directory searches work.
911
+ * @param glob - a glob, file, or directory
912
+ * @param root - root to use.
913
+ * @returns `**` is appended directories.
914
+ */
915
+ async function adjustPossibleDirectory(glob$2, root) {
916
+ const g = typeof glob$2 === "string" ? {
917
+ glob: glob$2,
918
+ root
919
+ } : {
920
+ glob: glob$2.glob,
921
+ root: glob$2.root ?? root
922
+ };
923
+ if (isPossibleGlobRegExp.test(g.glob)) return glob$2;
924
+ if (isPossibleUrlRegExp.test(g.glob)) return glob$2;
925
+ const dirPath = path$1.resolve(g.root, g.glob);
926
+ try {
927
+ const stat$1 = await promises.stat(dirPath);
928
+ if (stat$1.isDirectory()) {
929
+ const useGlob = posix.join(posixPath(g.glob), "**");
930
+ return typeof glob$2 === "string" ? useGlob : {
931
+ ...glob$2,
932
+ glob: useGlob
933
+ };
934
+ }
935
+ } catch {
936
+ return glob$2;
937
+ }
938
+ return glob$2;
939
+ }
940
+ function posixPath(p) {
941
+ return path$1.sep === "\\" ? p.replaceAll("\\", "/") : p;
942
+ }
943
+ async function normalizeFileOrGlobsToRoot(globs, root) {
944
+ const adjustedGlobs = await Promise.all(globs.map((g) => adjustPossibleDirectory(g, root)));
945
+ return normalizeGlobsToRoot(adjustedGlobs, root, false);
946
+ }
947
+ function glob$1(patterns, options) {
948
+ patterns = typeof patterns === "string" ? workaroundPicomatchBug(patterns) : patterns.map((g) => workaroundPicomatchBug(g));
949
+ return glob(patterns, options);
950
+ }
951
+
952
+ //#endregion
953
+ //#region src/util/stdin.ts
954
+ function readStdin() {
955
+ return readline.createInterface(process.stdin);
956
+ }
957
+
958
+ //#endregion
959
+ //#region src/util/stdinUrl.ts
960
+ function isStdinUrl(url) {
961
+ if (url instanceof URL) return url.protocol === STDINProtocol;
962
+ return url.startsWith(STDINProtocol);
963
+ }
964
+ /**
965
+ * Normalize and resolve a stdin url.
966
+ * @param url - stdin url to resolve.
967
+ * @param cwd - file path to resolve relative paths against.
968
+ * @returns
969
+ */
970
+ function resolveStdinUrl(url, cwd) {
971
+ assert(url.startsWith(STDINProtocol), `Expected url to start with ${STDINProtocol}`);
972
+ const path$2 = decodeURIComponent(url).slice(STDINProtocol.length).replace(/^\/\//, "").replace(/^\/([a-z]:)/i, "$1");
973
+ const fileUrl = toFileURL(path$2, cwd);
974
+ return new URL(fileUrl.toString().replace(/^file:/, STDINProtocol) + (path$2 ? "" : "/"));
975
+ }
976
+
977
+ //#endregion
978
+ //#region src/util/fileHelper.ts
979
+ function fileInfoToDocument(fileInfo, languageId, locale) {
980
+ const { filename, text } = fileInfo;
981
+ languageId = languageId || void 0;
982
+ locale = locale || void 0;
983
+ const uri = filenameToUrl(filename);
984
+ if (uri.href.startsWith(STDINProtocol)) return clean({
985
+ uri: uri.href,
986
+ text,
987
+ languageId,
988
+ locale
989
+ });
990
+ return fileToDocument(uri.href, text, languageId, locale);
991
+ }
992
+ function filenameToUrl(filename, cwd = ".") {
993
+ if (filename instanceof URL) return filename;
994
+ const cwdURL = toFileDirURL(cwd);
995
+ if (filename === STDIN) return new URL("stdin:///");
996
+ if (isStdinUrl(filename)) return new URL(resolveStdinUrl(filename, cwd));
997
+ return toFileURL(filename, cwdURL);
998
+ }
999
+ function filenameToUri(filename, cwd) {
1000
+ return toURL(filenameToUrl(filename, cwd));
1001
+ }
1002
+ function isBinaryFile$1(filename, cwd) {
1003
+ const uri = filenameToUri(filename, cwd);
1004
+ if (uri.protocol.startsWith("stdin")) return false;
1005
+ return isBinaryFile(uri);
1006
+ }
1007
+ function resolveFilenameToUrl(filename, cwd) {
1008
+ if (filename instanceof URL) return filename;
1009
+ if (filename === STDIN) return new URL(STDINUrlPrefix);
1010
+ if (filename.startsWith(FileUrlAbsPrefix)) return new URL(filename);
1011
+ const cwdUrl = toFileDirURL(cwd || process.cwd());
1012
+ if (filename.startsWith(FileUrlPrefix)) return new URL(filename.slice(FileUrlPrefix.length), cwdUrl);
1013
+ if (isStdinUrl(filename)) return resolveStdinUrl(filename, cwdUrl);
1014
+ return toFileURL(filename, cwdUrl);
1015
+ }
1016
+ function resolveFilename(filename, cwd) {
1017
+ return toFilePathOrHref(resolveFilenameToUrl(filename, cwd));
1018
+ }
1019
+ function readFileInfo(filename, encoding = UTF8, handleNotFound = false) {
1020
+ filename = resolveFilename(filename);
1021
+ const pText = filename.startsWith(STDINProtocol) ? streamConsumers.text(process.stdin) : readFileText(filename, encoding);
1022
+ return pText.then((text) => ({
1023
+ text,
1024
+ filename
1025
+ }), (e) => {
1026
+ const error = toError(e);
1027
+ return handleNotFound && error.code === "EISDIR" ? Promise.resolve({
1028
+ text: "",
1029
+ filename,
1030
+ errorCode: error.code
1031
+ }) : handleNotFound && error.code === "ENOENT" ? Promise.resolve({
1032
+ text: "",
1033
+ filename,
1034
+ errorCode: error.code
1035
+ }) : Promise.reject(new IOError(`Error reading file: "${filename}"`, error));
1036
+ });
1037
+ }
1038
+ function readFile(filename, encoding = UTF8) {
1039
+ return readFileInfo(filename, encoding).then((info) => info.text);
1040
+ }
1041
+ /**
1042
+ * Looks for matching glob patterns or stdin
1043
+ * @param globPatterns patterns or stdin
1044
+ */
1045
+ async function findFiles(globPatterns, options) {
1046
+ const stdin = [];
1047
+ const globPats = globPatterns.filter((filename) => !isStdin(filename) && !filename.startsWith(FileUrlPrefix) ? true : (stdin.push(filename), false));
1048
+ const globResults = globPats.length ? await globP(globPats, options) : [];
1049
+ const cwd = options.cwd || process.cwd();
1050
+ return [...stdin, ...globResults].map((filename) => resolveFilename(filename, cwd));
1051
+ }
1052
+ const resolveFilenames = asyncMap(resolveFilename);
1053
+ /**
1054
+ * Read
1055
+ * @param listFiles - array of file paths to read that will contain a list of files. Paths contained in each
1056
+ * file will be resolved relative to the containing file.
1057
+ * @returns - a list of files to be processed.
1058
+ */
1059
+ function readFileListFiles(listFiles) {
1060
+ let useStdin = false;
1061
+ const files = listFiles.filter((file) => {
1062
+ const isStdin$1 = file === "stdin";
1063
+ useStdin = useStdin || isStdin$1;
1064
+ return !isStdin$1;
1065
+ });
1066
+ const found = asyncPipe(files, asyncMap((file) => readFileListFile(file)), asyncAwait(), asyncFlatten());
1067
+ const stdin = useStdin ? readStdin() : [];
1068
+ return asyncPipe(mergeAsyncIterables(found, stdin), resolveFilenames);
1069
+ }
1070
+ /**
1071
+ * Read a `listFile` and return the containing file paths resolved relative to the `listFile`.
1072
+ * @param listFiles - array of file paths to read that will contain a list of files. Paths contained in each
1073
+ * file will be resolved relative to the containing file.
1074
+ * @returns - a list of files to be processed.
1075
+ */
1076
+ async function readFileListFile(listFile) {
1077
+ try {
1078
+ const relTo = path$1.resolve(path$1.dirname(listFile));
1079
+ const content = await readFile(listFile);
1080
+ const lines = content.split("\n").map((a) => a.trim()).filter((a) => !!a).map((file) => path$1.resolve(relTo, file));
1081
+ return lines;
1082
+ } catch (err) {
1083
+ throw toApplicationError(err, `Error reading file list from: "${listFile}"`);
1084
+ }
1085
+ }
1086
+ function isStdin(filename) {
1087
+ return filename === STDIN || isStdinUrl(filename);
1088
+ }
1089
+ async function isFile(filename) {
1090
+ if (isStdin(filename)) return true;
1091
+ try {
1092
+ const stat$1 = await promises.stat(filename);
1093
+ return stat$1.isFile();
1094
+ } catch {
1095
+ return false;
1096
+ }
1097
+ }
1098
+ async function isDir(filename) {
1099
+ try {
1100
+ const stat$1 = await promises.stat(filename);
1101
+ return stat$1.isDirectory();
1102
+ } catch {
1103
+ return false;
1104
+ }
1105
+ }
1106
+ function isNotDir(filename) {
1107
+ return isDir(filename).then((a) => !a);
1108
+ }
1109
+ function relativeToCwd(filename, cwd = process.cwd()) {
1110
+ const urlCwd = toFileDirURL(cwd);
1111
+ const url = toFileURL(filename, urlCwd);
1112
+ const rel = urlRelative(urlCwd, url);
1113
+ if (rel.startsWith("..")) return toFilePathOrHref(url);
1114
+ return rel;
1115
+ }
1116
+
1117
+ //#endregion
1118
+ //#region src/util/cache/file-entry-cache/flatCache.ts
1119
+ var FlatCache = class {
1120
+ #cache;
1121
+ constructor(cacheFilename) {
1122
+ this.cacheFilename = cacheFilename;
1123
+ this.#cache = /* @__PURE__ */ new Map();
1124
+ }
1125
+ keys() {
1126
+ return this.#cache.keys();
1127
+ }
1128
+ set(key, value) {
1129
+ this.#cache.set(key, value);
1130
+ return this;
1131
+ }
1132
+ removeKey(key) {
1133
+ this.#cache.delete(key);
1134
+ }
1135
+ get(key) {
1136
+ return this.#cache.get(key);
1137
+ }
1138
+ async load(ifFound = true) {
1139
+ this.#cache.clear();
1140
+ try {
1141
+ const content = await fs.readFile(this.cacheFilename, "utf8");
1142
+ this.#cache = new Map(Object.entries(parse(content)));
1143
+ } catch (error) {
1144
+ if (!ifFound) throw error;
1145
+ }
1146
+ return this;
1147
+ }
1148
+ async save() {
1149
+ const dir = new URL(".", this.cacheFilename);
1150
+ await fs.mkdir(dir, { recursive: true });
1151
+ const content = stringify(Object.fromEntries(this.#cache.entries()));
1152
+ await fs.writeFile(this.cacheFilename, content, "utf8");
1153
+ }
1154
+ /**
1155
+ * Clear the cache and remove the cache file from disk.
1156
+ */
1157
+ async destroy() {
1158
+ this.#cache.clear();
1159
+ try {
1160
+ await fs.unlink(this.cacheFilename);
1161
+ } catch {}
1162
+ }
1163
+ };
1164
+ /**
1165
+ *
1166
+ * @param cachefile - The location of the cache file.
1167
+ * @returns
1168
+ */
1169
+ function loadCacheFile(cachefile) {
1170
+ const cache = new FlatCache(cachefile);
1171
+ return cache.load();
1172
+ }
1173
+
1174
+ //#endregion
1175
+ //#region src/util/cache/file-entry-cache/file-entry-cache.ts
1176
+ async function createFromFile$1(cacheFileUrl, useChecksum, currentWorkingDir) {
1177
+ const cache = await loadCacheFile(cacheFileUrl);
1178
+ const fec = new ImplFileEntryCache(cache, useChecksum ?? false, currentWorkingDir);
1179
+ await fec.removeNotFoundFiles();
1180
+ return fec;
1181
+ }
1182
+ var ImplFileEntryCache = class {
1183
+ cache;
1184
+ useChecksum;
1185
+ #normalizedEntries = /* @__PURE__ */ new Map();
1186
+ /**
1187
+ * To enable relative paths as the key with current working directory
1188
+ */
1189
+ currentWorkingDir;
1190
+ constructor(cache, useChecksum, currentWorkingDir) {
1191
+ this.cache = cache;
1192
+ this.useChecksum = useChecksum || false;
1193
+ this.currentWorkingDir = currentWorkingDir ? fileURLToPath(currentWorkingDir) : void 0;
1194
+ }
1195
+ async removeNotFoundFiles() {
1196
+ for (const fPath of this.cache.keys()) try {
1197
+ const filePath = this.resolveKeyToFile(fPath);
1198
+ await fs.stat(filePath);
1199
+ } catch (error) {
1200
+ if (isNodeError(error) && error.code === "ENOENT") this.cache.removeKey(fPath);
1201
+ }
1202
+ }
1203
+ /**
1204
+ * Given a buffer, calculate md5 hash of its content.
1205
+ * @param buffer buffer to calculate hash on
1206
+ * @return content hash digest
1207
+ */
1208
+ #getHash(buffer) {
1209
+ return crypto.createHash("md5").update(buffer).digest("hex");
1210
+ }
1211
+ async getFileDescriptor(file) {
1212
+ let fstat;
1213
+ try {
1214
+ fstat = await fs.stat(file);
1215
+ } catch (error) {
1216
+ this.#removeEntry(file);
1217
+ return {
1218
+ key: file,
1219
+ notFound: true,
1220
+ err: toError$1(error)
1221
+ };
1222
+ }
1223
+ if (this.useChecksum) return this.#getFileDescriptorUsingChecksum(file);
1224
+ return this.#getFileDescriptorUsingMtimeAndSize(file, fstat);
1225
+ }
1226
+ #getFileDescriptorUsingMtimeAndSize(file, fstat) {
1227
+ const key = this.#getFileKey(file);
1228
+ let meta = this.cache.get(key);
1229
+ const cacheExists = !!meta;
1230
+ const cSize = fstat.size;
1231
+ const cTime = fstat.mtime.getTime();
1232
+ let isDifferentDate;
1233
+ let isDifferentSize;
1234
+ if (meta) {
1235
+ isDifferentDate = cTime !== meta.mtime;
1236
+ isDifferentSize = cSize !== meta.size;
1237
+ } else meta = {
1238
+ size: cSize,
1239
+ mtime: cTime
1240
+ };
1241
+ const nEntry = {
1242
+ key,
1243
+ changed: !cacheExists || isDifferentDate || isDifferentSize,
1244
+ meta
1245
+ };
1246
+ this.#normalizedEntries.set(key, nEntry);
1247
+ return nEntry;
1248
+ }
1249
+ async #getFileDescriptorUsingChecksum(file) {
1250
+ const key = this.#getFileKey(file);
1251
+ let meta = this.cache.get(key);
1252
+ const cacheExists = !!meta;
1253
+ let contentBuffer;
1254
+ try {
1255
+ contentBuffer = await fs.readFile(file);
1256
+ } catch {
1257
+ contentBuffer = "";
1258
+ }
1259
+ let isDifferent = true;
1260
+ const hash = this.#getHash(contentBuffer);
1261
+ if (meta) isDifferent = hash !== meta.hash;
1262
+ else meta = { hash };
1263
+ const nEntry = {
1264
+ key,
1265
+ changed: !cacheExists || isDifferent,
1266
+ meta
1267
+ };
1268
+ this.#normalizedEntries.set(key, nEntry);
1269
+ return nEntry;
1270
+ }
1271
+ /**
1272
+ * Remove an entry from the file-entry-cache. Useful to force the file to still be considered
1273
+ * modified the next time the process is run
1274
+ */
1275
+ #removeEntry(file) {
1276
+ const key = this.#getFileKey(file);
1277
+ this.#normalizedEntries.delete(key);
1278
+ this.cache.removeKey(key);
1279
+ }
1280
+ /**
1281
+ * Deletes the cache file from the disk and clears the memory cache
1282
+ */
1283
+ async destroy() {
1284
+ this.#normalizedEntries.clear();
1285
+ await this.cache.destroy();
1286
+ }
1287
+ async #getMetaForFileUsingCheckSum(cacheEntry) {
1288
+ const filePath = this.resolveKeyToFile(cacheEntry.key);
1289
+ const contentBuffer = await fs.readFile(filePath);
1290
+ const hash = this.#getHash(contentBuffer);
1291
+ const meta = {
1292
+ ...cacheEntry.meta,
1293
+ hash
1294
+ };
1295
+ delete meta.size;
1296
+ delete meta.mtime;
1297
+ return meta;
1298
+ }
1299
+ async #getMetaForFileUsingMtimeAndSize(cacheEntry) {
1300
+ const filePath = this.resolveKeyToFile(cacheEntry.key);
1301
+ const stat$1 = await fs.stat(filePath);
1302
+ const meta = {
1303
+ ...cacheEntry.meta,
1304
+ size: stat$1.size,
1305
+ mtime: stat$1.mtime.getTime()
1306
+ };
1307
+ delete meta.hash;
1308
+ return meta;
1309
+ }
1310
+ /**
1311
+ * Sync the files and persist them to the cache
1312
+ */
1313
+ async reconcile() {
1314
+ await this.removeNotFoundFiles();
1315
+ for (const [entryKey, cacheEntry] of this.#normalizedEntries.entries()) try {
1316
+ const meta = this.useChecksum ? await this.#getMetaForFileUsingCheckSum(cacheEntry) : await this.#getMetaForFileUsingMtimeAndSize(cacheEntry);
1317
+ this.cache.set(entryKey, meta);
1318
+ } catch (error) {
1319
+ if (!isNodeError(error) || error.code !== "ENOENT") throw error;
1320
+ }
1321
+ this.cache.save();
1322
+ }
1323
+ resolveKeyToFile(entryKey) {
1324
+ if (this.currentWorkingDir) return path.resolve(this.currentWorkingDir, entryKey);
1325
+ return entryKey;
1326
+ }
1327
+ #getFileKey(file) {
1328
+ if (this.currentWorkingDir && path.isAbsolute(file)) return normalizePath$1(path.relative(this.currentWorkingDir, file));
1329
+ return normalizePath$1(file);
1330
+ }
1331
+ };
1332
+ function isNodeError(error) {
1333
+ return typeof error === "object" && error !== null && "code" in error;
1334
+ }
1335
+ function toError$1(error) {
1336
+ if (error instanceof Error) return error;
1337
+ if (typeof error === "string") return new Error(error);
1338
+ return new Error("Unknown error", { cause: error });
1339
+ }
1340
+ function normalizePath$1(filePath) {
1341
+ if (path.sep === "/") return filePath;
1342
+ return filePath.split(path.sep).join("/");
1343
+ }
1344
+
1345
+ //#endregion
1346
+ //#region src/util/cache/fileEntryCache.ts
1347
+ function createFromFile(cacheFileUrl, useCheckSum, useRelative) {
1348
+ return createFromFile$1(cacheFileUrl, useCheckSum, useRelative ? new URL("./", cacheFileUrl) : void 0);
1349
+ }
1350
+
1351
+ //#endregion
1352
+ //#region src/util/cache/ObjectCollection.ts
1353
+ const compare = Intl.Collator().compare;
1354
+ var ShallowObjectCollection = class {
1355
+ tree = {};
1356
+ get(v) {
1357
+ if (typeof v !== "object" || v === null) return v;
1358
+ const keys = Object.entries(v).filter((entry) => entry[1] !== void 0).sort((a, b) => compare(a[0], b[0]));
1359
+ let t = this.tree;
1360
+ for (const [key, obj] of keys) {
1361
+ if (!t.c) t.c = /* @__PURE__ */ new Map();
1362
+ const c0 = t.c.get(key);
1363
+ const cc = c0 || /* @__PURE__ */ new Map();
1364
+ if (!c0) t.c.set(key, cc);
1365
+ const c1 = cc.get(obj);
1366
+ const ccc = c1 || {};
1367
+ if (!c1) cc.set(obj, ccc);
1368
+ t = ccc;
1369
+ }
1370
+ if (t.v) return t.v;
1371
+ t.v = v;
1372
+ return v;
1373
+ }
1374
+ };
1375
+
1376
+ //#endregion
1377
+ //#region src/util/cache/DiskCache.ts
1378
+ const cacheDataKeys = {
1379
+ v: "v",
1380
+ r: "r",
1381
+ d: "d"
1382
+ };
1383
+ /**
1384
+ * Meta Data Version is used to detect if the structure of the meta data has changed.
1385
+ * This is used in combination with the Suffix and the version of CSpell.
1386
+ */
1387
+ const META_DATA_BASE_VERSION = "1";
1388
+ const META_DATA_VERSION_SUFFIX = "-" + META_DATA_BASE_VERSION + "-" + Object.keys(cacheDataKeys).join("|");
1389
+ /**
1390
+ * Caches cspell results on disk
1391
+ */
1392
+ var DiskCache = class {
1393
+ cacheDir;
1394
+ dependencyCache = /* @__PURE__ */ new Map();
1395
+ dependencyCacheTree = {};
1396
+ objectCollection = new ShallowObjectCollection();
1397
+ ocCacheFileResult = new ShallowObjectCollection();
1398
+ version;
1399
+ constructor(cacheFileLocation, useCheckSum, cspellVersion, useUniversalCache, fileEntryCache) {
1400
+ this.cacheFileLocation = cacheFileLocation;
1401
+ this.useCheckSum = useCheckSum;
1402
+ this.cspellVersion = cspellVersion;
1403
+ this.useUniversalCache = useUniversalCache;
1404
+ this.fileEntryCache = fileEntryCache;
1405
+ this.cacheDir = fileURLToPath(new URL("./", cacheFileLocation));
1406
+ this.version = calcVersion(cspellVersion);
1407
+ }
1408
+ async getCachedLintResults(filename) {
1409
+ filename = normalizePath(filename);
1410
+ const fileDescriptor = await this.fileEntryCache.getFileDescriptor(filename);
1411
+ const meta = fileDescriptor.meta;
1412
+ const data = meta?.data;
1413
+ const result = data?.r;
1414
+ const versionMatches = this.version === data?.v;
1415
+ if (fileDescriptor.notFound || fileDescriptor.changed || !meta || !result || !versionMatches || !await this.checkDependencies(data.d)) return void 0;
1416
+ const dd = { ...data };
1417
+ if (dd.d) dd.d = setTreeEntry(this.dependencyCacheTree, dd.d);
1418
+ dd.r = dd.r && this.normalizeResult(dd.r);
1419
+ meta.data = this.objectCollection.get(dd);
1420
+ const hasErrors = !!result && (result.errors > 0 || result.configErrors > 0 || result.issues.length > 0);
1421
+ const cached = true;
1422
+ const shouldReadFile = hasErrors;
1423
+ return {
1424
+ ...result,
1425
+ elapsedTimeMs: void 0,
1426
+ fileInfo: shouldReadFile ? await readFileInfo(filename) : { filename },
1427
+ cached
1428
+ };
1429
+ }
1430
+ async setCachedLintResults({ fileInfo, elapsedTimeMs: _, cached: __,...result }, dependsUponFiles) {
1431
+ const fileDescriptor = await this.fileEntryCache.getFileDescriptor(fileInfo.filename);
1432
+ const meta = fileDescriptor.meta;
1433
+ if (fileDescriptor.notFound || !meta) return;
1434
+ const data = this.objectCollection.get({
1435
+ v: this.version,
1436
+ r: this.normalizeResult(result),
1437
+ d: await this.calcDependencyHashes(dependsUponFiles)
1438
+ });
1439
+ meta.data = data;
1440
+ }
1441
+ async reconcile() {
1442
+ await this.fileEntryCache.reconcile();
1443
+ }
1444
+ async reset() {
1445
+ await this.fileEntryCache.destroy();
1446
+ this.dependencyCache.clear();
1447
+ this.dependencyCacheTree = {};
1448
+ this.objectCollection = new ShallowObjectCollection();
1449
+ this.ocCacheFileResult = new ShallowObjectCollection();
1450
+ }
1451
+ normalizeResult(result) {
1452
+ const { issues, processed, errors, configErrors, reportIssueOptions,...rest } = result;
1453
+ if (!Object.keys(rest).length) return this.ocCacheFileResult.get(result);
1454
+ return this.ocCacheFileResult.get({
1455
+ issues,
1456
+ processed,
1457
+ errors,
1458
+ configErrors,
1459
+ reportIssueOptions
1460
+ });
1461
+ }
1462
+ async calcDependencyHashes(dependsUponFiles) {
1463
+ dependsUponFiles.sort();
1464
+ const c = getTreeEntry(this.dependencyCacheTree, dependsUponFiles);
1465
+ if (c?.d) return c.d;
1466
+ const dependencies = await Promise.all(dependsUponFiles.map((f) => this.getDependency(f)));
1467
+ return setTreeEntry(this.dependencyCacheTree, dependencies);
1468
+ }
1469
+ async checkDependency(dep) {
1470
+ const depFile = this.resolveFile(dep.f);
1471
+ const cDep = this.dependencyCache.get(depFile);
1472
+ if (cDep && compDep(dep, cDep)) return true;
1473
+ if (cDep) return false;
1474
+ const d = await this.getFileDep(depFile);
1475
+ if (compDep(dep, d)) {
1476
+ this.dependencyCache.set(depFile, dep);
1477
+ return true;
1478
+ }
1479
+ this.dependencyCache.set(depFile, d);
1480
+ return false;
1481
+ }
1482
+ async getDependency(file) {
1483
+ const dep = this.dependencyCache.get(file);
1484
+ if (dep) return dep;
1485
+ const d = await this.getFileDep(file);
1486
+ this.dependencyCache.set(file, d);
1487
+ return d;
1488
+ }
1489
+ async getFileDep(file) {
1490
+ if (isUrlLike(file)) {
1491
+ if (!file.startsWith("file://")) return getDependencyForUrl(file);
1492
+ file = toFilePathOrHref(file);
1493
+ }
1494
+ assert(isAbsolute(file), `Dependency must be absolute "${file}"`);
1495
+ const f = this.toRelFile(file);
1496
+ let h;
1497
+ try {
1498
+ const buffer = await fs.readFile(file);
1499
+ h = this.getHash(buffer);
1500
+ } catch {
1501
+ return { f };
1502
+ }
1503
+ return {
1504
+ f,
1505
+ h
1506
+ };
1507
+ }
1508
+ async checkDependencies(dependencies) {
1509
+ if (!dependencies) return false;
1510
+ for (const dep of dependencies) if (!await this.checkDependency(dep)) return false;
1511
+ return true;
1512
+ }
1513
+ getHash(buffer) {
1514
+ return crypto.createHash("md5").update(buffer).digest("hex");
1515
+ }
1516
+ resolveFile(file) {
1517
+ if (isUrlLike(file)) return file;
1518
+ return normalizePath(resolve(this.cacheDir, file));
1519
+ }
1520
+ toRelFile(file) {
1521
+ return normalizePath(this.useUniversalCache ? relative(this.cacheDir, file) : file);
1522
+ }
1523
+ };
1524
+ async function getDependencyForUrl(remoteUrl) {
1525
+ const url = new URL(remoteUrl);
1526
+ try {
1527
+ const response = await fetch(url, { method: "HEAD" });
1528
+ const h = response.headers.get("etag") || response.headers.get("last-modified") || response.headers.get("content-length") || "";
1529
+ return {
1530
+ f: url.href,
1531
+ h: h ? h.trim() : ""
1532
+ };
1533
+ } catch {
1534
+ return {
1535
+ f: url.href,
1536
+ h: ""
1537
+ };
1538
+ }
1539
+ }
1540
+ async function createDiskCache(cacheFileLocation, useCheckSum, cspellVersion, useUniversalCache) {
1541
+ const fileEntryCache = await createFromFile(cacheFileLocation, useCheckSum, useUniversalCache);
1542
+ const cache = new DiskCache(cacheFileLocation, useCheckSum, cspellVersion, useUniversalCache, fileEntryCache);
1543
+ return cache;
1544
+ }
1545
+ function getTreeEntry(tree, keys) {
1546
+ let r = tree;
1547
+ for (const k of keys) {
1548
+ r = r.c?.get(k);
1549
+ if (!r) return r;
1550
+ }
1551
+ return r;
1552
+ }
1553
+ function setTreeEntry(tree, deps, update = false) {
1554
+ let r = tree;
1555
+ for (const d$1 of deps) {
1556
+ const k = d$1.f;
1557
+ if (!r.c) r.c = /* @__PURE__ */ new Map();
1558
+ const cn = r.c.get(k);
1559
+ const n = cn ?? {};
1560
+ if (!cn) r.c.set(k, n);
1561
+ r = n;
1562
+ }
1563
+ let d = r.d;
1564
+ if (!d || r.d && update) {
1565
+ r.d = deps;
1566
+ d = deps;
1567
+ }
1568
+ return d;
1569
+ }
1570
+ function compDep(a, b) {
1571
+ return a.f === b.f && a.h === b.h;
1572
+ }
1573
+ function calcVersion(version$2) {
1574
+ return version$2 + META_DATA_VERSION_SUFFIX;
1575
+ }
1576
+ function normalizePath(filePath) {
1577
+ if (sep === "/") return filePath;
1578
+ return filePath.split(sep).join("/");
1579
+ }
1580
+
1581
+ //#endregion
1582
+ //#region src/util/cache/DummyCache.ts
1583
+ /**
1584
+ * Dummy cache implementation that should be usd if caching option is disabled.
1585
+ */
1586
+ var DummyCache = class {
1587
+ getCachedLintResults() {
1588
+ return Promise.resolve(void 0);
1589
+ }
1590
+ setCachedLintResults() {
1591
+ return Promise.resolve();
1592
+ }
1593
+ reconcile() {
1594
+ return Promise.resolve();
1595
+ }
1596
+ reset() {
1597
+ return Promise.resolve();
1598
+ }
1599
+ };
1600
+
1601
+ //#endregion
1602
+ //#region src/util/cache/createCache.ts
1603
+ const DEFAULT_CACHE_LOCATION = ".cspellcache";
1604
+ const versionSuffix = "";
1605
+ /**
1606
+ * Creates CSpellLintResultCache (disk cache if caching is enabled in config or dummy otherwise)
1607
+ */
1608
+ async function createCache(options) {
1609
+ const { useCache, cacheLocation, cacheStrategy, reset } = options;
1610
+ const location = toFileURL(cacheLocation);
1611
+ const useChecksum = cacheStrategy === "content";
1612
+ const version$2 = normalizeVersion(options.version);
1613
+ const useUniversal = options.cacheFormat === "universal";
1614
+ const cache = useCache ? await createDiskCache(location, useChecksum, version$2, useUniversal) : new DummyCache();
1615
+ if (reset) await cache.reset();
1616
+ return cache;
1617
+ }
1618
+ async function calcCacheSettings(config, cacheOptions, root) {
1619
+ const cs = config.cache ?? {};
1620
+ const useCache = cacheOptions.cache ?? cs.useCache ?? false;
1621
+ const cacheLocation = await resolveCacheLocation(path.resolve(root, cacheOptions.cacheLocation ?? cs.cacheLocation ?? DEFAULT_CACHE_LOCATION));
1622
+ const cacheStrategy = cacheOptions.cacheStrategy ?? cs.cacheStrategy ?? "content";
1623
+ const cacheFormat = cacheOptions.cacheFormat ?? cs.cacheFormat ?? "universal";
1624
+ const optionals = {};
1625
+ if (cacheOptions.cacheReset) optionals.reset = true;
1626
+ return {
1627
+ ...optionals,
1628
+ useCache,
1629
+ cacheLocation,
1630
+ cacheStrategy,
1631
+ version: cacheOptions.version,
1632
+ cacheFormat
1633
+ };
1634
+ }
1635
+ async function resolveCacheLocation(cacheLocation) {
1636
+ try {
1637
+ const s = await stat(cacheLocation);
1638
+ if (s.isFile()) return cacheLocation;
1639
+ return path.join(cacheLocation, DEFAULT_CACHE_LOCATION);
1640
+ } catch (err) {
1641
+ if (isErrorLike(err) && err.code === "ENOENT") return cacheLocation;
1642
+ throw err;
1643
+ }
1644
+ }
1645
+ /**
1646
+ * Normalizes the version and return only `major.minor + versionSuffix`
1647
+ * @param version The cspell semantic version.
1648
+ */
1649
+ function normalizeVersion(version$2) {
1650
+ const parts = version$2.split(".").slice(0, 2);
1651
+ assert(parts.length === 2);
1652
+ return parts.join(".") + versionSuffix;
1653
+ }
1654
+
1655
+ //#endregion
1656
+ //#region src/util/configFileHelper.ts
1657
+ async function readConfig(configFile, root, stopConfigSearchAt) {
1658
+ configFile ??= getEnvironmentVariable(environmentKeys.CSPELL_CONFIG_PATH);
1659
+ if (configFile) {
1660
+ const cfgFile = typeof configFile === "string" ? await readConfigHandleError(configFile) : configFile;
1661
+ return configFileToConfigInfo(cfgFile);
1662
+ }
1663
+ const config = await cspell.searchForConfig(root, { stopSearchAt: stopConfigSearchAt });
1664
+ const defaultConfigFile = getEnvironmentVariable(environmentKeys.CSPELL_DEFAULT_CONFIG_PATH);
1665
+ if (!config && defaultConfigFile) {
1666
+ const cfgFile = await readConfigFile(defaultConfigFile).catch(() => void 0);
1667
+ if (cfgFile) return configFileToConfigInfo(cfgFile);
1668
+ }
1669
+ return {
1670
+ source: config?.__importRef?.filename || "None found",
1671
+ config: config || {}
1672
+ };
1673
+ }
1674
+ async function configFileToConfigInfo(cfgFile) {
1675
+ const config = await cspell.resolveConfigFileImports(cfgFile);
1676
+ const source = toFilePathOrHref(cfgFile.url);
1677
+ return {
1678
+ source,
1679
+ config
1680
+ };
1681
+ }
1682
+ function readConfigFile(filename) {
1683
+ return cspell.readConfigFile(filename);
1684
+ }
1685
+ async function readConfigHandleError(filename) {
1686
+ try {
1687
+ return await readConfigFile(filename);
1688
+ } catch (e) {
1689
+ const settings = { __importRef: {
1690
+ filename: filename.toString(),
1691
+ error: e
1692
+ } };
1693
+ return {
1694
+ url: filenameToUrl(filename),
1695
+ settings
1696
+ };
1697
+ }
1698
+ }
1699
+
1700
+ //#endregion
1701
+ //#region src/util/extractContext.ts
1702
+ function prefCharIndex(text, offset, count = 1) {
1703
+ if (offset - count < 0) return 0;
1704
+ for (; count > 0 && offset > 0; count--) {
1705
+ let code = text.charCodeAt(--offset) || 0;
1706
+ if (code === 65039) code = text.charCodeAt(--offset) || 0;
1707
+ offset -= (code & 64512) === 56320 ? 1 : 0;
1708
+ }
1709
+ return offset < 0 ? 0 : offset;
1710
+ }
1711
+ function nextCharIndex(text, offset, count = 1) {
1712
+ if (offset + count >= text.length) return text.length;
1713
+ for (; count > 0 && offset < text.length; count--) {
1714
+ const code = text.charCodeAt(offset++) || 0;
1715
+ offset += (code & 64512) === 55296 ? 1 : 0;
1716
+ if (text.charCodeAt(offset) === 65039) offset++;
1717
+ }
1718
+ return offset > text.length ? text.length : offset;
1719
+ }
1720
+ function lineContext(lineText, start, end, contextRange) {
1721
+ let left = prefCharIndex(lineText, start, contextRange);
1722
+ let right = nextCharIndex(lineText, end, contextRange);
1723
+ const isLetter = /^\p{L}$/u;
1724
+ const isMark = /^\p{M}$/u;
1725
+ for (let n = contextRange / 2; n > 0 && left > 0; n--, left--) {
1726
+ const c = lineText[left - 1];
1727
+ if (isMark.test(c)) {
1728
+ if (!isLetter.test(lineText[left - 2])) break;
1729
+ left--;
1730
+ continue;
1731
+ }
1732
+ if (!isLetter.test(lineText[left - 1])) break;
1733
+ }
1734
+ for (let n = contextRange / 2; n > 0 && right < lineText.length; n--, right++) {
1735
+ if (!isLetter.test(lineText[right])) break;
1736
+ if (isMark.test(lineText[right + 1])) right++;
1737
+ }
1738
+ left = left < 0 ? 0 : left;
1739
+ const t0 = lineText.slice(left, right);
1740
+ const tLeft = t0.trimStart();
1741
+ left = Math.min(left + t0.length - tLeft.length, start);
1742
+ const text = tLeft.trimEnd();
1743
+ const context = {
1744
+ text,
1745
+ offset: left
1746
+ };
1747
+ return context;
1748
+ }
1749
+ function extractContext(tdo, contextRange) {
1750
+ const { line, offset, text } = tdo;
1751
+ const start = offset - line.offset;
1752
+ const context = lineContext(line.text, start, start + text.length, contextRange);
1753
+ context.offset += line.offset;
1754
+ return context;
1755
+ }
1756
+
1757
+ //#endregion
1758
+ //#region src/util/prefetch.ts
1759
+ function* prefetchIterable(iterable, size) {
1760
+ assert(size >= 0);
1761
+ const buffer = [];
1762
+ for (const value of iterable) {
1763
+ buffer.push(value);
1764
+ if (buffer.length >= size - 1) {
1765
+ const value$1 = buffer[0];
1766
+ buffer.shift();
1767
+ yield value$1;
1768
+ }
1769
+ }
1770
+ yield* buffer;
1771
+ }
1772
+
1773
+ //#endregion
1774
+ //#region src/util/reporters.ts
1775
+ function filterFeatureIssues(features, issue, reportOptions) {
1776
+ if (issue.issueType === IssueType.directive) return features?.issueType && reportOptions?.validateDirectives || false;
1777
+ if (features?.unknownWords) return true;
1778
+ if (!reportOptions) return true;
1779
+ if (issue.isFlagged || !reportOptions.unknownWords || reportOptions.unknownWords === unknownWordsChoices.ReportAll) return true;
1780
+ if (issue.hasPreferredSuggestions && reportOptions.unknownWords !== unknownWordsChoices.ReportFlagged) return true;
1781
+ if (issue.hasSimpleSuggestions && reportOptions.unknownWords === unknownWordsChoices.ReportSimple) return true;
1782
+ return false;
1783
+ }
1784
+ function handleIssue(reporter, issue, reportOptions) {
1785
+ if (!reporter.issue) return;
1786
+ if (!filterFeatureIssues(reporter.features, issue, reportOptions)) return;
1787
+ if (!reporter.features?.contextGeneration && !issue.context) {
1788
+ issue = { ...issue };
1789
+ issue.context = issue.line;
1790
+ }
1791
+ return reporter.issue(issue, reportOptions);
1792
+ }
1793
+ /**
1794
+ * Loads reporter modules configured in cspell config file
1795
+ */
1796
+ async function loadReporters(reporters, defaultReporter, config) {
1797
+ async function loadReporter(reporterSettings) {
1798
+ if (reporterSettings === "default") return defaultReporter;
1799
+ if (!Array.isArray(reporterSettings)) reporterSettings = [reporterSettings];
1800
+ const [moduleName, settings] = reporterSettings;
1801
+ try {
1802
+ const { getReporter: getReporter$1 } = await dynamicImport(moduleName, [process.cwd(), pkgDir]);
1803
+ return getReporter$1(settings, config);
1804
+ } catch (e) {
1805
+ throw new ApplicationError(`Failed to load reporter ${moduleName}: ${toError(e).message}`);
1806
+ }
1807
+ }
1808
+ reporters = !reporters || !reporters.length ? ["default"] : [...reporters];
1809
+ const loadedReporters = await Promise.all(reporters.map(loadReporter));
1810
+ return loadedReporters.filter((v) => v !== void 0);
1811
+ }
1812
+ function finalizeReporter(reporter) {
1813
+ if (!reporter) return void 0;
1814
+ if (reporterIsFinalized(reporter)) return reporter;
1815
+ const final = {
1816
+ issue: (...params) => reporter.issue?.(...params),
1817
+ info: (...params) => reporter.info?.(...params),
1818
+ debug: (...params) => reporter.debug?.(...params),
1819
+ progress: (...params) => reporter.progress?.(...params),
1820
+ error: (...params) => reporter.error?.(...params),
1821
+ result: (...params) => reporter.result?.(...params),
1822
+ features: reporter.features
1823
+ };
1824
+ return final;
1825
+ }
1826
+ function reporterIsFinalized(reporter) {
1827
+ return !!reporter && reporter.features && typeof reporter.issue === "function" && typeof reporter.info === "function" && typeof reporter.debug === "function" && typeof reporter.error === "function" && typeof reporter.progress === "function" && typeof reporter.result === "function" || false;
1828
+ }
1829
+ const reportIssueOptionsKeyMap = {
1830
+ unknownWords: "unknownWords",
1831
+ validateDirectives: "validateDirectives",
1832
+ showContext: "showContext"
1833
+ };
1834
+ function setValue(options, key, value) {
1835
+ if (value !== void 0) options[key] = value;
1836
+ }
1837
+ function extractReporterIssueOptions(settings) {
1838
+ const src = settings;
1839
+ const options = {};
1840
+ for (const key in reportIssueOptionsKeyMap) {
1841
+ const k = key;
1842
+ setValue(options, k, src[k]);
1843
+ }
1844
+ return options;
1845
+ }
1846
+ function mergeReportIssueOptions(a, b) {
1847
+ const options = extractReporterIssueOptions(a);
1848
+ if (!b) return options;
1849
+ for (const key in reportIssueOptionsKeyMap) {
1850
+ const k = key;
1851
+ setValue(options, k, b[k]);
1852
+ }
1853
+ return options;
1854
+ }
1855
+ var LintReporter = class {
1856
+ #reporters = [];
1857
+ #config;
1858
+ #finalized = false;
1859
+ constructor(defaultReporter, config) {
1860
+ this.defaultReporter = defaultReporter;
1861
+ this.#config = config;
1862
+ if (defaultReporter) this.#reporters.push(finalizeReporter(defaultReporter));
1863
+ }
1864
+ get config() {
1865
+ return this.#config;
1866
+ }
1867
+ set config(config) {
1868
+ assert(!this.#finalized, "Cannot change the configuration of a finalized reporter");
1869
+ this.#config = config;
1870
+ }
1871
+ issue(issue, reportOptions) {
1872
+ for (const reporter of this.#reporters) handleIssue(reporter, issue, reportOptions);
1873
+ }
1874
+ info(...params) {
1875
+ for (const reporter of this.#reporters) reporter.info(...params);
1876
+ }
1877
+ debug(...params) {
1878
+ for (const reporter of this.#reporters) reporter.debug(...params);
1879
+ }
1880
+ error(...params) {
1881
+ for (const reporter of this.#reporters) reporter.error(...params);
1882
+ }
1883
+ progress(...params) {
1884
+ for (const reporter of this.#reporters) reporter.progress(...params);
1885
+ }
1886
+ async result(result) {
1887
+ await Promise.all(this.#reporters.map((reporter) => reporter.result?.(result)));
1888
+ }
1889
+ get features() {
1890
+ return {
1891
+ unknownWords: true,
1892
+ issueType: true
1893
+ };
1894
+ }
1895
+ async loadReportersAndFinalize(reporters) {
1896
+ assert(!this.#finalized, "Cannot change the configuration of a finalized reporter");
1897
+ const loaded = await loadReporters(reporters, this.defaultReporter, this.config);
1898
+ this.#reporters = [...new Set(loaded)].map((reporter) => finalizeReporter(reporter));
1899
+ }
1900
+ emitProgressBegin(filename, fileNum, fileCount) {
1901
+ this.progress({
1902
+ type: "ProgressFileBegin",
1903
+ fileNum,
1904
+ fileCount,
1905
+ filename
1906
+ });
1907
+ }
1908
+ emitProgressComplete(filename, fileNum, fileCount, result) {
1909
+ const filteredIssues = result.issues.filter((issue) => filterFeatureIssues({}, issue, result.reportIssueOptions));
1910
+ const numIssues = filteredIssues.length;
1911
+ for (const reporter of this.#reporters) {
1912
+ const progress = clean({
1913
+ type: "ProgressFileComplete",
1914
+ fileNum,
1915
+ fileCount,
1916
+ filename,
1917
+ elapsedTimeMs: result.elapsedTimeMs,
1918
+ processed: result.processed,
1919
+ numErrors: numIssues || result.errors,
1920
+ cached: result.cached,
1921
+ perf: result.perf,
1922
+ issues: reporter.features && result.issues,
1923
+ reportIssueOptions: reporter.features && result.reportIssueOptions
1924
+ });
1925
+ reporter.progress(progress);
1926
+ }
1927
+ result.issues.forEach((issue) => this.issue(issue, result.reportIssueOptions));
1928
+ return numIssues;
1929
+ }
1930
+ };
1931
+
1932
+ //#endregion
1933
+ //#region src/util/timer.ts
1934
+ function getTimeMeasurer() {
1935
+ const timer = createPerfTimer("timer");
1936
+ return () => timer.elapsed;
1937
+ }
1938
+
1939
+ //#endregion
1940
+ //#region src/util/writeFile.ts
1941
+ async function writeFileOrStream(filename, data) {
1942
+ switch (filename) {
1943
+ case "stdout": {
1944
+ await writeStream(process.stdout, data);
1945
+ return;
1946
+ }
1947
+ case "stderr": {
1948
+ await writeStream(process.stderr, data);
1949
+ return;
1950
+ }
1951
+ case "null": return;
1952
+ }
1953
+ return fs.writeFile(filename, data);
1954
+ }
1955
+ function writeStream(stream, data) {
1956
+ return new Promise((resolve$1, reject) => {
1957
+ stream.write(data, (err) => {
1958
+ if (err) reject(err);
1959
+ else resolve$1();
1960
+ });
1961
+ });
1962
+ }
1963
+
1964
+ //#endregion
1965
+ //#region src/lint/lint.ts
1966
+ const version = npmPackage.version;
1967
+ const BATCH_SIZE = 8;
1968
+ const { opFilterAsync } = operators;
1969
+ async function runLint(cfg) {
1970
+ const reporter = new LintReporter(cfg.reporter, cfg.options);
1971
+ const configErrors = /* @__PURE__ */ new Set();
1972
+ const timer = getTimeMeasurer();
1973
+ const logDictRequests = truthy(getEnvironmentVariable("CSPELL_ENABLE_DICTIONARY_LOGGING"));
1974
+ if (logDictRequests) _debug.cacheDictionaryEnableLogging(true);
1975
+ const lintResult = await run();
1976
+ if (logDictRequests) await writeDictionaryLog();
1977
+ await reporter.result(lintResult);
1978
+ const elapsed = timer();
1979
+ if (getFeatureFlags().getFlag("timer")) console.log(`Elapsed Time: ${elapsed.toFixed(2)}ms`);
1980
+ return lintResult;
1981
+ function prefetch(filename, configInfo, cache) {
1982
+ if (isBinaryFile$1(filename, cfg.root)) return {
1983
+ filename,
1984
+ result: Promise.resolve({ skip: true })
1985
+ };
1986
+ const reportIssueOptions = extractReporterIssueOptions(configInfo.config);
1987
+ async function fetch$1() {
1988
+ const getElapsedTimeMs = getTimeMeasurer();
1989
+ const cachedResult = await cache.getCachedLintResults(filename);
1990
+ if (cachedResult) {
1991
+ reporter.debug(`Filename: ${filename}, using cache`);
1992
+ const fileResult = {
1993
+ ...cachedResult,
1994
+ elapsedTimeMs: getElapsedTimeMs()
1995
+ };
1996
+ return { fileResult };
1997
+ }
1998
+ const uri = filenameToUri(filename, cfg.root).href;
1999
+ const checkResult = await shouldCheckDocument({ uri }, {}, configInfo.config);
2000
+ if (!checkResult.shouldCheck) return { skip: true };
2001
+ const fileInfo = await readFileInfo(filename, void 0, true);
2002
+ return {
2003
+ fileInfo,
2004
+ reportIssueOptions
2005
+ };
2006
+ }
2007
+ const result = fetch$1();
2008
+ return {
2009
+ filename,
2010
+ result
2011
+ };
2012
+ }
2013
+ async function processFile(filename, configInfo, cache, prefetch$1) {
2014
+ if (prefetch$1?.fileResult) return prefetch$1.fileResult;
2015
+ const getElapsedTimeMs = getTimeMeasurer();
2016
+ const reportIssueOptions = prefetch$1?.reportIssueOptions;
2017
+ const cachedResult = await cache.getCachedLintResults(filename);
2018
+ if (cachedResult) {
2019
+ reporter.debug(`Filename: ${filename}, using cache`);
2020
+ return {
2021
+ ...cachedResult,
2022
+ elapsedTimeMs: getElapsedTimeMs(),
2023
+ reportIssueOptions: {
2024
+ ...cachedResult.reportIssueOptions,
2025
+ ...reportIssueOptions
2026
+ }
2027
+ };
2028
+ }
2029
+ const result = {
2030
+ fileInfo: { filename },
2031
+ issues: [],
2032
+ processed: false,
2033
+ errors: 0,
2034
+ configErrors: 0,
2035
+ elapsedTimeMs: 0,
2036
+ reportIssueOptions
2037
+ };
2038
+ const fileInfo = prefetch$1?.fileInfo || await readFileInfo(filename, void 0, true);
2039
+ if (fileInfo.errorCode) {
2040
+ if (fileInfo.errorCode !== "EISDIR" && cfg.options.mustFindFiles) {
2041
+ const err = new LinterError(`File not found: "${filename}"`);
2042
+ reporter.error("Linter:", err);
2043
+ result.errors += 1;
2044
+ }
2045
+ return result;
2046
+ }
2047
+ const doc = fileInfoToDocument(fileInfo, cfg.options.languageId, cfg.locale);
2048
+ const { text } = fileInfo;
2049
+ result.fileInfo = fileInfo;
2050
+ let spellResult = {};
2051
+ reporter.info(`Checking: ${filename}, File type: ${doc.languageId ?? "auto"}, Language: ${doc.locale ?? "default"}`, MessageTypes.Info);
2052
+ try {
2053
+ const { showSuggestions: generateSuggestions, validateDirectives, skipValidation } = cfg.options;
2054
+ const numSuggestions = configInfo.config.numSuggestions ?? 5;
2055
+ const validateOptions = clean({
2056
+ generateSuggestions,
2057
+ numSuggestions,
2058
+ validateDirectives,
2059
+ skipValidation
2060
+ });
2061
+ const r = await spellCheckDocument(doc, validateOptions, configInfo.config);
2062
+ spellResult = r;
2063
+ result.processed = r.checked;
2064
+ result.perf = r.perf ? { ...r.perf } : void 0;
2065
+ result.issues = Text.calculateTextDocumentOffsets(doc.uri, text, r.issues).map(mapIssue);
2066
+ } catch (e) {
2067
+ reporter.error(`Failed to process "${filename}"`, toError(e));
2068
+ result.errors += 1;
2069
+ }
2070
+ result.elapsedTimeMs = getElapsedTimeMs();
2071
+ const config = spellResult.settingsUsed ?? {};
2072
+ result.reportIssueOptions = mergeReportIssueOptions(spellResult.settingsUsed || configInfo.config, reportIssueOptions);
2073
+ result.configErrors += await reportConfigurationErrors(config);
2074
+ const elapsed$1 = result.elapsedTimeMs;
2075
+ const dictionaries = config.dictionaries || [];
2076
+ reporter.info(`Checked: ${filename}, File type: ${config.languageId}, Language: ${config.language} ... Issues: ${result.issues.length} ${elapsed$1.toFixed(2)}ms`, MessageTypes.Info);
2077
+ reporter.info(`Config file Used: ${spellResult.localConfigFilepath || configInfo.source}`, MessageTypes.Info);
2078
+ reporter.info(`Dictionaries Used: ${dictionaries.join(", ")}`, MessageTypes.Info);
2079
+ if (cfg.options.debug) {
2080
+ const { id: _id, name: _name, __imports, __importRef,...cfg$1 } = config;
2081
+ const debugCfg = {
2082
+ filename,
2083
+ languageId: doc.languageId ?? cfg$1.languageId ?? "default",
2084
+ config: {
2085
+ ...cfg$1,
2086
+ source: null
2087
+ },
2088
+ source: spellResult.localConfigFilepath
2089
+ };
2090
+ reporter.debug(JSON.stringify(debugCfg, void 0, 2));
2091
+ }
2092
+ const dep = calcDependencies(config);
2093
+ await cache.setCachedLintResults(result, dep.files);
2094
+ return result;
2095
+ }
2096
+ function mapIssue({ doc: _,...tdo }) {
2097
+ const context = cfg.showContext ? extractContext(tdo, cfg.showContext) : void 0;
2098
+ return clean({
2099
+ ...tdo,
2100
+ context
2101
+ });
2102
+ }
2103
+ async function processFiles(files, configInfo, cacheSettings) {
2104
+ const fileCount = Array.isArray(files) ? files.length : void 0;
2105
+ const status = runResult();
2106
+ const cache = await createCache(cacheSettings);
2107
+ const failFast = cfg.options.failFast ?? configInfo.config.failFast ?? false;
2108
+ function* prefetchFiles(files$1) {
2109
+ const iter = prefetchIterable(pipe(files$1, opMap$1((filename) => prefetch(filename, configInfo, cache))), BATCH_SIZE);
2110
+ for (const v of iter) yield v;
2111
+ }
2112
+ async function* prefetchFilesAsync(files$1) {
2113
+ for await (const filename of files$1) yield prefetch(filename, configInfo, cache);
2114
+ }
2115
+ const emptyResult = {
2116
+ fileInfo: { filename: "" },
2117
+ issues: [],
2118
+ processed: false,
2119
+ errors: 0,
2120
+ configErrors: 0,
2121
+ elapsedTimeMs: 1,
2122
+ reportIssueOptions: void 0
2123
+ };
2124
+ async function processPrefetchFileResult(pf, index) {
2125
+ const { filename, result: pFetchResult } = pf;
2126
+ const getElapsedTimeMs = getTimeMeasurer();
2127
+ const fetchResult = await pFetchResult;
2128
+ reporter.emitProgressBegin(filename, index, fileCount ?? index);
2129
+ if (fetchResult?.skip) return {
2130
+ filename,
2131
+ fileNum: index,
2132
+ result: {
2133
+ ...emptyResult,
2134
+ fileInfo: { filename },
2135
+ elapsedTimeMs: getElapsedTimeMs()
2136
+ }
2137
+ };
2138
+ const result = await processFile(filename, configInfo, cache, fetchResult);
2139
+ return {
2140
+ filename,
2141
+ fileNum: index,
2142
+ result
2143
+ };
2144
+ }
2145
+ async function* loadAndProcessFiles() {
2146
+ let i = 0;
2147
+ if (isAsyncIterable(files)) for await (const pf of prefetchFilesAsync(files)) yield processPrefetchFileResult(pf, ++i);
2148
+ else for (const pf of prefetchFiles(files)) {
2149
+ await pf.result;
2150
+ yield processPrefetchFileResult(pf, ++i);
2151
+ }
2152
+ }
2153
+ for await (const fileP of loadAndProcessFiles()) {
2154
+ const { filename, fileNum, result } = fileP;
2155
+ status.files += 1;
2156
+ status.cachedFiles = (status.cachedFiles || 0) + (result.cached ? 1 : 0);
2157
+ const numIssues = reporter.emitProgressComplete(filename, fileNum, fileCount ?? fileNum, result);
2158
+ if (numIssues || result.errors) {
2159
+ status.filesWithIssues.add(relativeToCwd(filename, cfg.root));
2160
+ status.issues += numIssues;
2161
+ status.errors += result.errors;
2162
+ if (failFast) return status;
2163
+ }
2164
+ status.errors += result.configErrors;
2165
+ }
2166
+ await cache.reconcile();
2167
+ return status;
2168
+ }
2169
+ function calcDependencies(config) {
2170
+ const { configFiles, dictionaryFiles } = extractDependencies(config);
2171
+ return { files: [...configFiles, ...dictionaryFiles] };
2172
+ }
2173
+ async function reportConfigurationErrors(config) {
2174
+ const errors = extractImportErrors(config);
2175
+ let count = 0;
2176
+ errors.forEach((ref) => {
2177
+ const key = ref.error.toString();
2178
+ if (configErrors.has(key)) return;
2179
+ configErrors.add(key);
2180
+ count += 1;
2181
+ reporter.error("Configuration", ref.error);
2182
+ });
2183
+ const dictCollection = await getDictionary(config);
2184
+ dictCollection.dictionaries.forEach((dict) => {
2185
+ const dictErrors = dict.getErrors?.() || [];
2186
+ const msg = `Dictionary Error with (${dict.name})`;
2187
+ dictErrors.forEach((error) => {
2188
+ const key = msg + error.toString();
2189
+ if (configErrors.has(key)) return;
2190
+ configErrors.add(key);
2191
+ count += 1;
2192
+ reporter.error(msg, error);
2193
+ });
2194
+ });
2195
+ return count;
2196
+ }
2197
+ function countConfigErrors(configInfo) {
2198
+ return reportConfigurationErrors(configInfo.config);
2199
+ }
2200
+ async function run() {
2201
+ if (cfg.options.root) setEnvironmentVariable(ENV_CSPELL_GLOB_ROOT, cfg.root);
2202
+ const configInfo = await readConfig(cfg.configFile, cfg.root, cfg.options.stopConfigSearchAt);
2203
+ if (cfg.options.defaultConfiguration !== void 0) configInfo.config.loadDefaultConfiguration = cfg.options.defaultConfiguration;
2204
+ configInfo.config = mergeSettings(configInfo.config, cfg.cspellSettingsFromCliOptions);
2205
+ const reporterConfig = clean({
2206
+ maxNumberOfProblems: configInfo.config.maxNumberOfProblems,
2207
+ maxDuplicateProblems: configInfo.config.maxDuplicateProblems,
2208
+ minWordLength: configInfo.config.minWordLength,
2209
+ ...cfg.options,
2210
+ console
2211
+ });
2212
+ const reporters = cfg.options.reporter ?? configInfo.config.reporters;
2213
+ reporter.config = reporterConfig;
2214
+ await reporter.loadReportersAndFinalize(reporters);
2215
+ setLogger(getLoggerFromReporter(reporter));
2216
+ const globInfo = await determineGlobs(configInfo, cfg);
2217
+ const { fileGlobs, excludeGlobs } = globInfo;
2218
+ const hasFileLists = !!cfg.fileLists.length;
2219
+ if (!fileGlobs.length && !hasFileLists && !cfg.files?.length) return runResult();
2220
+ header(fileGlobs, excludeGlobs);
2221
+ checkGlobs(fileGlobs, reporter);
2222
+ reporter.info(`Config Files Found:\n ${configInfo.source}\n`, MessageTypes.Info);
2223
+ const configErrors$1 = await countConfigErrors(configInfo);
2224
+ if (configErrors$1 && cfg.options.exitCode !== false && !cfg.options.continueOnError) return runResult({ errors: configErrors$1 });
2225
+ const { root } = cfg;
2226
+ try {
2227
+ const cacheSettings = await calcCacheSettings(configInfo.config, {
2228
+ ...cfg.options,
2229
+ version
2230
+ }, root);
2231
+ const files = await determineFilesToCheck(configInfo, cfg, reporter, globInfo);
2232
+ const result = await processFiles(files, configInfo, cacheSettings);
2233
+ if (configErrors$1 && cfg.options.exitCode !== false) result.errors ||= configErrors$1;
2234
+ return result;
2235
+ } catch (e) {
2236
+ const err = toApplicationError(e);
2237
+ reporter.error("Linter", err);
2238
+ return runResult({ errors: 1 });
2239
+ }
2240
+ }
2241
+ function header(files, cliExcludes) {
2242
+ const formattedFiles = files.length > 100 ? [...files.slice(0, 100), "..."] : files;
2243
+ reporter.info(`
2244
+ cspell;
2245
+ Date: ${(/* @__PURE__ */ new Date()).toUTCString()}
2246
+ Options:
2247
+ verbose: ${yesNo(!!cfg.options.verbose)}
2248
+ config: ${cfg.configFile || "default"}
2249
+ exclude: ${cliExcludes.join("\n ")}
2250
+ files: ${formattedFiles}
2251
+ wordsOnly: ${yesNo(!!cfg.options.wordsOnly)}
2252
+ unique: ${yesNo(!!cfg.options.unique)}
2253
+ `, MessageTypes.Info);
2254
+ }
2255
+ }
2256
+ function checkGlobs(globs, reporter) {
2257
+ globs.filter((g) => g.startsWith("'") || g.endsWith("'")).map((glob$2) => chalk.yellow(glob$2)).forEach((glob$2) => reporter.error("Linter", new CheckFailed(`Glob starting or ending with ' (single quote) is not likely to match any files: ${glob$2}.`)));
2258
+ }
2259
+ async function determineGlobs(configInfo, cfg) {
2260
+ const useGitignore = cfg.options.gitignore ?? configInfo.config.useGitignore ?? false;
2261
+ const gitignoreRoots = cfg.options.gitignoreRoot ?? configInfo.config.gitignoreRoot;
2262
+ const gitIgnore = useGitignore ? await generateGitIgnore(gitignoreRoots) : void 0;
2263
+ const cliGlobs = cfg.fileGlobs;
2264
+ const allGlobs = cliGlobs.length && cliGlobs || cfg.options.filterFiles !== false && configInfo.config.files || [];
2265
+ const combinedGlobs = await normalizeFileOrGlobsToRoot(allGlobs, cfg.root);
2266
+ const cliExcludeGlobs = extractPatterns(cfg.excludes).map((p) => p.glob);
2267
+ const normalizedExcludes = normalizeGlobsToRoot(cliExcludeGlobs, cfg.root, true);
2268
+ const includeGlobs = combinedGlobs.filter((g) => !g.startsWith("!"));
2269
+ const excludeGlobs = [...combinedGlobs.filter((g) => g.startsWith("!")).map((g) => g.slice(1)), ...normalizedExcludes];
2270
+ const fileGlobs = includeGlobs;
2271
+ const appGlobs = {
2272
+ allGlobs,
2273
+ gitIgnore,
2274
+ fileGlobs,
2275
+ excludeGlobs,
2276
+ normalizedExcludes
2277
+ };
2278
+ return appGlobs;
2279
+ }
2280
+ async function determineFilesToCheck(configInfo, cfg, reporter, globInfo) {
2281
+ async function _determineFilesToCheck() {
2282
+ const { fileLists } = cfg;
2283
+ const hasFileLists = !!fileLists.length;
2284
+ const { allGlobs, gitIgnore, fileGlobs, excludeGlobs, normalizedExcludes } = globInfo;
2285
+ const { root } = cfg;
2286
+ const globsToExcludeRaw = [...configInfo.config.ignorePaths || [], ...excludeGlobs];
2287
+ const globsToExclude = globsToExcludeRaw.filter((g) => !globPattern(g).startsWith("!"));
2288
+ if (globsToExclude.length !== globsToExcludeRaw.length) {
2289
+ const globs = globsToExcludeRaw.map((g) => globPattern(g)).filter((g) => g.startsWith("!"));
2290
+ const msg = `Negative glob exclusions are not supported: ${globs.join(", ")}`;
2291
+ reporter.info(msg, MessageTypes.Warning);
2292
+ }
2293
+ const globMatcher = buildGlobMatcher(globsToExclude, root, true);
2294
+ const ignoreGlobs = extractGlobsFromMatcher(globMatcher);
2295
+ const globOptions = {
2296
+ root,
2297
+ cwd: root,
2298
+ ignore: [...ignoreGlobs, ...normalizedExcludes],
2299
+ nodir: true
2300
+ };
2301
+ const enableGlobDot = cfg.enableGlobDot ?? configInfo.config.enableGlobDot;
2302
+ if (enableGlobDot !== void 0) globOptions.dot = enableGlobDot;
2303
+ const opFilterExcludedFiles = opFilter(filterOutExcludedFilesFn(globMatcher));
2304
+ const includeFilter = createIncludeFileFilterFn(allGlobs, root, enableGlobDot);
2305
+ const rawCliFiles = cfg.files?.map((file) => resolveFilename(file, root)).filter(includeFilter);
2306
+ const cliFiles = cfg.options.mustFindFiles ? rawCliFiles : rawCliFiles && pipeAsync(rawCliFiles, opFilterAsync(isFile));
2307
+ const foundFiles = hasFileLists ? concatAsyncIterables(cliFiles, await useFileLists(fileLists, includeFilter)) : cliFiles || await findFiles(fileGlobs, globOptions);
2308
+ const filtered = gitIgnore ? await gitIgnore.filterOutIgnored(foundFiles) : foundFiles;
2309
+ const files = isAsyncIterable(filtered) ? pipeAsync(filtered, opFilterExcludedFiles) : [...pipe(filtered, opFilterExcludedFiles)];
2310
+ return files;
2311
+ }
2312
+ function isExcluded(filename, globMatcherExclude) {
2313
+ if (isBinaryFile(toFileURL(filename))) return true;
2314
+ const { root } = cfg;
2315
+ const absFilename = path$1.resolve(root, filename);
2316
+ const r = globMatcherExclude.matchEx(absFilename);
2317
+ if (r.matched) {
2318
+ const { glob: glob$2, source } = extractGlobSource(r.pattern);
2319
+ reporter.info(`Excluded File: ${path$1.relative(root, absFilename)}; Excluded by ${glob$2} from ${source}`, MessageTypes.Info);
2320
+ }
2321
+ return r.matched;
2322
+ }
2323
+ function filterOutExcludedFilesFn(globMatcherExclude) {
2324
+ const patterns = globMatcherExclude.patterns;
2325
+ const excludeInfo = patterns.map(extractGlobSource).map(({ glob: glob$2, source }) => `Glob: ${glob$2} from ${source}`).filter(uniqueFn());
2326
+ reporter.info(`Exclusion Globs: \n ${excludeInfo.join("\n ")}\n`, MessageTypes.Info);
2327
+ return (filename) => !isExcluded(filename, globMatcherExclude);
2328
+ }
2329
+ return _determineFilesToCheck();
2330
+ }
2331
+ function extractGlobSource(g) {
2332
+ const { glob: glob$2, rawGlob, source } = g;
2333
+ return {
2334
+ glob: rawGlob || glob$2,
2335
+ source
2336
+ };
2337
+ }
2338
+ function runResult(init = {}) {
2339
+ const { files = 0, filesWithIssues = /* @__PURE__ */ new Set(), issues = 0, errors = 0, cachedFiles = 0 } = init;
2340
+ return {
2341
+ files,
2342
+ filesWithIssues,
2343
+ issues,
2344
+ errors,
2345
+ cachedFiles
2346
+ };
2347
+ }
2348
+ function yesNo(value) {
2349
+ return value ? "Yes" : "No";
2350
+ }
2351
+ function getLoggerFromReporter(reporter) {
2352
+ const log = (...params) => {
2353
+ const msg = format(...params);
2354
+ reporter.info(msg, "Info");
2355
+ };
2356
+ const error = (...params) => {
2357
+ const msg = format(...params);
2358
+ const err = {
2359
+ message: "",
2360
+ name: "error",
2361
+ toString: () => ""
2362
+ };
2363
+ reporter.error(msg, err);
2364
+ };
2365
+ const warn = (...params) => {
2366
+ const msg = format(...params);
2367
+ reporter.info(msg, "Warning");
2368
+ };
2369
+ return {
2370
+ log,
2371
+ warn,
2372
+ error
2373
+ };
2374
+ }
2375
+ async function generateGitIgnore(roots) {
2376
+ const root = (typeof roots === "string" ? [roots].filter((r) => !!r) : roots) || [];
2377
+ if (!root?.length) {
2378
+ const cwd = process.cwd();
2379
+ const repo = await findRepoRoot(cwd) || cwd;
2380
+ root.push(repo);
2381
+ }
2382
+ return new GitIgnore(root?.map((p) => path$1.resolve(p)));
2383
+ }
2384
+ async function useFileLists(fileListFiles, filterFiles) {
2385
+ const files = readFileListFiles(fileListFiles);
2386
+ return pipeAsync(files, opFilter(filterFiles), opFilterAsync(isNotDir));
2387
+ }
2388
+ function createIncludeFileFilterFn(includeGlobPatterns, root, dot) {
2389
+ if (!includeGlobPatterns?.length) return () => true;
2390
+ const patterns = includeGlobPatterns.map((g) => g === "." ? "/**" : g);
2391
+ const options = {
2392
+ root,
2393
+ mode: "include"
2394
+ };
2395
+ if (dot !== void 0) options.dot = dot;
2396
+ const globMatcher = new GlobMatcher(patterns, options);
2397
+ return (file) => globMatcher.match(file);
2398
+ }
2399
+ async function* concatAsyncIterables(...iterables) {
2400
+ for (const iter of iterables) {
2401
+ if (!iter) continue;
2402
+ yield* iter;
2403
+ }
2404
+ }
2405
+ async function writeDictionaryLog() {
2406
+ const fieldsCsv = getEnvironmentVariable("CSPELL_ENABLE_DICTIONARY_LOG_FIELDS") || "time, word, value";
2407
+ const fields = fieldsCsv.split(",").map((f) => f.trim());
2408
+ const header = fields.join(", ") + "\n";
2409
+ const lines = _debug.cacheDictionaryGetLog().filter((d) => d.method === "has").map((d) => fields.map((f) => f in d ? `${d[f]}` : "").join(", "));
2410
+ const data = header + lines.join("\n") + "\n";
2411
+ const filename = getEnvironmentVariable("CSPELL_ENABLE_DICTIONARY_LOG_FILE") || "cspell-dictionary-log.csv";
2412
+ await writeFileOrStream(filename, data);
2413
+ }
2414
+ function globPattern(g) {
2415
+ return typeof g === "string" ? g : g.glob;
2416
+ }
2417
+ var LinterError = class extends Error {
2418
+ constructor(message) {
2419
+ super(message);
2420
+ }
2421
+ toString() {
2422
+ return this.message;
2423
+ }
2424
+ };
2425
+
2426
+ //#endregion
2427
+ //#region src/lint/LintRequest.ts
2428
+ const defaultContextRange = 20;
2429
+ var LintRequest = class {
2430
+ locale;
2431
+ configFile;
2432
+ excludes;
2433
+ root;
2434
+ showContext;
2435
+ enableGlobDot;
2436
+ fileLists;
2437
+ files;
2438
+ cspellSettingsFromCliOptions;
2439
+ constructor(fileGlobs, options, reporter) {
2440
+ this.fileGlobs = fileGlobs;
2441
+ this.options = options;
2442
+ this.reporter = reporter;
2443
+ this.root = path$1.resolve(options.root || process.cwd());
2444
+ this.configFile = options.config;
2445
+ this.excludes = calcExcludeGlobInfo(this.root, options.exclude);
2446
+ this.locale = options.locale ?? options.local ?? "";
2447
+ this.enableGlobDot = options.dot;
2448
+ this.showContext = Math.max(options.showContext === true ? defaultContextRange : options.showContext ? options.showContext : 0, 0);
2449
+ this.fileLists = (options.fileList ?? options.fileLists) || [];
2450
+ this.files = mergeFiles(options.file, options.files);
2451
+ const noConfigSearch = options.configSearch === false ? true : options.configSearch === true ? false : void 0;
2452
+ const dictionaries = [...(options.disableDictionary ?? []).map((d) => `!${d}`), ...(options.dictionary ?? []).map((d) => `!!${d}`)];
2453
+ const languageSettings = [{
2454
+ languageId: "*",
2455
+ locale: "*",
2456
+ dictionaries
2457
+ }];
2458
+ this.cspellSettingsFromCliOptions = {
2459
+ ...noConfigSearch !== void 0 ? { noConfigSearch } : {},
2460
+ ...extractUnknownWordsConfig(options),
2461
+ languageSettings
2462
+ };
2463
+ }
2464
+ };
2465
+ function mergeFiles(a, b) {
2466
+ const files = merge(a, b);
2467
+ if (!files) return void 0;
2468
+ return [...new Set(files.flatMap((a$1) => a$1.split("\n").map((a$2) => a$2.trim())).filter((a$1) => !!a$1))];
2469
+ }
2470
+ function merge(a, b) {
2471
+ if (!a) return b;
2472
+ if (!b) return a;
2473
+ return [...a, ...b];
2474
+ }
2475
+ function extractUnknownWordsConfig(options) {
2476
+ const config = {};
2477
+ if (!options.report) return config;
2478
+ switch (options.report) {
2479
+ case "all": {
2480
+ config.unknownWords = unknownWordsChoices.ReportAll;
2481
+ break;
2482
+ }
2483
+ case "simple": {
2484
+ config.unknownWords = unknownWordsChoices.ReportSimple;
2485
+ break;
2486
+ }
2487
+ case "typos": {
2488
+ config.unknownWords = unknownWordsChoices.ReportCommonTypos;
2489
+ break;
2490
+ }
2491
+ case "flagged": {
2492
+ config.unknownWords = unknownWordsChoices.ReportFlagged;
2493
+ break;
2494
+ }
2495
+ }
2496
+ return config;
2497
+ }
2498
+
2499
+ //#endregion
2500
+ //#region src/options.ts
2501
+ const ReportChoicesAll = [
2502
+ "all",
2503
+ "simple",
2504
+ "typos",
2505
+ "flagged"
2506
+ ];
2507
+ function fixLegacy(opts) {
2508
+ const { local,...rest } = opts;
2509
+ if (local && !rest.locale) rest.locale = local;
2510
+ return rest;
2511
+ }
2512
+
2513
+ //#endregion
2514
+ //#region src/repl/index.ts
2515
+ function simpleRepl() {
2516
+ return new SimpleRepl();
2517
+ }
2518
+ var SimpleRepl = class {
2519
+ beforeEach;
2520
+ completer;
2521
+ _history;
2522
+ rl;
2523
+ constructor(prompt = "> ") {
2524
+ this.prompt = prompt;
2525
+ this._history = [];
2526
+ this.rl = readline.createInterface({
2527
+ input: process.stdin,
2528
+ output: process.stdout,
2529
+ prompt,
2530
+ history: this._history,
2531
+ historySize: 100,
2532
+ completer: (line) => this._completer(line)
2533
+ });
2534
+ this.rl.on("history", (h) => (this._history = h, void 0));
2535
+ }
2536
+ question(query) {
2537
+ return new Promise((resolve$1) => {
2538
+ this.rl.question(query, resolve$1);
2539
+ });
2540
+ }
2541
+ _completer(line) {
2542
+ if (this.completer) return this.completer(line);
2543
+ const hist = this._history.filter((h) => h.startsWith(line));
2544
+ return [hist, line];
2545
+ }
2546
+ get history() {
2547
+ return this._history;
2548
+ }
2549
+ [Symbol.asyncIterator]() {
2550
+ const next = () => {
2551
+ if (this.beforeEach) this.beforeEach();
2552
+ return this.question(this.prompt).then((value) => ({ value })).catch(() => ({
2553
+ done: true,
2554
+ value: void 0
2555
+ }));
2556
+ };
2557
+ return { next };
2558
+ }
2559
+ };
2560
+
2561
+ //#endregion
2562
+ //#region src/dictionaries/listDictionaries.ts
2563
+ const inlineDictionaries = {
2564
+ "[words]": {
2565
+ name: "[words]",
2566
+ description: "List of words to be included in the spell check.",
2567
+ enabled: true
2568
+ },
2569
+ "[flagWords]": {
2570
+ name: "[flagWords]",
2571
+ description: "List of words to be flagged as incorrect.",
2572
+ enabled: true
2573
+ },
2574
+ "[ignoreWords]": {
2575
+ name: "[ignoreWords]",
2576
+ description: "List of words to be ignored in the spell check.",
2577
+ enabled: true
2578
+ },
2579
+ "[suggestWords]": {
2580
+ name: "[suggestWords]",
2581
+ description: "List of spelling suggestions for words.",
2582
+ enabled: true
2583
+ }
2584
+ };
2585
+ function splitList(list) {
2586
+ if (!list) return [];
2587
+ if (typeof list === "string") return list.split(",").map((s) => s.trim()).filter((s) => !!s);
2588
+ return list.flatMap((s) => splitList(s));
2589
+ }
2590
+ function extractDictionaryLocalesAndFileTypes(config) {
2591
+ const map = /* @__PURE__ */ new Map();
2592
+ function getDict(name$1) {
2593
+ const found = map.get(name$1);
2594
+ if (found) return found;
2595
+ const dict = {
2596
+ locales: /* @__PURE__ */ new Set(),
2597
+ fileTypes: /* @__PURE__ */ new Set()
2598
+ };
2599
+ map.set(name$1, dict);
2600
+ return dict;
2601
+ }
2602
+ const languageSettings = config.languageSettings || [];
2603
+ for (const lang of languageSettings) {
2604
+ const locales = splitList(lang.locale);
2605
+ const fileTypes = splitList(lang.languageId);
2606
+ const dicts = lang.dictionaries || [];
2607
+ for (const dictName of dicts) {
2608
+ const dict = getDict(dictName);
2609
+ for (const locale of locales) if (locale) dict.locales.add(locale);
2610
+ for (const fileType of fileTypes) if (fileType) dict.fileTypes.add(fileType);
2611
+ }
2612
+ }
2613
+ return map;
2614
+ }
2615
+ function extractInlineDictionaries(dict) {
2616
+ const iDict = dict;
2617
+ const inline = [];
2618
+ if (iDict.words?.length) inline.push("[words]");
2619
+ if (iDict.flagWords?.length) inline.push("[flagWords]");
2620
+ if (iDict.ignoreWords?.length) inline.push("[ignoreWords]");
2621
+ if (iDict.suggestWords?.length) inline.push("[suggestWords]");
2622
+ return inline.length ? inline : void 0;
2623
+ }
2624
+ function extractSpecialDictionaries(config) {
2625
+ const specialDictionaries = [];
2626
+ if (config.words?.length) specialDictionaries.push(inlineDictionaries["[words]"]);
2627
+ if (config.flagWords?.length) specialDictionaries.push(inlineDictionaries["[flagWords]"]);
2628
+ if (config.ignoreWords?.length) specialDictionaries.push(inlineDictionaries["[ignoreWords]"]);
2629
+ if (config.suggestWords?.length) specialDictionaries.push(inlineDictionaries["[suggestWords]"]);
2630
+ return specialDictionaries;
2631
+ }
2632
+ async function listDictionaries(options) {
2633
+ const configFile = await readConfig(options.config, void 0);
2634
+ const loadDefault = options.defaultConfiguration ?? configFile.config.loadDefaultConfiguration ?? true;
2635
+ const configBase = mergeSettings(await getDefaultSettings(loadDefault), await getGlobalSettingsAsync(), configFile.config);
2636
+ const useFileType = options.fileType === "text" ? "plaintext" : options.fileType;
2637
+ if (options.locale) configBase.language = options.locale;
2638
+ const config = combineTextAndLanguageSettings(configBase, "", useFileType || configBase.languageId || "plaintext");
2639
+ const dictionaryLocalesAndFileTypes = extractDictionaryLocalesAndFileTypes(config);
2640
+ const enabledDictionaries = new Set(config.dictionaries || []);
2641
+ function toListDictionariesResult(dict) {
2642
+ const inline = extractInlineDictionaries(dict);
2643
+ return {
2644
+ name: dict.name,
2645
+ description: dict.description,
2646
+ enabled: enabledDictionaries.has(dict.name),
2647
+ path: dict.path,
2648
+ inline,
2649
+ locales: [...dictionaryLocalesAndFileTypes.get(dict.name)?.locales || []].sort(),
2650
+ fileTypes: [...dictionaryLocalesAndFileTypes.get(dict.name)?.fileTypes || []].sort()
2651
+ };
2652
+ }
2653
+ function filterDicts(dict) {
2654
+ if (options.enabled === void 0) return true;
2655
+ return options.enabled === enabledDictionaries.has(dict.name);
2656
+ }
2657
+ const dictionaryDefinitions = (config.dictionaryDefinitions || []).filter(filterDicts);
2658
+ dictionaryDefinitions.sort((a, b) => a.name.localeCompare(b.name));
2659
+ const specialDicts = options.enabled !== false ? extractSpecialDictionaries(config) : [];
2660
+ return [...specialDicts, ...dictionaryDefinitions.map(toListDictionariesResult)];
2661
+ }
2662
+
2663
+ //#endregion
2664
+ //#region src/application.mts
2665
+ function lint(fileGlobs, options, reporter) {
2666
+ options = fixLegacy(options);
2667
+ const unknownWordsConfig = extractUnknownWordsConfig(options);
2668
+ const useOptions = {
2669
+ ...options,
2670
+ ...unknownWordsConfig
2671
+ };
2672
+ const reporterOptions = {
2673
+ ...useOptions,
2674
+ console
2675
+ };
2676
+ const cfg = new LintRequest(fileGlobs, useOptions, finalizeReporter(reporter) ?? getReporter({
2677
+ ...useOptions,
2678
+ fileGlobs
2679
+ }, reporterOptions));
2680
+ return runLint(cfg);
2681
+ }
2682
+ async function* trace(words, options) {
2683
+ options = fixLegacy(options);
2684
+ const iWords = options.stdin ? toAsyncIterable(words, readStdin()) : words;
2685
+ const { languageId, locale, allowCompoundWords, ignoreCase } = options;
2686
+ const configFile = await readConfig(options.config, void 0);
2687
+ const loadDefault = options.defaultConfiguration ?? configFile.config.loadDefaultConfiguration ?? true;
2688
+ const additionalSettings = {};
2689
+ if (options.dictionary) additionalSettings.dictionaries = options.dictionary;
2690
+ const config = mergeSettings(await getDefaultSettings(loadDefault), await getGlobalSettingsAsync(), configFile.config, additionalSettings);
2691
+ yield* traceWordsAsync(iWords, config, clean({
2692
+ languageId,
2693
+ locale,
2694
+ ignoreCase,
2695
+ allowCompoundWords
2696
+ }));
2697
+ }
2698
+ async function checkText(filename, options) {
2699
+ options = fixLegacy(options);
2700
+ const fileInfo = await readFileInfo(filename);
2701
+ const { locale, languageId, validateDirectives } = options;
2702
+ const doc = fileInfoToDocument(fileInfo, languageId, locale);
2703
+ const checkOptions = {
2704
+ configFile: options.config,
2705
+ validateDirectives
2706
+ };
2707
+ const settingsFromCommandLine = clean({
2708
+ languageId,
2709
+ language: locale,
2710
+ loadDefaultConfiguration: options.defaultConfiguration
2711
+ });
2712
+ return checkTextDocument(doc, clean({ ...checkOptions }), settingsFromCommandLine);
2713
+ }
2714
+ async function* suggestions(words, options) {
2715
+ options = fixLegacy(options);
2716
+ const configFile = await readConfig(options.config, void 0);
2717
+ let timer;
2718
+ function tapStart() {
2719
+ timer = getTimeMeasurer();
2720
+ }
2721
+ function mapStart(v) {
2722
+ tapStart();
2723
+ return v;
2724
+ }
2725
+ function mapEnd(v) {
2726
+ const elapsedTimeMs = timer?.();
2727
+ return elapsedTimeMs ? {
2728
+ ...v,
2729
+ elapsedTimeMs
2730
+ } : v;
2731
+ }
2732
+ const iWords = options.repl ? pipeAsync(toAsyncIterable(words, simpleRepl()), opTap(tapStart)) : options.useStdin ? pipeAsync(toAsyncIterable(words, readStdin()), opTap(tapStart)) : words.map(mapStart);
2733
+ try {
2734
+ const results = pipeAsync(suggestionsForWords(iWords, clean({ ...options }), configFile.config), opMap(mapEnd));
2735
+ yield* results;
2736
+ } catch (e) {
2737
+ if (!(e instanceof SuggestionError)) throw e;
2738
+ console.error(e.message);
2739
+ process.exitCode = 1;
2740
+ }
2741
+ }
2742
+ function createInit(options) {
2743
+ return configInit(options);
2744
+ }
2745
+ function registerApplicationFeatureFlags() {
2746
+ const ff = getFeatureFlags();
2747
+ const flags = [{
2748
+ name: "timer",
2749
+ description: "Display elapsed time for command."
2750
+ }];
2751
+ flags.forEach((flag) => ff.register(flag));
2752
+ return ff;
2753
+ }
2754
+ function parseApplicationFeatureFlags(flags) {
2755
+ const ff = registerApplicationFeatureFlags();
2756
+ return parseFeatureFlags(flags, ff);
2757
+ }
2758
+
2759
+ //#endregion
2760
+ export { ApplicationError, CheckFailed, DEFAULT_CACHE_LOCATION, IncludeExcludeFlag, ReportChoicesAll, checkText, console, createInit, getReporter, lint, listDictionaries, npmPackage, parseApplicationFeatureFlags, suggestions, trace };
2761
+ //# sourceMappingURL=application-_MFvh02K.js.map