cspell 9.1.2 → 9.1.5

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