cspell 9.4.0 → 9.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -6
- package/dist/cjs/commonJsApi.cjs +8 -0
- package/dist/cjs/commonJsApi.d.cts +2 -0
- package/dist/esm/app.js +9 -120
- package/dist/esm/{application-DCyfKhGm.js → application-DaQrXF9X.js} +1052 -624
- package/dist/esm/application.js +1 -1
- package/dist/esm/index.js +1 -1
- package/package.json +22 -18
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { isAsyncIterable, opFilter, opMap, opTap, operators, pipeAsync, pipeAsync as asyncPipe, toAsyncIterable, toAsyncIterable as mergeAsyncIterables } from "@cspell/cspell-pipe";
|
|
3
3
|
import * as cspell from "cspell-lib";
|
|
4
|
-
import { ENV_CSPELL_GLOB_ROOT, IncludeExcludeFlag, SuggestionError, Text, checkTextDocument, combineTextAndLanguageSettings, createPerfTimer, extractDependencies, extractImportErrors, fileToDocument, getDefaultSettings,
|
|
4
|
+
import { ENV_CSPELL_GLOB_ROOT, IncludeExcludeFlag, MessageTypes, SuggestionError, Text, checkTextDocument, combineTextAndLanguageSettings, createPerfTimer, extractDependencies, extractImportErrors, fileToDocument, getDefaultSettings, getGlobalSettingsAsync, getSystemFeatureFlags, isBinaryFile, isSpellingDictionaryLoadError, mergeSettings, setLogger, shouldCheckDocument, spellCheckDocument, suggestionsForWords, traceWordsAsync } from "cspell-lib";
|
|
5
5
|
import assert from "node:assert";
|
|
6
6
|
import { format, formatWithOptions, stripVTControlCharacters } from "node:util";
|
|
7
7
|
import { isUrlLike, toFileDirURL, toFilePathOrHref, toFileURL, urlRelative } from "@cspell/url";
|
|
8
8
|
import chalk, { Chalk } from "chalk";
|
|
9
9
|
import { makeTemplate } from "chalk-template";
|
|
10
|
+
import ansiRegex from "ansi-regex";
|
|
10
11
|
import fs, { stat } from "node:fs/promises";
|
|
11
12
|
import { MutableCSpellConfigFile, createReaderWriter, cspellConfigFileSchema, isCfgArrayNode } from "cspell-config-lib";
|
|
12
13
|
import { promises } from "node:fs";
|
|
13
14
|
import { fileURLToPath } from "node:url";
|
|
14
15
|
import * as path$1 from "node:path";
|
|
15
16
|
import path, { isAbsolute, posix, relative, resolve, sep } from "node:path";
|
|
17
|
+
import { enablePerformanceMeasurements, measurePerf } from "@cspell/cspell-performance-monitor";
|
|
16
18
|
import { opMap as opMap$1, pipe } from "@cspell/cspell-pipe/sync";
|
|
17
|
-
import { IssueType, MessageTypes, unknownWordsChoices } from "@cspell/cspell-types";
|
|
18
|
-
import {
|
|
19
|
+
import { IssueType, MessageTypes as MessageTypes$1, unknownWordsChoices } from "@cspell/cspell-types";
|
|
20
|
+
import { dictionaryCacheEnableLogging, dictionaryCacheGetLog } from "cspell-dictionary";
|
|
19
21
|
import { GitIgnore, findRepoRoot } from "cspell-gitignore";
|
|
20
22
|
import { GlobMatcher, fileOrGlobToGlob, workaroundPicomatchBug } from "cspell-glob";
|
|
21
23
|
import crypto from "node:crypto";
|
|
@@ -25,7 +27,6 @@ import { glob } from "tinyglobby";
|
|
|
25
27
|
import * as readline from "node:readline";
|
|
26
28
|
import { parse, stringify } from "flatted";
|
|
27
29
|
import { dynamicImport } from "@cspell/dynamic-import";
|
|
28
|
-
import ansiRegex from "ansi-regex";
|
|
29
30
|
|
|
30
31
|
//#region src/console.ts
|
|
31
32
|
var ImplChannel = class {
|
|
@@ -89,7 +90,7 @@ var IOError = class extends ApplicationError {
|
|
|
89
90
|
return this.cause.code === "ENOENT";
|
|
90
91
|
}
|
|
91
92
|
};
|
|
92
|
-
function toError(e) {
|
|
93
|
+
function toError$1(e) {
|
|
93
94
|
if (isError(e)) return e;
|
|
94
95
|
if (isErrorLike(e)) {
|
|
95
96
|
const ex = new Error(e.message, { cause: e });
|
|
@@ -109,10 +110,349 @@ function isErrorLike(e) {
|
|
|
109
110
|
}
|
|
110
111
|
function toApplicationError(e, message) {
|
|
111
112
|
if (e instanceof ApplicationError && !message) return e;
|
|
112
|
-
const err = toError(e);
|
|
113
|
+
const err = toError$1(e);
|
|
113
114
|
return new ApplicationError(message ?? err.message, void 0, err);
|
|
114
115
|
}
|
|
115
116
|
|
|
117
|
+
//#endregion
|
|
118
|
+
//#region src/util/perfMeasurements.ts
|
|
119
|
+
function getPerfMeasurements() {
|
|
120
|
+
const measurements = performance.getEntriesByType("measure");
|
|
121
|
+
const root = {
|
|
122
|
+
depth: -1,
|
|
123
|
+
totalTimeMs: 0,
|
|
124
|
+
nestedTimeMs: 0,
|
|
125
|
+
children: /* @__PURE__ */ new Map()
|
|
126
|
+
};
|
|
127
|
+
if (!measurements.length) return [];
|
|
128
|
+
const stack = [];
|
|
129
|
+
let depth = 0;
|
|
130
|
+
for (let i = 0; i < measurements.length; i++) {
|
|
131
|
+
const m = measurements[i];
|
|
132
|
+
rollUpStack(m.startTime);
|
|
133
|
+
const s = {
|
|
134
|
+
m,
|
|
135
|
+
p: addToParent(depth === 0 ? root : stack[depth - 1].p, m)
|
|
136
|
+
};
|
|
137
|
+
stack[depth++] = s;
|
|
138
|
+
}
|
|
139
|
+
sortChildren(root);
|
|
140
|
+
return [...root.children.values()].flatMap((r) => [...flattenChildren(r)]);
|
|
141
|
+
function contains(m, t) {
|
|
142
|
+
const stop = m.startTime + m.duration;
|
|
143
|
+
return t >= m.startTime && t < stop;
|
|
144
|
+
}
|
|
145
|
+
function rollUpStack(t) {
|
|
146
|
+
for (; depth > 0 && !contains(stack[depth - 1].m, t); --depth);
|
|
147
|
+
}
|
|
148
|
+
function addToParent(p, m) {
|
|
149
|
+
p.children ??= /* @__PURE__ */ new Map();
|
|
150
|
+
p.nestedTimeMs += m.duration;
|
|
151
|
+
return updateChild(p.children, m, p.depth + 1);
|
|
152
|
+
}
|
|
153
|
+
function updateChild(children, m, depth$1) {
|
|
154
|
+
const p = children.get(m.name);
|
|
155
|
+
if (p) {
|
|
156
|
+
p.totalTimeMs += m.duration;
|
|
157
|
+
p.count += 1;
|
|
158
|
+
p.minTimeMs = Math.min(p.minTimeMs, m.duration);
|
|
159
|
+
p.maxTimeMs = Math.max(p.maxTimeMs, m.duration);
|
|
160
|
+
return p;
|
|
161
|
+
}
|
|
162
|
+
const n = {
|
|
163
|
+
name: m.name,
|
|
164
|
+
depth: depth$1,
|
|
165
|
+
totalTimeMs: m.duration,
|
|
166
|
+
nestedTimeMs: 0,
|
|
167
|
+
count: 1,
|
|
168
|
+
minTimeMs: m.duration,
|
|
169
|
+
maxTimeMs: m.duration
|
|
170
|
+
};
|
|
171
|
+
children.set(m.name, n);
|
|
172
|
+
return n;
|
|
173
|
+
}
|
|
174
|
+
function* flattenChildren(m) {
|
|
175
|
+
yield m;
|
|
176
|
+
if (!m.children) return;
|
|
177
|
+
for (const child of m.children.values()) yield* flattenChildren(child);
|
|
178
|
+
}
|
|
179
|
+
function sortChildren(m) {
|
|
180
|
+
if (!m.children) return;
|
|
181
|
+
m.children = new Map([...m.children.entries()].sort((a, b) => b[1].totalTimeMs - a[1].totalTimeMs));
|
|
182
|
+
m.children.forEach(sortChildren);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
//#endregion
|
|
187
|
+
//#region src/util/ansi.ts
|
|
188
|
+
function isAnsiString(s) {
|
|
189
|
+
return s.includes("\x1B") || s.includes("");
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
*
|
|
193
|
+
* @param s - the string to measure - should NOT contains ANSI codes
|
|
194
|
+
* @param tabWidth -
|
|
195
|
+
* @returns
|
|
196
|
+
*/
|
|
197
|
+
function width(s, tabWidth = 1) {
|
|
198
|
+
return s.replaceAll("…", ".").replaceAll(" ", " ".repeat(tabWidth)).replaceAll(/\p{M}/gu, "").replaceAll(/\p{L}/gu, ".").replaceAll(/[\u0000-\u001F\u0300-\u036F]/g, "").replaceAll(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, ".").length;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Measure the width of a string containing ANSI control characters.
|
|
202
|
+
* @param s - string to measure with width in characters.
|
|
203
|
+
* @returns the approximate number of screen characters.
|
|
204
|
+
*/
|
|
205
|
+
function ansiWidth(s) {
|
|
206
|
+
return width(stripVTControlCharacters(s));
|
|
207
|
+
}
|
|
208
|
+
function fragmentString(str, splitOnRegex, sType) {
|
|
209
|
+
const fragments = [];
|
|
210
|
+
let lastIndex = 0;
|
|
211
|
+
for (const match of str.matchAll(new RegExp(splitOnRegex))) {
|
|
212
|
+
if (match.index > lastIndex) fragments.push({
|
|
213
|
+
type: "text",
|
|
214
|
+
text: str.slice(lastIndex, match.index)
|
|
215
|
+
});
|
|
216
|
+
fragments.push({
|
|
217
|
+
type: sType,
|
|
218
|
+
text: match[0]
|
|
219
|
+
});
|
|
220
|
+
lastIndex = match.index + match[0].length;
|
|
221
|
+
}
|
|
222
|
+
if (lastIndex < str.length) fragments.push({
|
|
223
|
+
type: "text",
|
|
224
|
+
text: str.slice(lastIndex)
|
|
225
|
+
});
|
|
226
|
+
return fragments;
|
|
227
|
+
}
|
|
228
|
+
const ansi = ansiRegex();
|
|
229
|
+
function parseAnsiStr(str) {
|
|
230
|
+
return fragmentString(str, ansi, "ansi");
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Prune the end of a string to fit within a specified width, adding an ellipsis if necessary.
|
|
234
|
+
* @param str - the text to prune - ANSI is supported
|
|
235
|
+
* @param maxWidth - the maximum width of the text
|
|
236
|
+
* @param pad - the string to use for padding, default is '…'
|
|
237
|
+
* @returns the pruned text
|
|
238
|
+
*/
|
|
239
|
+
function pruneAnsiTextEnd(str, maxWidth, pad$1 = "…") {
|
|
240
|
+
if (!maxWidth || maxWidth <= 0) return str;
|
|
241
|
+
if (str.length <= maxWidth) return str;
|
|
242
|
+
if (ansiWidth(str) <= maxWidth) return str;
|
|
243
|
+
const padWidth$1 = ansiWidth(pad$1);
|
|
244
|
+
const fragments = parseAnsiStr(str);
|
|
245
|
+
let remaining = maxWidth - padWidth$1;
|
|
246
|
+
for (const frag of fragments) {
|
|
247
|
+
if (frag.type !== "text") continue;
|
|
248
|
+
if (remaining <= 0) {
|
|
249
|
+
frag.text = "";
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
const pruned = pruneTextEnd(frag.text, remaining, pad$1);
|
|
253
|
+
if (pruned !== frag.text) {
|
|
254
|
+
frag.text = pruned;
|
|
255
|
+
remaining = 0;
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
remaining -= width(frag.text);
|
|
259
|
+
}
|
|
260
|
+
return fragments.map((frag) => frag.text).join("");
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Prune the start of a string to fit within a specified width, adding an ellipsis if necessary.
|
|
264
|
+
* @param str - the text to prune - ANSI is supported
|
|
265
|
+
* @param maxWidth - the maximum width of the text
|
|
266
|
+
* @param pad - the string to use for padding, default is '…'
|
|
267
|
+
* @returns the pruned text
|
|
268
|
+
*/
|
|
269
|
+
function pruneAnsiTextStart(str, maxWidth, pad$1 = "…") {
|
|
270
|
+
if (!maxWidth || maxWidth <= 0) return str;
|
|
271
|
+
if (str.length <= maxWidth) return str;
|
|
272
|
+
if (ansiWidth(str) <= maxWidth) return str;
|
|
273
|
+
const padWidth$1 = ansiWidth(pad$1);
|
|
274
|
+
const fragments = parseAnsiStr(str);
|
|
275
|
+
let remaining = maxWidth - padWidth$1;
|
|
276
|
+
for (const frag of fragments.reverse()) {
|
|
277
|
+
if (frag.type !== "text") continue;
|
|
278
|
+
if (remaining <= 0) {
|
|
279
|
+
frag.text = "";
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
const pruned = pruneTextStart(frag.text, remaining, pad$1);
|
|
283
|
+
if (pruned !== frag.text) {
|
|
284
|
+
frag.text = pruned;
|
|
285
|
+
remaining = 0;
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
remaining -= width(frag.text);
|
|
289
|
+
}
|
|
290
|
+
return fragments.reverse().map((frag) => frag.text).join("");
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Prune the end of a string to fit within a specified width, adding an ellipsis if necessary.
|
|
294
|
+
* @param str - the text to prune - ANSI is not supported
|
|
295
|
+
* @param maxWidth - the maximum width of the text
|
|
296
|
+
* @param pad - the string to use for padding, default is '…'
|
|
297
|
+
* @returns the pruned text
|
|
298
|
+
*/
|
|
299
|
+
function pruneTextEnd(str, maxWidth, pad$1 = "…") {
|
|
300
|
+
if (!maxWidth || maxWidth <= 0) return str;
|
|
301
|
+
if (str.length <= maxWidth) return str;
|
|
302
|
+
if (isAnsiString(str)) return pruneAnsiTextEnd(str, maxWidth, pad$1);
|
|
303
|
+
const maxWidthWithPad = maxWidth - width(pad$1);
|
|
304
|
+
const letters = [...str];
|
|
305
|
+
let len = 0;
|
|
306
|
+
for (let i = 0; i < letters.length; i++) {
|
|
307
|
+
const c = letters[i];
|
|
308
|
+
len += width(c);
|
|
309
|
+
if (len > maxWidthWithPad) {
|
|
310
|
+
let j = i + 1;
|
|
311
|
+
while (j < letters.length && width(letters[j]) === 0) ++j;
|
|
312
|
+
return j === letters.length ? str : letters.slice(0, i).join("") + pad$1;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return str;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Prune the start of a string to fit within a specified width, adding an ellipsis if necessary.
|
|
319
|
+
* @param str - the text to prune - ANSI is not supported
|
|
320
|
+
* @param maxWidth - the maximum width of the text
|
|
321
|
+
* @param pad - the string to use for padding, default is '…'
|
|
322
|
+
* @returns the pruned text
|
|
323
|
+
*/
|
|
324
|
+
function pruneTextStart(str, maxWidth, pad$1 = "…") {
|
|
325
|
+
if (!maxWidth || maxWidth <= 0) return str;
|
|
326
|
+
if (str.length <= maxWidth) return str;
|
|
327
|
+
const maxWidthWithPad = maxWidth - width(pad$1);
|
|
328
|
+
const letters = [...str];
|
|
329
|
+
let len = 0;
|
|
330
|
+
for (let i = letters.length - 1; i >= 1; i--) {
|
|
331
|
+
const c = letters[i];
|
|
332
|
+
len += width(c);
|
|
333
|
+
if (len > maxWidthWithPad) {
|
|
334
|
+
i += 1;
|
|
335
|
+
while (i < letters.length && width(letters[i]) === 0) ++i;
|
|
336
|
+
return pad$1 + letters.slice(i).join("");
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return str;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
//#endregion
|
|
343
|
+
//#region src/util/pad.ts
|
|
344
|
+
function pad(s, w) {
|
|
345
|
+
const p = padWidth(s, w);
|
|
346
|
+
if (!p) return s;
|
|
347
|
+
return s.padEnd(p + s.length);
|
|
348
|
+
}
|
|
349
|
+
function padWidth(s, target) {
|
|
350
|
+
const sWidth = ansiWidth(s);
|
|
351
|
+
return Math.max(target - sWidth, 0);
|
|
352
|
+
}
|
|
353
|
+
function padLeft(s, w) {
|
|
354
|
+
const p = padWidth(s, w);
|
|
355
|
+
if (!p) return s;
|
|
356
|
+
return s.padStart(p + s.length);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
//#endregion
|
|
360
|
+
//#region src/util/table.ts
|
|
361
|
+
function tableToLines(table, deliminator) {
|
|
362
|
+
const del = deliminator || table.deliminator || " | ";
|
|
363
|
+
const columnWidths = [];
|
|
364
|
+
const columnAlignments = table.columnAlignments || [];
|
|
365
|
+
const maxColumnWidthsMap = table.maxColumnWidths || {};
|
|
366
|
+
const tableIndent = table.indent ? typeof table.indent === "number" ? " ".repeat(table.indent) : table.indent : "";
|
|
367
|
+
const { header, rows } = table;
|
|
368
|
+
const simpleHeader = header.map((col) => Array.isArray(col) ? col[1] : col);
|
|
369
|
+
const columnFieldNames = header.map((col) => Array.isArray(col) ? col[0] : col);
|
|
370
|
+
const maxColumnWidths = columnFieldNames.map((field, idx) => maxColumnWidthsMap[field] ?? maxColumnWidthsMap[idx]);
|
|
371
|
+
function getCell(row, col) {
|
|
372
|
+
return getCellFromRow(rows[row], col);
|
|
373
|
+
}
|
|
374
|
+
function getCellFromRow(row, col) {
|
|
375
|
+
if (!row) return void 0;
|
|
376
|
+
if (Array.isArray(row)) return row[col];
|
|
377
|
+
return row[columnFieldNames[col]];
|
|
378
|
+
}
|
|
379
|
+
function rowToCells(row) {
|
|
380
|
+
if (Array.isArray(row)) return row;
|
|
381
|
+
return columnFieldNames.map((fieldName) => row[fieldName]);
|
|
382
|
+
}
|
|
383
|
+
function getText(col, maxWidth) {
|
|
384
|
+
return !col ? "" : typeof col === "string" ? pruneTextEnd(col, maxWidth) : col(maxWidth);
|
|
385
|
+
}
|
|
386
|
+
function getRCText(row, col, maxWidth) {
|
|
387
|
+
return getText(getCell(row, col), maxWidth);
|
|
388
|
+
}
|
|
389
|
+
function recordHeaderWidths(header$1) {
|
|
390
|
+
header$1.forEach((col, idx) => {
|
|
391
|
+
columnWidths[idx] = Math.max(ansiWidth(col), columnWidths[idx] || 0);
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
function recordColWidths() {
|
|
395
|
+
for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) for (let colIndex = 0; colIndex < columnFieldNames.length; colIndex++) columnWidths[colIndex] = Math.max(ansiWidth(getRCText(rowIndex, colIndex, void 0)), columnWidths[colIndex] || 0);
|
|
396
|
+
}
|
|
397
|
+
function justifyRow(c, i) {
|
|
398
|
+
return columnAlignments[i] === "R" ? padLeft(c, columnWidths[i]) : pad(c, columnWidths[i]);
|
|
399
|
+
}
|
|
400
|
+
function toHeaderLine(header$1) {
|
|
401
|
+
return tableIndent + decorateRowWith(header$1.map((c, i) => getText(c, columnWidths[i])), justifyRow, headerDecorator).join(del);
|
|
402
|
+
}
|
|
403
|
+
function toLine(row) {
|
|
404
|
+
return tableIndent + decorateRowWith(rowToCells(row).map((c, i) => getText(c, columnWidths[i])), justifyRow).join(del);
|
|
405
|
+
}
|
|
406
|
+
function* process$1() {
|
|
407
|
+
if (table.title) yield table.title;
|
|
408
|
+
yield toHeaderLine(simpleHeader);
|
|
409
|
+
yield* rows.map(toLine);
|
|
410
|
+
}
|
|
411
|
+
function sumColumnWidths() {
|
|
412
|
+
return columnWidths.reduce((sum, width$1) => sum + width$1, 0);
|
|
413
|
+
}
|
|
414
|
+
function adjustColWidths() {
|
|
415
|
+
for (let i = 0; i < columnWidths.length; i++) {
|
|
416
|
+
const mw = maxColumnWidths[i];
|
|
417
|
+
if (!mw) continue;
|
|
418
|
+
columnWidths[i] = Math.min(columnWidths[i], mw);
|
|
419
|
+
}
|
|
420
|
+
if (!table.terminalWidth) return;
|
|
421
|
+
const dWidth = (columnWidths.length - 1) * ansiWidth(del);
|
|
422
|
+
const lineWidth = table.terminalWidth - dWidth;
|
|
423
|
+
if (lineWidth <= columnWidths.length * 2) {
|
|
424
|
+
const fixedWidth = Math.max(Math.min(...columnWidths), 5);
|
|
425
|
+
for (let i = 0; i < columnWidths.length; i++) columnWidths[i] = fixedWidth;
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
if (columnWidths.length === 1) {
|
|
429
|
+
columnWidths[0] = lineWidth;
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
function trimWidestColumn(neededToTrim) {
|
|
433
|
+
let first = 0;
|
|
434
|
+
let second = 0;
|
|
435
|
+
for (let i = 0; i < columnWidths.length; i++) if (columnWidths[i] > columnWidths[first]) {
|
|
436
|
+
second = first;
|
|
437
|
+
first = i;
|
|
438
|
+
} else if (columnWidths[i] > columnWidths[second]) second = i;
|
|
439
|
+
const diff = Math.max(columnWidths[first] - columnWidths[second], 1);
|
|
440
|
+
columnWidths[first] -= Math.min(diff, neededToTrim);
|
|
441
|
+
}
|
|
442
|
+
for (let sum = sumColumnWidths(); sum > lineWidth; sum = sumColumnWidths()) trimWidestColumn(sum - lineWidth);
|
|
443
|
+
}
|
|
444
|
+
recordHeaderWidths(simpleHeader);
|
|
445
|
+
recordColWidths();
|
|
446
|
+
adjustColWidths();
|
|
447
|
+
return [...process$1()];
|
|
448
|
+
}
|
|
449
|
+
function headerDecorator(t) {
|
|
450
|
+
return chalk.bold(chalk.underline(t));
|
|
451
|
+
}
|
|
452
|
+
function decorateRowWith(row, ...decorators) {
|
|
453
|
+
return decorators.reduce((row$1, decorator) => row$1.map(decorator), row);
|
|
454
|
+
}
|
|
455
|
+
|
|
116
456
|
//#endregion
|
|
117
457
|
//#region src/util/util.ts
|
|
118
458
|
const uniqueFn = uniqueFilterFnGenerator;
|
|
@@ -222,7 +562,8 @@ function getReporter(options, config) {
|
|
|
222
562
|
filesProcessed: 0,
|
|
223
563
|
filesSkipped: 0,
|
|
224
564
|
filesCached: 0,
|
|
225
|
-
|
|
565
|
+
accumulatedTimeMs: 0,
|
|
566
|
+
startTime: performance.now(),
|
|
226
567
|
perf: Object.create(null)
|
|
227
568
|
};
|
|
228
569
|
const noColor = options.color === false;
|
|
@@ -279,6 +620,7 @@ function getReporter(options, config) {
|
|
|
279
620
|
if (!fileGlobs.length && !result.files) return;
|
|
280
621
|
const { files, issues: issues$1, cachedFiles, filesWithIssues, errors, skippedFiles } = result;
|
|
281
622
|
const numFilesWithIssues = filesWithIssues.size;
|
|
623
|
+
const chalk$1 = stderr.chalk;
|
|
282
624
|
if (stderr.getColorLevel() > 0) {
|
|
283
625
|
stderr.write("\r");
|
|
284
626
|
stderr.clearLine(0);
|
|
@@ -299,20 +641,88 @@ function getReporter(options, config) {
|
|
|
299
641
|
errorCollection.forEach((error) => consoleError(error));
|
|
300
642
|
}
|
|
301
643
|
if (options.showPerfSummary) {
|
|
644
|
+
const elapsedTotal = performance.now() - perfStats.startTime;
|
|
302
645
|
consoleError("-------------------------------------------");
|
|
303
646
|
consoleError("Performance Summary:");
|
|
304
|
-
consoleError(` Files Processed: ${perfStats.filesProcessed.toString().padStart(
|
|
305
|
-
consoleError(` Files Skipped
|
|
306
|
-
consoleError(` Files Cached
|
|
307
|
-
consoleError(` Processing Time: ${perfStats.
|
|
308
|
-
consoleError(
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
647
|
+
consoleError(` Files Processed : ${perfStats.filesProcessed.toString().padStart(11)}`);
|
|
648
|
+
consoleError(` Files Skipped : ${perfStats.filesSkipped.toString().padStart(11)}`);
|
|
649
|
+
consoleError(` Files Cached : ${perfStats.filesCached.toString().padStart(11)}`);
|
|
650
|
+
consoleError(` Processing Time : ${perfStats.accumulatedTimeMs.toFixed(2).padStart(9)}ms`);
|
|
651
|
+
consoleError(` Total Time : ${elapsedTotal.toFixed(2).padStart(9)}ms`);
|
|
652
|
+
const tableStats = {
|
|
653
|
+
title: chalk$1.bold("Perf Stats:"),
|
|
654
|
+
header: ["Name", "Time (ms)"],
|
|
655
|
+
columnAlignments: ["L", "R"],
|
|
656
|
+
indent: 2,
|
|
657
|
+
rows: Object.entries(perfStats.perf).filter((p) => !!p[1]).map(([key, value]) => [key, value.toFixed(2)])
|
|
658
|
+
};
|
|
659
|
+
consoleError("");
|
|
660
|
+
for (const line of tableToLines(tableStats)) consoleError(line);
|
|
661
|
+
if (options.verboseLevel) verbosePerfReport();
|
|
314
662
|
}
|
|
315
663
|
};
|
|
664
|
+
function verbosePerfReport() {
|
|
665
|
+
const perfMeasurements = getPerfMeasurements();
|
|
666
|
+
if (!perfMeasurements.length) return;
|
|
667
|
+
const notable = extractNotableBySelfTimeInGroup(perfMeasurements);
|
|
668
|
+
const chalk$1 = stderr.chalk;
|
|
669
|
+
const maxDepth = Math.max(...perfMeasurements.map((m) => m.depth));
|
|
670
|
+
const depthIndicator = (d) => "⋅".repeat(d) + " ".repeat(maxDepth - d);
|
|
671
|
+
const rows = perfMeasurements.map((m) => {
|
|
672
|
+
const cbd = (text) => colorByDepth(chalk$1, m.depth, text);
|
|
673
|
+
const cNotable = (text) => notable.has(m) ? chalk$1.yellow(text) : text;
|
|
674
|
+
return [
|
|
675
|
+
chalk$1.dim("⋅".repeat(m.depth)) + colorByDepthGrayscale(stderr.chalk, m.depth, m.name),
|
|
676
|
+
cbd(m.totalTimeMs.toFixed(2) + chalk$1.dim(depthIndicator(m.depth))),
|
|
677
|
+
cbd(cNotable((m.totalTimeMs - m.nestedTimeMs).toFixed(2))),
|
|
678
|
+
cbd(m.count.toString()),
|
|
679
|
+
cbd(m.minTimeMs.toFixed(2)),
|
|
680
|
+
cbd(m.maxTimeMs.toFixed(2)),
|
|
681
|
+
cbd((m.totalTimeMs / m.count).toFixed(2))
|
|
682
|
+
];
|
|
683
|
+
});
|
|
684
|
+
const table = tableToLines({
|
|
685
|
+
title: chalk$1.bold("Detailed Measurements:"),
|
|
686
|
+
header: [
|
|
687
|
+
"Name",
|
|
688
|
+
"Total Time (ms)",
|
|
689
|
+
"Self (ms)",
|
|
690
|
+
"Count",
|
|
691
|
+
"Min (ms)",
|
|
692
|
+
"Max (ms)",
|
|
693
|
+
"Avg (ms)"
|
|
694
|
+
],
|
|
695
|
+
rows,
|
|
696
|
+
columnAlignments: [
|
|
697
|
+
"L",
|
|
698
|
+
"R",
|
|
699
|
+
"R",
|
|
700
|
+
"R",
|
|
701
|
+
"R",
|
|
702
|
+
"R",
|
|
703
|
+
"R"
|
|
704
|
+
],
|
|
705
|
+
indent: 2
|
|
706
|
+
});
|
|
707
|
+
consoleError("\n-------------------------------------------\n");
|
|
708
|
+
for (const line of table) consoleError(line);
|
|
709
|
+
}
|
|
710
|
+
function colorByDepth(chalk$1, depth, text) {
|
|
711
|
+
const colors = [
|
|
712
|
+
chalk$1.green,
|
|
713
|
+
chalk$1.cyan,
|
|
714
|
+
chalk$1.blue,
|
|
715
|
+
chalk$1.magenta,
|
|
716
|
+
chalk$1.red
|
|
717
|
+
];
|
|
718
|
+
const color = colors[depth % colors.length];
|
|
719
|
+
if (depth / colors.length >= 1) return chalk$1.dim(color(text));
|
|
720
|
+
return color(text);
|
|
721
|
+
}
|
|
722
|
+
function colorByDepthGrayscale(chalk$1, depth, text) {
|
|
723
|
+
const grayLevel = Math.max(32, 255 - depth * 20);
|
|
724
|
+
return chalk$1.rgb(grayLevel, grayLevel, grayLevel)(text);
|
|
725
|
+
}
|
|
316
726
|
function collectPerfStats(p) {
|
|
317
727
|
if (p.cached) {
|
|
318
728
|
perfStats.filesCached++;
|
|
@@ -320,7 +730,7 @@ function getReporter(options, config) {
|
|
|
320
730
|
}
|
|
321
731
|
perfStats.filesProcessed += p.processed ? 1 : 0;
|
|
322
732
|
perfStats.filesSkipped += !p.processed ? 1 : 0;
|
|
323
|
-
perfStats.
|
|
733
|
+
perfStats.accumulatedTimeMs += p.elapsedTimeMs || 0;
|
|
324
734
|
if (!p.perf) return;
|
|
325
735
|
for (const [key, value] of Object.entries(p.perf)) if (typeof value === "number") perfStats.perf[key] = (perfStats.perf[key] || 0) + value;
|
|
326
736
|
}
|
|
@@ -338,6 +748,27 @@ function getReporter(options, config) {
|
|
|
338
748
|
features: void 0
|
|
339
749
|
};
|
|
340
750
|
}
|
|
751
|
+
function extractNotableBySelfTimeInGroup(measurements) {
|
|
752
|
+
const notable = /* @__PURE__ */ new Set();
|
|
753
|
+
if (!measurements.length) return notable;
|
|
754
|
+
let highest;
|
|
755
|
+
let highestSelfTime = 0;
|
|
756
|
+
for (const m of measurements) {
|
|
757
|
+
if (m.depth === 0 || !highest) {
|
|
758
|
+
if (highest) notable.add(highest);
|
|
759
|
+
highest = m;
|
|
760
|
+
highestSelfTime = m.totalTimeMs - m.nestedTimeMs;
|
|
761
|
+
continue;
|
|
762
|
+
}
|
|
763
|
+
const selfTime = m.totalTimeMs - m.nestedTimeMs;
|
|
764
|
+
if (selfTime > highestSelfTime) {
|
|
765
|
+
highest = m;
|
|
766
|
+
highestSelfTime = selfTime;
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
if (highest) notable.add(highest);
|
|
770
|
+
return notable;
|
|
771
|
+
}
|
|
341
772
|
function formatIssue(io, templateStr, issue, maxIssueTextWidth) {
|
|
342
773
|
function clean$1(t$1) {
|
|
343
774
|
return t$1.replace(/\s+/, " ");
|
|
@@ -447,7 +878,7 @@ async function fileExists(url) {
|
|
|
447
878
|
try {
|
|
448
879
|
return (await promises.stat(url)).isFile();
|
|
449
880
|
} catch (e) {
|
|
450
|
-
if (toError(e).code === "ENOENT") return false;
|
|
881
|
+
if (toError$1(e).code === "ENOENT") return false;
|
|
451
882
|
throw e;
|
|
452
883
|
}
|
|
453
884
|
}
|
|
@@ -770,8 +1201,8 @@ const pkgDir = _dirname;
|
|
|
770
1201
|
//#endregion
|
|
771
1202
|
//#region src/pkgInfo.ts
|
|
772
1203
|
const name = "cspell";
|
|
773
|
-
const version$1 = "9.
|
|
774
|
-
const engines = { node: ">=20" };
|
|
1204
|
+
const version$1 = "9.6.1";
|
|
1205
|
+
const engines = { node: ">=20.18" };
|
|
775
1206
|
const npmPackage = {
|
|
776
1207
|
name,
|
|
777
1208
|
version: version$1,
|
|
@@ -991,7 +1422,7 @@ function readFileInfo(filename, encoding = UTF8, handleNotFound = false) {
|
|
|
991
1422
|
text,
|
|
992
1423
|
filename
|
|
993
1424
|
}), (e) => {
|
|
994
|
-
const error = toError(e);
|
|
1425
|
+
const error = toError$1(e);
|
|
995
1426
|
return handleNotFound && error.code === "EISDIR" ? Promise.resolve({
|
|
996
1427
|
text: "",
|
|
997
1428
|
filename,
|
|
@@ -1181,7 +1612,7 @@ var ImplFileEntryCache = class {
|
|
|
1181
1612
|
return {
|
|
1182
1613
|
key: file,
|
|
1183
1614
|
notFound: true,
|
|
1184
|
-
err: toError
|
|
1615
|
+
err: toError(error)
|
|
1185
1616
|
};
|
|
1186
1617
|
}
|
|
1187
1618
|
if (this.useChecksum) return this.#getFileDescriptorUsingChecksum(file);
|
|
@@ -1296,7 +1727,7 @@ var ImplFileEntryCache = class {
|
|
|
1296
1727
|
function isNodeError(error) {
|
|
1297
1728
|
return typeof error === "object" && error !== null && "code" in error;
|
|
1298
1729
|
}
|
|
1299
|
-
function toError
|
|
1730
|
+
function toError(error) {
|
|
1300
1731
|
if (error instanceof Error) return error;
|
|
1301
1732
|
if (typeof error === "string") return new Error(error);
|
|
1302
1733
|
return new Error("Unknown error", { cause: error });
|
|
@@ -1648,109 +2079,38 @@ async function readConfigHandleError(filename) {
|
|
|
1648
2079
|
}
|
|
1649
2080
|
|
|
1650
2081
|
//#endregion
|
|
1651
|
-
//#region src/util/
|
|
1652
|
-
function
|
|
1653
|
-
if (
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
return
|
|
2082
|
+
//#region src/util/reporters.ts
|
|
2083
|
+
function filterFeatureIssues(features, issue, reportOptions) {
|
|
2084
|
+
if (issue.issueType === IssueType.directive) return features?.issueType && reportOptions?.validateDirectives || false;
|
|
2085
|
+
if (features?.unknownWords) return true;
|
|
2086
|
+
if (!reportOptions) return true;
|
|
2087
|
+
if (issue.isFlagged || !reportOptions.unknownWords || reportOptions.unknownWords === unknownWordsChoices.ReportAll) return true;
|
|
2088
|
+
if (issue.hasPreferredSuggestions && reportOptions.unknownWords !== unknownWordsChoices.ReportFlagged) return true;
|
|
2089
|
+
if (issue.hasSimpleSuggestions && reportOptions.unknownWords === unknownWordsChoices.ReportSimple) return true;
|
|
2090
|
+
return false;
|
|
1660
2091
|
}
|
|
1661
|
-
function
|
|
1662
|
-
if (
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
2092
|
+
function handleIssue(reporter, issue, reportOptions) {
|
|
2093
|
+
if (!reporter.issue) return;
|
|
2094
|
+
if (!filterFeatureIssues(reporter.features, issue, reportOptions)) return;
|
|
2095
|
+
if (!reporter.features?.contextGeneration && !issue.context) {
|
|
2096
|
+
issue = { ...issue };
|
|
2097
|
+
issue.context = issue.line;
|
|
1667
2098
|
}
|
|
1668
|
-
return
|
|
2099
|
+
return reporter.issue(issue, reportOptions);
|
|
1669
2100
|
}
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
}
|
|
1682
|
-
|
|
1683
|
-
}
|
|
1684
|
-
for (let n = contextRange / 2; n > 0 && right < lineText.length; n--, right++) {
|
|
1685
|
-
if (!isLetter.test(lineText[right])) break;
|
|
1686
|
-
if (isMark.test(lineText[right + 1])) right++;
|
|
1687
|
-
}
|
|
1688
|
-
left = left < 0 ? 0 : left;
|
|
1689
|
-
const t0 = lineText.slice(left, right);
|
|
1690
|
-
const tLeft = t0.trimStart();
|
|
1691
|
-
left = Math.min(left + t0.length - tLeft.length, start);
|
|
1692
|
-
return {
|
|
1693
|
-
text: tLeft.trimEnd(),
|
|
1694
|
-
offset: left
|
|
1695
|
-
};
|
|
1696
|
-
}
|
|
1697
|
-
function extractContext(tdo, contextRange) {
|
|
1698
|
-
const { line, offset, text } = tdo;
|
|
1699
|
-
const start = offset - line.offset;
|
|
1700
|
-
const context = lineContext(line.text, start, start + text.length, contextRange);
|
|
1701
|
-
context.offset += line.offset;
|
|
1702
|
-
return context;
|
|
1703
|
-
}
|
|
1704
|
-
|
|
1705
|
-
//#endregion
|
|
1706
|
-
//#region src/util/prefetch.ts
|
|
1707
|
-
function* prefetchIterable(iterable, size) {
|
|
1708
|
-
assert(size >= 0);
|
|
1709
|
-
const buffer = [];
|
|
1710
|
-
for (const value of iterable) {
|
|
1711
|
-
buffer.push(value);
|
|
1712
|
-
if (buffer.length >= size - 1) {
|
|
1713
|
-
const value$1 = buffer[0];
|
|
1714
|
-
buffer.shift();
|
|
1715
|
-
yield value$1;
|
|
1716
|
-
}
|
|
1717
|
-
}
|
|
1718
|
-
yield* buffer;
|
|
1719
|
-
}
|
|
1720
|
-
|
|
1721
|
-
//#endregion
|
|
1722
|
-
//#region src/util/reporters.ts
|
|
1723
|
-
function filterFeatureIssues(features, issue, reportOptions) {
|
|
1724
|
-
if (issue.issueType === IssueType.directive) return features?.issueType && reportOptions?.validateDirectives || false;
|
|
1725
|
-
if (features?.unknownWords) return true;
|
|
1726
|
-
if (!reportOptions) return true;
|
|
1727
|
-
if (issue.isFlagged || !reportOptions.unknownWords || reportOptions.unknownWords === unknownWordsChoices.ReportAll) return true;
|
|
1728
|
-
if (issue.hasPreferredSuggestions && reportOptions.unknownWords !== unknownWordsChoices.ReportFlagged) return true;
|
|
1729
|
-
if (issue.hasSimpleSuggestions && reportOptions.unknownWords === unknownWordsChoices.ReportSimple) return true;
|
|
1730
|
-
return false;
|
|
1731
|
-
}
|
|
1732
|
-
function handleIssue(reporter, issue, reportOptions) {
|
|
1733
|
-
if (!reporter.issue) return;
|
|
1734
|
-
if (!filterFeatureIssues(reporter.features, issue, reportOptions)) return;
|
|
1735
|
-
if (!reporter.features?.contextGeneration && !issue.context) {
|
|
1736
|
-
issue = { ...issue };
|
|
1737
|
-
issue.context = issue.line;
|
|
1738
|
-
}
|
|
1739
|
-
return reporter.issue(issue, reportOptions);
|
|
1740
|
-
}
|
|
1741
|
-
/**
|
|
1742
|
-
* Loads reporter modules configured in cspell config file
|
|
1743
|
-
*/
|
|
1744
|
-
async function loadReporters(reporters, defaultReporter, config) {
|
|
1745
|
-
async function loadReporter(reporterSettings) {
|
|
1746
|
-
if (reporterSettings === "default") return defaultReporter;
|
|
1747
|
-
if (!Array.isArray(reporterSettings)) reporterSettings = [reporterSettings];
|
|
1748
|
-
const [moduleName, settings] = reporterSettings;
|
|
1749
|
-
try {
|
|
1750
|
-
const { getReporter: getReporter$1 } = await dynamicImport(moduleName, [process.cwd(), pkgDir]);
|
|
1751
|
-
return getReporter$1(settings, config);
|
|
1752
|
-
} catch (e) {
|
|
1753
|
-
throw new ApplicationError(`Failed to load reporter ${moduleName}: ${toError(e).message}`);
|
|
2101
|
+
/**
|
|
2102
|
+
* Loads reporter modules configured in cspell config file
|
|
2103
|
+
*/
|
|
2104
|
+
async function loadReporters(reporters, defaultReporter, config) {
|
|
2105
|
+
async function loadReporter(reporterSettings) {
|
|
2106
|
+
if (reporterSettings === "default") return defaultReporter;
|
|
2107
|
+
if (!Array.isArray(reporterSettings)) reporterSettings = [reporterSettings];
|
|
2108
|
+
const [moduleName, settings] = reporterSettings;
|
|
2109
|
+
try {
|
|
2110
|
+
const { getReporter: getReporter$1 } = await dynamicImport(moduleName, [process.cwd(), pkgDir]);
|
|
2111
|
+
return getReporter$1(settings, config);
|
|
2112
|
+
} catch (e) {
|
|
2113
|
+
throw new ApplicationError(`Failed to load reporter ${moduleName}: ${toError$1(e).message}`);
|
|
1754
2114
|
}
|
|
1755
2115
|
}
|
|
1756
2116
|
reporters = !reporters || !reporters.length ? ["default"] : [...reporters];
|
|
@@ -1892,11 +2252,11 @@ function getTimeMeasurer() {
|
|
|
1892
2252
|
* @returns
|
|
1893
2253
|
*/
|
|
1894
2254
|
function indent(str, padding, firstLinePadding = "") {
|
|
1895
|
-
let pad = firstLinePadding;
|
|
2255
|
+
let pad$1 = firstLinePadding;
|
|
1896
2256
|
const lines = [];
|
|
1897
2257
|
for (const line of str.split("\n")) {
|
|
1898
|
-
lines.push(pad + line);
|
|
1899
|
-
pad = padding;
|
|
2258
|
+
lines.push(pad$1 + line);
|
|
2259
|
+
pad$1 = padding;
|
|
1900
2260
|
}
|
|
1901
2261
|
return lines.join("\n");
|
|
1902
2262
|
}
|
|
@@ -1939,206 +2299,6 @@ function unindentString(str) {
|
|
|
1939
2299
|
return lines.map((line) => line.slice(curPad)).join("\n");
|
|
1940
2300
|
}
|
|
1941
2301
|
|
|
1942
|
-
//#endregion
|
|
1943
|
-
//#region src/util/unitNumbers.ts
|
|
1944
|
-
const regexUnitNumber = /^((?:\d+(?:\.\d*)?)|(?:\.\d+))([a-z]*)$/i;
|
|
1945
|
-
const unitSizes = {
|
|
1946
|
-
"": 1,
|
|
1947
|
-
b: 1,
|
|
1948
|
-
k: 1024,
|
|
1949
|
-
kb: 1024,
|
|
1950
|
-
m: 1 << 20,
|
|
1951
|
-
mb: 1 << 20,
|
|
1952
|
-
g: 1 << 30,
|
|
1953
|
-
gb: 1 << 30
|
|
1954
|
-
};
|
|
1955
|
-
function parseUnitSize(size) {
|
|
1956
|
-
const match = size.match(regexUnitNumber);
|
|
1957
|
-
const digits = match?.[1] || "";
|
|
1958
|
-
const units = (match?.[2] || "").toLowerCase();
|
|
1959
|
-
if (!match) return {
|
|
1960
|
-
size,
|
|
1961
|
-
digits,
|
|
1962
|
-
units,
|
|
1963
|
-
error: "Invalid size."
|
|
1964
|
-
};
|
|
1965
|
-
if (!units || units in unitSizes) return {
|
|
1966
|
-
size,
|
|
1967
|
-
digits,
|
|
1968
|
-
units
|
|
1969
|
-
};
|
|
1970
|
-
return {
|
|
1971
|
-
size,
|
|
1972
|
-
digits,
|
|
1973
|
-
units,
|
|
1974
|
-
error: `Unknown units. Valid units are: ${Object.keys(unitSizes).filter(Boolean).join(", ").toUpperCase()}.`
|
|
1975
|
-
};
|
|
1976
|
-
}
|
|
1977
|
-
function validateUnitSize(size) {
|
|
1978
|
-
return parseUnitSize(size).error;
|
|
1979
|
-
}
|
|
1980
|
-
function sizeToNumber(size) {
|
|
1981
|
-
const p = parseUnitSize(size);
|
|
1982
|
-
if (p.error) return NaN;
|
|
1983
|
-
return Number.parseFloat(p.digits) * (unitSizes[p.units] || 1);
|
|
1984
|
-
}
|
|
1985
|
-
|
|
1986
|
-
//#endregion
|
|
1987
|
-
//#region src/util/ansi.ts
|
|
1988
|
-
function isAnsiString(s) {
|
|
1989
|
-
return s.includes("\x1B") || s.includes("");
|
|
1990
|
-
}
|
|
1991
|
-
/**
|
|
1992
|
-
*
|
|
1993
|
-
* @param s - the string to measure - should NOT contains ANSI codes
|
|
1994
|
-
* @param tabWidth -
|
|
1995
|
-
* @returns
|
|
1996
|
-
*/
|
|
1997
|
-
function width(s, tabWidth = 1) {
|
|
1998
|
-
return s.replaceAll("…", ".").replaceAll(" ", " ".repeat(tabWidth)).replaceAll(/\p{M}/gu, "").replaceAll(/\p{L}/gu, ".").replaceAll(/[\u0000-\u001F\u0300-\u036F]/g, "").replaceAll(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, ".").length;
|
|
1999
|
-
}
|
|
2000
|
-
/**
|
|
2001
|
-
* Measure the width of a string containing ANSI control characters.
|
|
2002
|
-
* @param s - string to measure with width in characters.
|
|
2003
|
-
* @returns the approximate number of screen characters.
|
|
2004
|
-
*/
|
|
2005
|
-
function ansiWidth(s) {
|
|
2006
|
-
return width(stripVTControlCharacters(s));
|
|
2007
|
-
}
|
|
2008
|
-
function fragmentString(str, splitOnRegex, sType) {
|
|
2009
|
-
const fragments = [];
|
|
2010
|
-
let lastIndex = 0;
|
|
2011
|
-
for (const match of str.matchAll(new RegExp(splitOnRegex))) {
|
|
2012
|
-
if (match.index > lastIndex) fragments.push({
|
|
2013
|
-
type: "text",
|
|
2014
|
-
text: str.slice(lastIndex, match.index)
|
|
2015
|
-
});
|
|
2016
|
-
fragments.push({
|
|
2017
|
-
type: sType,
|
|
2018
|
-
text: match[0]
|
|
2019
|
-
});
|
|
2020
|
-
lastIndex = match.index + match[0].length;
|
|
2021
|
-
}
|
|
2022
|
-
if (lastIndex < str.length) fragments.push({
|
|
2023
|
-
type: "text",
|
|
2024
|
-
text: str.slice(lastIndex)
|
|
2025
|
-
});
|
|
2026
|
-
return fragments;
|
|
2027
|
-
}
|
|
2028
|
-
const ansi = ansiRegex();
|
|
2029
|
-
function parseAnsiStr(str) {
|
|
2030
|
-
return fragmentString(str, ansi, "ansi");
|
|
2031
|
-
}
|
|
2032
|
-
/**
|
|
2033
|
-
* Prune the end of a string to fit within a specified width, adding an ellipsis if necessary.
|
|
2034
|
-
* @param str - the text to prune - ANSI is supported
|
|
2035
|
-
* @param maxWidth - the maximum width of the text
|
|
2036
|
-
* @param pad - the string to use for padding, default is '…'
|
|
2037
|
-
* @returns the pruned text
|
|
2038
|
-
*/
|
|
2039
|
-
function pruneAnsiTextEnd(str, maxWidth, pad = "…") {
|
|
2040
|
-
if (!maxWidth || maxWidth <= 0) return str;
|
|
2041
|
-
if (str.length <= maxWidth) return str;
|
|
2042
|
-
if (ansiWidth(str) <= maxWidth) return str;
|
|
2043
|
-
const padWidth = ansiWidth(pad);
|
|
2044
|
-
const fragments = parseAnsiStr(str);
|
|
2045
|
-
let remaining = maxWidth - padWidth;
|
|
2046
|
-
for (const frag of fragments) {
|
|
2047
|
-
if (frag.type !== "text") continue;
|
|
2048
|
-
if (remaining <= 0) {
|
|
2049
|
-
frag.text = "";
|
|
2050
|
-
continue;
|
|
2051
|
-
}
|
|
2052
|
-
const pruned = pruneTextEnd(frag.text, remaining, pad);
|
|
2053
|
-
if (pruned !== frag.text) {
|
|
2054
|
-
frag.text = pruned;
|
|
2055
|
-
remaining = 0;
|
|
2056
|
-
continue;
|
|
2057
|
-
}
|
|
2058
|
-
remaining -= width(frag.text);
|
|
2059
|
-
}
|
|
2060
|
-
return fragments.map((frag) => frag.text).join("");
|
|
2061
|
-
}
|
|
2062
|
-
/**
|
|
2063
|
-
* Prune the start of a string to fit within a specified width, adding an ellipsis if necessary.
|
|
2064
|
-
* @param str - the text to prune - ANSI is supported
|
|
2065
|
-
* @param maxWidth - the maximum width of the text
|
|
2066
|
-
* @param pad - the string to use for padding, default is '…'
|
|
2067
|
-
* @returns the pruned text
|
|
2068
|
-
*/
|
|
2069
|
-
function pruneAnsiTextStart(str, maxWidth, pad = "…") {
|
|
2070
|
-
if (!maxWidth || maxWidth <= 0) return str;
|
|
2071
|
-
if (str.length <= maxWidth) return str;
|
|
2072
|
-
if (ansiWidth(str) <= maxWidth) return str;
|
|
2073
|
-
const padWidth = ansiWidth(pad);
|
|
2074
|
-
const fragments = parseAnsiStr(str);
|
|
2075
|
-
let remaining = maxWidth - padWidth;
|
|
2076
|
-
for (const frag of fragments.reverse()) {
|
|
2077
|
-
if (frag.type !== "text") continue;
|
|
2078
|
-
if (remaining <= 0) {
|
|
2079
|
-
frag.text = "";
|
|
2080
|
-
continue;
|
|
2081
|
-
}
|
|
2082
|
-
const pruned = pruneTextStart(frag.text, remaining, pad);
|
|
2083
|
-
if (pruned !== frag.text) {
|
|
2084
|
-
frag.text = pruned;
|
|
2085
|
-
remaining = 0;
|
|
2086
|
-
continue;
|
|
2087
|
-
}
|
|
2088
|
-
remaining -= width(frag.text);
|
|
2089
|
-
}
|
|
2090
|
-
return fragments.reverse().map((frag) => frag.text).join("");
|
|
2091
|
-
}
|
|
2092
|
-
/**
|
|
2093
|
-
* Prune the end of a string to fit within a specified width, adding an ellipsis if necessary.
|
|
2094
|
-
* @param str - the text to prune - ANSI is not supported
|
|
2095
|
-
* @param maxWidth - the maximum width of the text
|
|
2096
|
-
* @param pad - the string to use for padding, default is '…'
|
|
2097
|
-
* @returns the pruned text
|
|
2098
|
-
*/
|
|
2099
|
-
function pruneTextEnd(str, maxWidth, pad = "…") {
|
|
2100
|
-
if (!maxWidth || maxWidth <= 0) return str;
|
|
2101
|
-
if (str.length <= maxWidth) return str;
|
|
2102
|
-
if (isAnsiString(str)) return pruneAnsiTextEnd(str, maxWidth, pad);
|
|
2103
|
-
const maxWidthWithPad = maxWidth - width(pad);
|
|
2104
|
-
const letters = [...str];
|
|
2105
|
-
let len = 0;
|
|
2106
|
-
for (let i = 0; i < letters.length; i++) {
|
|
2107
|
-
const c = letters[i];
|
|
2108
|
-
len += width(c);
|
|
2109
|
-
if (len > maxWidthWithPad) {
|
|
2110
|
-
let j = i + 1;
|
|
2111
|
-
while (j < letters.length && width(letters[j]) === 0) ++j;
|
|
2112
|
-
return j === letters.length ? str : letters.slice(0, i).join("") + pad;
|
|
2113
|
-
}
|
|
2114
|
-
}
|
|
2115
|
-
return str;
|
|
2116
|
-
}
|
|
2117
|
-
/**
|
|
2118
|
-
* Prune the start of a string to fit within a specified width, adding an ellipsis if necessary.
|
|
2119
|
-
* @param str - the text to prune - ANSI is not supported
|
|
2120
|
-
* @param maxWidth - the maximum width of the text
|
|
2121
|
-
* @param pad - the string to use for padding, default is '…'
|
|
2122
|
-
* @returns the pruned text
|
|
2123
|
-
*/
|
|
2124
|
-
function pruneTextStart(str, maxWidth, pad = "…") {
|
|
2125
|
-
if (!maxWidth || maxWidth <= 0) return str;
|
|
2126
|
-
if (str.length <= maxWidth) return str;
|
|
2127
|
-
const maxWidthWithPad = maxWidth - width(pad);
|
|
2128
|
-
const letters = [...str];
|
|
2129
|
-
let len = 0;
|
|
2130
|
-
for (let i = letters.length - 1; i >= 1; i--) {
|
|
2131
|
-
const c = letters[i];
|
|
2132
|
-
len += width(c);
|
|
2133
|
-
if (len > maxWidthWithPad) {
|
|
2134
|
-
i += 1;
|
|
2135
|
-
while (i < letters.length && width(letters[i]) === 0) ++i;
|
|
2136
|
-
return pad + letters.slice(i).join("");
|
|
2137
|
-
}
|
|
2138
|
-
}
|
|
2139
|
-
return str;
|
|
2140
|
-
}
|
|
2141
|
-
|
|
2142
2302
|
//#endregion
|
|
2143
2303
|
//#region src/util/wrap.ts
|
|
2144
2304
|
const wrapSep = /\s+|(?<=,)|\.(?=\w)/g;
|
|
@@ -2200,157 +2360,137 @@ function writeStream(stream, data) {
|
|
|
2200
2360
|
}
|
|
2201
2361
|
|
|
2202
2362
|
//#endregion
|
|
2203
|
-
//#region src/
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
if (
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
return
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
if (cachedResult) {
|
|
2234
|
-
reporter.debug(`Filename: ${filename}, using cache`);
|
|
2235
|
-
return { fileResult: {
|
|
2236
|
-
...cachedResult,
|
|
2237
|
-
elapsedTimeMs: getElapsedTimeMs()
|
|
2238
|
-
} };
|
|
2239
|
-
}
|
|
2240
|
-
const uri = filenameToUri(filename, cfg.root).href;
|
|
2241
|
-
const checkResult = await shouldCheckDocument({ uri }, {}, configInfo.config);
|
|
2242
|
-
if (!checkResult.shouldCheck) return {
|
|
2243
|
-
skip: true,
|
|
2244
|
-
skipReason: checkResult.reason || "Ignored by configuration."
|
|
2245
|
-
};
|
|
2246
|
-
const maxFileSize = processMaxFileSize(cfg.maxFileSize ?? checkResult.settings.maxFileSize);
|
|
2247
|
-
if (maxFileSize) {
|
|
2248
|
-
if (await getFileSize(filename) > maxFileSize) return {
|
|
2249
|
-
skip: true,
|
|
2250
|
-
skipReason: `File exceeded max file size of ${maxFileSize.toLocaleString()}`
|
|
2251
|
-
};
|
|
2252
|
-
}
|
|
2253
|
-
return {
|
|
2254
|
-
fileInfo: await readFileInfo(filename, void 0, true),
|
|
2255
|
-
reportIssueOptions
|
|
2256
|
-
};
|
|
2363
|
+
//#region src/util/extractContext.ts
|
|
2364
|
+
function prefCharIndex(text, offset, count = 1) {
|
|
2365
|
+
if (offset - count < 0) return 0;
|
|
2366
|
+
for (; count > 0 && offset > 0; count--) {
|
|
2367
|
+
let code = text.charCodeAt(--offset) || 0;
|
|
2368
|
+
if (code === 65039) code = text.charCodeAt(--offset) || 0;
|
|
2369
|
+
offset -= (code & 64512) === 56320 ? 1 : 0;
|
|
2370
|
+
}
|
|
2371
|
+
return offset < 0 ? 0 : offset;
|
|
2372
|
+
}
|
|
2373
|
+
function nextCharIndex(text, offset, count = 1) {
|
|
2374
|
+
if (offset + count >= text.length) return text.length;
|
|
2375
|
+
for (; count > 0 && offset < text.length; count--) {
|
|
2376
|
+
const code = text.charCodeAt(offset++) || 0;
|
|
2377
|
+
offset += (code & 64512) === 55296 ? 1 : 0;
|
|
2378
|
+
if (text.charCodeAt(offset) === 65039) offset++;
|
|
2379
|
+
}
|
|
2380
|
+
return offset > text.length ? text.length : offset;
|
|
2381
|
+
}
|
|
2382
|
+
function lineContext(lineText, start, end, contextRange) {
|
|
2383
|
+
let left = prefCharIndex(lineText, start, contextRange);
|
|
2384
|
+
let right = nextCharIndex(lineText, end, contextRange);
|
|
2385
|
+
const isLetter = /^\p{L}$/u;
|
|
2386
|
+
const isMark = /^\p{M}$/u;
|
|
2387
|
+
for (let n = contextRange / 2; n > 0 && left > 0; n--, left--) {
|
|
2388
|
+
const c = lineText[left - 1];
|
|
2389
|
+
if (isMark.test(c)) {
|
|
2390
|
+
if (!isLetter.test(lineText[left - 2])) break;
|
|
2391
|
+
left--;
|
|
2392
|
+
continue;
|
|
2257
2393
|
}
|
|
2394
|
+
if (!isLetter.test(lineText[left - 1])) break;
|
|
2395
|
+
}
|
|
2396
|
+
for (let n = contextRange / 2; n > 0 && right < lineText.length; n--, right++) {
|
|
2397
|
+
if (!isLetter.test(lineText[right])) break;
|
|
2398
|
+
if (isMark.test(lineText[right + 1])) right++;
|
|
2399
|
+
}
|
|
2400
|
+
left = left < 0 ? 0 : left;
|
|
2401
|
+
const t0 = lineText.slice(left, right);
|
|
2402
|
+
const tLeft = t0.trimStart();
|
|
2403
|
+
left = Math.min(left + t0.length - tLeft.length, start);
|
|
2404
|
+
return {
|
|
2405
|
+
text: tLeft.trimEnd(),
|
|
2406
|
+
offset: left
|
|
2407
|
+
};
|
|
2408
|
+
}
|
|
2409
|
+
function extractContext(tdo, contextRange) {
|
|
2410
|
+
const { line, offset, text } = tdo;
|
|
2411
|
+
const start = offset - line.offset;
|
|
2412
|
+
const context = lineContext(line.text, start, start + text.length, contextRange);
|
|
2413
|
+
context.offset += line.offset;
|
|
2414
|
+
return context;
|
|
2415
|
+
}
|
|
2416
|
+
|
|
2417
|
+
//#endregion
|
|
2418
|
+
//#region src/lint/LinterError.ts
|
|
2419
|
+
var LinterError = class extends Error {
|
|
2420
|
+
constructor(message) {
|
|
2421
|
+
super(message);
|
|
2422
|
+
}
|
|
2423
|
+
toString() {
|
|
2424
|
+
return this.message;
|
|
2425
|
+
}
|
|
2426
|
+
};
|
|
2427
|
+
|
|
2428
|
+
//#endregion
|
|
2429
|
+
//#region src/lint/processFile.ts
|
|
2430
|
+
async function processFile(filename, cache, prefetch$1, processFileOptions) {
|
|
2431
|
+
if (prefetch$1?.fileResult) return prefetch$1.fileResult;
|
|
2432
|
+
const { reporter, cfg, configInfo, userSettings } = processFileOptions;
|
|
2433
|
+
const getElapsedTimeMs = getTimeMeasurer();
|
|
2434
|
+
const reportIssueOptions = prefetch$1?.reportIssueOptions;
|
|
2435
|
+
const cachedResult = await cache.getCachedLintResults(filename);
|
|
2436
|
+
if (cachedResult) {
|
|
2437
|
+
reporter.debug(`Filename: ${filename}, using cache`);
|
|
2258
2438
|
return {
|
|
2259
|
-
|
|
2260
|
-
|
|
2439
|
+
...cachedResult,
|
|
2440
|
+
elapsedTimeMs: getElapsedTimeMs(),
|
|
2441
|
+
reportIssueOptions: {
|
|
2442
|
+
...cachedResult.reportIssueOptions,
|
|
2443
|
+
...reportIssueOptions
|
|
2444
|
+
}
|
|
2261
2445
|
};
|
|
2262
2446
|
}
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
};
|
|
2278
|
-
}
|
|
2279
|
-
const result = {
|
|
2280
|
-
fileInfo: { filename },
|
|
2281
|
-
issues: [],
|
|
2282
|
-
processed: false,
|
|
2283
|
-
errors: 0,
|
|
2284
|
-
configErrors: 0,
|
|
2285
|
-
elapsedTimeMs: 0,
|
|
2286
|
-
reportIssueOptions
|
|
2287
|
-
};
|
|
2288
|
-
const fileInfo = prefetch$1?.fileInfo || await readFileInfo(filename, void 0, true);
|
|
2289
|
-
if (fileInfo.errorCode) {
|
|
2290
|
-
if (fileInfo.errorCode !== "EISDIR" && cfg.options.mustFindFiles) {
|
|
2291
|
-
const err = new LinterError(`File not found: "${filename}"`);
|
|
2292
|
-
reporter.error("Linter:", err);
|
|
2293
|
-
result.errors += 1;
|
|
2294
|
-
}
|
|
2295
|
-
return result;
|
|
2296
|
-
}
|
|
2297
|
-
const doc = fileInfoToDocument(fileInfo, cfg.options.languageId, cfg.locale);
|
|
2298
|
-
const { text } = fileInfo;
|
|
2299
|
-
result.fileInfo = fileInfo;
|
|
2300
|
-
let spellResult = {};
|
|
2301
|
-
try {
|
|
2302
|
-
const { showSuggestions: generateSuggestions, validateDirectives, skipValidation } = cfg.options;
|
|
2303
|
-
const numSuggestions = configInfo.config.numSuggestions ?? 5;
|
|
2304
|
-
const r = await spellCheckDocument(doc, clean({
|
|
2305
|
-
generateSuggestions,
|
|
2306
|
-
numSuggestions,
|
|
2307
|
-
validateDirectives,
|
|
2308
|
-
skipValidation
|
|
2309
|
-
}), configInfo.config);
|
|
2310
|
-
spellResult = r;
|
|
2311
|
-
result.processed = r.checked;
|
|
2312
|
-
result.perf = r.perf ? { ...r.perf } : void 0;
|
|
2313
|
-
result.issues = Text.calculateTextDocumentOffsets(doc.uri, text, r.issues).map(mapIssue);
|
|
2314
|
-
} catch (e) {
|
|
2315
|
-
reporter.error(`Failed to process "${filename}"`, toError(e));
|
|
2447
|
+
const result = {
|
|
2448
|
+
fileInfo: { filename },
|
|
2449
|
+
issues: [],
|
|
2450
|
+
processed: false,
|
|
2451
|
+
errors: 0,
|
|
2452
|
+
configErrors: 0,
|
|
2453
|
+
elapsedTimeMs: 0,
|
|
2454
|
+
reportIssueOptions
|
|
2455
|
+
};
|
|
2456
|
+
const fileInfo = prefetch$1?.fileInfo || await readFileInfo(filename, void 0, true);
|
|
2457
|
+
if (fileInfo.errorCode) {
|
|
2458
|
+
if (fileInfo.errorCode !== "EISDIR" && cfg.options.mustFindFiles) {
|
|
2459
|
+
const err = new LinterError(`File not found: "${filename}"`);
|
|
2460
|
+
reporter.error("Linter:", err);
|
|
2316
2461
|
result.errors += 1;
|
|
2317
2462
|
}
|
|
2318
|
-
result.elapsedTimeMs = getElapsedTimeMs();
|
|
2319
|
-
const config = spellResult.settingsUsed ?? {};
|
|
2320
|
-
result.reportIssueOptions = mergeReportIssueOptions(spellResult.settingsUsed || configInfo.config, reportIssueOptions);
|
|
2321
|
-
result.configErrors += await reportConfigurationErrors(config);
|
|
2322
|
-
reportCheckResult(result, doc, spellResult, configInfo, config);
|
|
2323
|
-
const dep = calcDependencies(config);
|
|
2324
|
-
await cache.setCachedLintResults(result, dep.files);
|
|
2325
2463
|
return result;
|
|
2326
2464
|
}
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2465
|
+
const doc = fileInfoToDocument(fileInfo, cfg.options.languageId, cfg.locale);
|
|
2466
|
+
const { text } = fileInfo;
|
|
2467
|
+
result.fileInfo = fileInfo;
|
|
2468
|
+
let spellResult = {};
|
|
2469
|
+
try {
|
|
2470
|
+
const { showSuggestions: generateSuggestions, validateDirectives, skipValidation } = cfg.options;
|
|
2471
|
+
const numSuggestions = configInfo.config.numSuggestions ?? 5;
|
|
2472
|
+
const r = await spellCheckDocument(doc, clean({
|
|
2473
|
+
generateSuggestions,
|
|
2474
|
+
numSuggestions,
|
|
2475
|
+
validateDirectives,
|
|
2476
|
+
skipValidation
|
|
2477
|
+
}), userSettings);
|
|
2478
|
+
spellResult = r;
|
|
2479
|
+
result.processed = r.checked;
|
|
2480
|
+
result.perf = r.perf ? { ...r.perf } : void 0;
|
|
2481
|
+
result.issues = Text.calculateTextDocumentOffsets(doc.uri, text, r.issues).map(mapIssue);
|
|
2482
|
+
} catch (e) {
|
|
2483
|
+
reporter.error(`Failed to process "${filename}"`, toError$1(e));
|
|
2484
|
+
result.errors += 1;
|
|
2485
|
+
}
|
|
2486
|
+
result.elapsedTimeMs = getElapsedTimeMs();
|
|
2487
|
+
const config = spellResult.settingsUsed ?? {};
|
|
2488
|
+
result.reportIssueOptions = mergeReportIssueOptions(spellResult.settingsUsed || configInfo.config, reportIssueOptions);
|
|
2489
|
+
result.configErrors += reportSpellingResultConfigErrors(spellResult, processFileOptions);
|
|
2490
|
+
reportCheckResult(result, doc, spellResult, config, processFileOptions);
|
|
2491
|
+
const dep = calcDependencies(config);
|
|
2492
|
+
await cache.setCachedLintResults(result, dep.files);
|
|
2493
|
+
return result;
|
|
2354
2494
|
function mapIssue({ doc: _, ...tdo }) {
|
|
2355
2495
|
const context = cfg.showContext ? extractContext(tdo, cfg.showContext) : void 0;
|
|
2356
2496
|
return clean({
|
|
@@ -2358,142 +2498,427 @@ async function runLint(cfg) {
|
|
|
2358
2498
|
context
|
|
2359
2499
|
});
|
|
2360
2500
|
}
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2501
|
+
}
|
|
2502
|
+
function reportCheckResult(result, _doc, spellResult, config, processFileOptions) {
|
|
2503
|
+
const { configInfo, reporter, verboseLevel, useColor, cfg, chalk: chalk$1 } = processFileOptions;
|
|
2504
|
+
const elapsed = result.elapsedTimeMs || 0;
|
|
2505
|
+
const dictionaries = config.dictionaries || [];
|
|
2506
|
+
if (verboseLevel > 1) {
|
|
2507
|
+
const dictsUsed = [...dictionaries].sort().map((name$1) => chalk$1.green(name$1)).join(", ");
|
|
2508
|
+
const msg = unindent`
|
|
2509
|
+
File type: ${config.languageId}, Language: ${config.language}, Issues: ${result.issues.length} ${elapsed.toFixed(2)}ms
|
|
2510
|
+
Config file Used: ${relativeToCwd(spellResult.localConfigFilepath || configInfo.source, cfg.root)}
|
|
2511
|
+
Dictionaries Used:
|
|
2512
|
+
${wordWrapAnsiText(dictsUsed, 70)}`;
|
|
2513
|
+
reporter.info(indent(msg, " "), MessageTypes.Info);
|
|
2514
|
+
}
|
|
2515
|
+
if (cfg.options.debug) {
|
|
2516
|
+
const { enabled, language, languageId, dictionaries: dictionaries$1 } = config;
|
|
2517
|
+
const msg = unindent`\
|
|
2518
|
+
Debug Config: ${formatWithOptions({
|
|
2519
|
+
depth: 2,
|
|
2520
|
+
colors: useColor
|
|
2521
|
+
}, {
|
|
2522
|
+
languageId,
|
|
2523
|
+
enabled,
|
|
2524
|
+
language,
|
|
2525
|
+
dictionaries: dictionaries$1
|
|
2526
|
+
})}`;
|
|
2527
|
+
reporter.debug(msg);
|
|
2528
|
+
}
|
|
2529
|
+
}
|
|
2530
|
+
function calcDependencies(config) {
|
|
2531
|
+
const { configFiles, dictionaryFiles } = extractDependencies(config);
|
|
2532
|
+
return { files: [...configFiles, ...dictionaryFiles] };
|
|
2533
|
+
}
|
|
2534
|
+
function reportConfigurationErrors(config, processFileOptions) {
|
|
2535
|
+
return reportImportErrors(extractImportErrors(config), processFileOptions);
|
|
2536
|
+
}
|
|
2537
|
+
function reportImportErrors(errors, processFileOptions) {
|
|
2538
|
+
const { reporter, configErrors } = processFileOptions;
|
|
2539
|
+
let count = 0;
|
|
2540
|
+
errors.forEach((ref) => {
|
|
2541
|
+
const key = ref.error.toString();
|
|
2542
|
+
if (configErrors.has(key)) return;
|
|
2543
|
+
configErrors.add(key);
|
|
2544
|
+
count += 1;
|
|
2545
|
+
reporter.error("Configuration", ref.error);
|
|
2546
|
+
});
|
|
2547
|
+
return count;
|
|
2548
|
+
}
|
|
2549
|
+
function reportSpellingResultConfigErrors(spellResult, processFileOptions) {
|
|
2550
|
+
const { reporter, configErrors } = processFileOptions;
|
|
2551
|
+
let count = reportImportErrors(spellResult.configErrors || [], processFileOptions);
|
|
2552
|
+
const dictionaryErrors = [...spellResult.dictionaryErrors || []];
|
|
2553
|
+
for (const [dictName, dictErrors] of dictionaryErrors) {
|
|
2554
|
+
const msg = `Dictionary Error with (${dictName})`;
|
|
2555
|
+
dictErrors.forEach((error) => {
|
|
2556
|
+
const key = msg + error.toString();
|
|
2557
|
+
if (configErrors.has(key)) return;
|
|
2558
|
+
configErrors.add(key);
|
|
2559
|
+
count += 1;
|
|
2560
|
+
reporter.error(msg, error);
|
|
2561
|
+
});
|
|
2562
|
+
}
|
|
2563
|
+
return count;
|
|
2564
|
+
}
|
|
2565
|
+
function countConfigErrors(configInfo, processFileOptions) {
|
|
2566
|
+
return reportConfigurationErrors(configInfo.config, processFileOptions);
|
|
2567
|
+
}
|
|
2568
|
+
|
|
2569
|
+
//#endregion
|
|
2570
|
+
//#region src/util/prefetch.ts
|
|
2571
|
+
function* prefetchIterable(iterable, size) {
|
|
2572
|
+
assert(size >= 0);
|
|
2573
|
+
const buffer = [];
|
|
2574
|
+
for (const value of iterable) {
|
|
2575
|
+
buffer.push(value);
|
|
2576
|
+
if (buffer.length >= size - 1) {
|
|
2577
|
+
const value$1 = buffer[0];
|
|
2578
|
+
buffer.shift();
|
|
2579
|
+
yield value$1;
|
|
2369
2580
|
}
|
|
2370
|
-
|
|
2371
|
-
|
|
2581
|
+
}
|
|
2582
|
+
yield* buffer;
|
|
2583
|
+
}
|
|
2584
|
+
|
|
2585
|
+
//#endregion
|
|
2586
|
+
//#region src/util/unitNumbers.ts
|
|
2587
|
+
const regexUnitNumber = /^((?:\d+(?:\.\d*)?)|(?:\.\d+))([a-z]*)$/i;
|
|
2588
|
+
const unitSizes = {
|
|
2589
|
+
"": 1,
|
|
2590
|
+
b: 1,
|
|
2591
|
+
k: 1024,
|
|
2592
|
+
kb: 1024,
|
|
2593
|
+
m: 1 << 20,
|
|
2594
|
+
mb: 1 << 20,
|
|
2595
|
+
g: 1 << 30,
|
|
2596
|
+
gb: 1 << 30
|
|
2597
|
+
};
|
|
2598
|
+
function parseUnitSize(size) {
|
|
2599
|
+
const match = size.match(regexUnitNumber);
|
|
2600
|
+
const digits = match?.[1] || "";
|
|
2601
|
+
const units = (match?.[2] || "").toLowerCase();
|
|
2602
|
+
if (!match) return {
|
|
2603
|
+
size,
|
|
2604
|
+
digits,
|
|
2605
|
+
units,
|
|
2606
|
+
error: "Invalid size."
|
|
2607
|
+
};
|
|
2608
|
+
if (!units || units in unitSizes) return {
|
|
2609
|
+
size,
|
|
2610
|
+
digits,
|
|
2611
|
+
units
|
|
2612
|
+
};
|
|
2613
|
+
return {
|
|
2614
|
+
size,
|
|
2615
|
+
digits,
|
|
2616
|
+
units,
|
|
2617
|
+
error: `Unknown units. Valid units are: ${Object.keys(unitSizes).filter(Boolean).join(", ").toUpperCase()}.`
|
|
2618
|
+
};
|
|
2619
|
+
}
|
|
2620
|
+
function validateUnitSize(size) {
|
|
2621
|
+
return parseUnitSize(size).error;
|
|
2622
|
+
}
|
|
2623
|
+
function sizeToNumber(size) {
|
|
2624
|
+
const p = parseUnitSize(size);
|
|
2625
|
+
if (p.error) return NaN;
|
|
2626
|
+
return Number.parseFloat(p.digits) * (unitSizes[p.units] || 1);
|
|
2627
|
+
}
|
|
2628
|
+
|
|
2629
|
+
//#endregion
|
|
2630
|
+
//#region src/lint/processFiles.ts
|
|
2631
|
+
const BATCH_FETCH_SIZE = 12;
|
|
2632
|
+
const BATCH_PROCESS_SIZE = 1;
|
|
2633
|
+
function prefetch(fileToProcess, cfg) {
|
|
2634
|
+
const { filename } = fileToProcess;
|
|
2635
|
+
if (isBinaryFile$1(filename, cfg.root)) return {
|
|
2636
|
+
...fileToProcess,
|
|
2637
|
+
result: Promise.resolve({
|
|
2638
|
+
skip: true,
|
|
2639
|
+
skipReason: "Binary file."
|
|
2640
|
+
})
|
|
2641
|
+
};
|
|
2642
|
+
const reportIssueOptions = extractReporterIssueOptions(cfg.config);
|
|
2643
|
+
async function fetch$1() {
|
|
2644
|
+
const getElapsedTimeMs = getTimeMeasurer();
|
|
2645
|
+
const cachedResult = await cfg.cache.getCachedLintResults(filename);
|
|
2646
|
+
if (cachedResult) {
|
|
2647
|
+
cfg.reporter.debug(`Filename: ${filename}, using cache`);
|
|
2648
|
+
return { fileResult: {
|
|
2649
|
+
...cachedResult,
|
|
2650
|
+
elapsedTimeMs: getElapsedTimeMs()
|
|
2651
|
+
} };
|
|
2372
2652
|
}
|
|
2373
|
-
const
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
configErrors: 0,
|
|
2379
|
-
elapsedTimeMs: 1,
|
|
2380
|
-
reportIssueOptions: void 0
|
|
2653
|
+
const uri = filenameToUri(filename, cfg.root).href;
|
|
2654
|
+
const checkResult = await shouldCheckDocument({ uri }, {}, cfg.config);
|
|
2655
|
+
if (!checkResult.shouldCheck) return {
|
|
2656
|
+
skip: true,
|
|
2657
|
+
skipReason: checkResult.reason || "Ignored by configuration."
|
|
2381
2658
|
};
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
reporter.emitProgressBegin(filename, index, fileCount ?? index);
|
|
2388
|
-
if (fetchResult?.skip) return {
|
|
2389
|
-
filename,
|
|
2390
|
-
fileNum: index,
|
|
2391
|
-
result: {
|
|
2392
|
-
...emptyResult,
|
|
2393
|
-
fileInfo: { filename },
|
|
2394
|
-
elapsedTimeMs: getElapsedTimeMs(),
|
|
2395
|
-
skippedReason: fetchResult.skipReason
|
|
2396
|
-
}
|
|
2397
|
-
};
|
|
2398
|
-
return {
|
|
2399
|
-
filename,
|
|
2400
|
-
fileNum: index,
|
|
2401
|
-
result: await processFile(filename, configInfo, cache, fetchResult)
|
|
2659
|
+
const maxFileSize = processMaxFileSize(cfg.maxFileSize ?? checkResult.settings.maxFileSize);
|
|
2660
|
+
if (maxFileSize) {
|
|
2661
|
+
if (await getFileSize(filename) > maxFileSize) return {
|
|
2662
|
+
skip: true,
|
|
2663
|
+
skipReason: `File exceeded max file size of ${maxFileSize.toLocaleString()}`
|
|
2402
2664
|
};
|
|
2403
2665
|
}
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2666
|
+
return {
|
|
2667
|
+
fileInfo: await readFileInfo(filename, void 0, true),
|
|
2668
|
+
reportIssueOptions
|
|
2669
|
+
};
|
|
2670
|
+
}
|
|
2671
|
+
const result = fetch$1().catch((e) => toApplicationError(e));
|
|
2672
|
+
return {
|
|
2673
|
+
...fileToProcess,
|
|
2674
|
+
result
|
|
2675
|
+
};
|
|
2676
|
+
}
|
|
2677
|
+
async function processFiles(files, options) {
|
|
2678
|
+
const status = runResult();
|
|
2679
|
+
const cache = await createCache(options.cacheSettings);
|
|
2680
|
+
const failFast = options.cfg.options.failFast ?? options.configInfo.config.failFast ?? false;
|
|
2681
|
+
const reporter = options.lintReporter;
|
|
2682
|
+
const prefetchConfig = {
|
|
2683
|
+
reporter,
|
|
2684
|
+
root: options.cfg.root,
|
|
2685
|
+
maxFileSize: options.cfg.maxFileSize,
|
|
2686
|
+
config: options.configInfo.config,
|
|
2687
|
+
cache
|
|
2688
|
+
};
|
|
2689
|
+
const processFileOptionsGeneral = {
|
|
2690
|
+
reporter,
|
|
2691
|
+
chalk: options.chalk,
|
|
2692
|
+
configInfo: options.configInfo,
|
|
2693
|
+
cfg: options.cfg,
|
|
2694
|
+
verboseLevel: options.verboseLevel,
|
|
2695
|
+
useColor: options.useColor,
|
|
2696
|
+
configErrors: options.configErrors,
|
|
2697
|
+
userSettings: options.configInfo.config
|
|
2698
|
+
};
|
|
2699
|
+
function* prefetchFiles(files$1) {
|
|
2700
|
+
yield* prefetchIterable(pipe(files$1, opMap$1((file) => prefetch(file, prefetchConfig))), BATCH_FETCH_SIZE);
|
|
2701
|
+
}
|
|
2702
|
+
async function* prefetchFilesAsync(files$1) {
|
|
2703
|
+
for await (const file of files$1) yield prefetch(file, prefetchConfig);
|
|
2704
|
+
}
|
|
2705
|
+
const emptyResult = {
|
|
2706
|
+
fileInfo: { filename: "" },
|
|
2707
|
+
issues: [],
|
|
2708
|
+
processed: false,
|
|
2709
|
+
errors: 0,
|
|
2710
|
+
configErrors: 0,
|
|
2711
|
+
elapsedTimeMs: 1,
|
|
2712
|
+
reportIssueOptions: void 0
|
|
2713
|
+
};
|
|
2714
|
+
async function processPrefetchFileResult(pf) {
|
|
2715
|
+
const { filename, sequence, sequenceSize, result: pFetchResult } = pf;
|
|
2716
|
+
const getElapsedTimeMs = getTimeMeasurer();
|
|
2717
|
+
const fetchResult = await pFetchResult;
|
|
2718
|
+
if (fetchResult instanceof Error) throw fetchResult;
|
|
2719
|
+
const fileNum = sequence + 1;
|
|
2720
|
+
reporter.emitProgressBegin(filename, fileNum, pf.sequenceSize ?? sequence);
|
|
2721
|
+
if (fetchResult?.skip) return {
|
|
2722
|
+
filename,
|
|
2723
|
+
sequence,
|
|
2724
|
+
sequenceSize,
|
|
2725
|
+
result: {
|
|
2726
|
+
...emptyResult,
|
|
2727
|
+
fileInfo: { filename },
|
|
2728
|
+
elapsedTimeMs: getElapsedTimeMs(),
|
|
2729
|
+
skippedReason: fetchResult.skipReason
|
|
2410
2730
|
}
|
|
2731
|
+
};
|
|
2732
|
+
return {
|
|
2733
|
+
filename,
|
|
2734
|
+
sequence,
|
|
2735
|
+
sequenceSize,
|
|
2736
|
+
result: await processFile(filename, cache, fetchResult, processFileOptionsGeneral)
|
|
2737
|
+
};
|
|
2738
|
+
}
|
|
2739
|
+
async function* loadAndProcessFiles() {
|
|
2740
|
+
if (isAsyncIterable(files)) {
|
|
2741
|
+
for await (const pf of prefetchFilesAsync(files)) yield processPrefetchFileResult(pf);
|
|
2742
|
+
return;
|
|
2411
2743
|
}
|
|
2412
|
-
|
|
2413
|
-
const
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
status.skippedFiles = (status.skippedFiles || 0) + (result.processed ? 0 : 1);
|
|
2417
|
-
const numIssues = reporter.emitProgressComplete(filename, fileNum, fileCount ?? fileNum, result);
|
|
2418
|
-
if (numIssues || result.errors) {
|
|
2419
|
-
status.filesWithIssues.add(relativeToCwd(filename, cfg.root));
|
|
2420
|
-
status.issues += numIssues;
|
|
2421
|
-
status.errors += result.errors;
|
|
2422
|
-
if (failFast) return status;
|
|
2744
|
+
if (BATCH_PROCESS_SIZE <= 1) {
|
|
2745
|
+
for (const pf of prefetchFiles(files)) {
|
|
2746
|
+
await pf.result;
|
|
2747
|
+
yield processPrefetchFileResult(pf);
|
|
2423
2748
|
}
|
|
2424
|
-
|
|
2749
|
+
return;
|
|
2425
2750
|
}
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
const
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2751
|
+
yield* pipe(prefetchIterable(pipe(prefetchFiles(files), opMap$1(async (pf) => processPrefetchFileResult(pf))), BATCH_PROCESS_SIZE));
|
|
2752
|
+
}
|
|
2753
|
+
for await (const fileP of loadAndProcessFiles()) {
|
|
2754
|
+
const { filename, sequence, sequenceSize, result } = fileP;
|
|
2755
|
+
status.files += 1;
|
|
2756
|
+
status.cachedFiles = (status.cachedFiles || 0) + (result.cached ? 1 : 0);
|
|
2757
|
+
status.skippedFiles = (status.skippedFiles || 0) + (result.processed ? 0 : 1);
|
|
2758
|
+
const fileNum = sequence + 1;
|
|
2759
|
+
const numIssues = reporter.emitProgressComplete(filename, fileNum, sequenceSize ?? fileNum, result);
|
|
2760
|
+
if (numIssues || result.errors) {
|
|
2761
|
+
status.filesWithIssues.add(relativeToCwd(filename, options.cfg.root));
|
|
2762
|
+
status.issues += numIssues;
|
|
2763
|
+
status.errors += result.errors;
|
|
2764
|
+
if (failFast) return status;
|
|
2765
|
+
}
|
|
2766
|
+
status.errors += result.configErrors;
|
|
2767
|
+
}
|
|
2768
|
+
await cache.reconcile();
|
|
2769
|
+
return status;
|
|
2770
|
+
}
|
|
2771
|
+
function processMaxFileSize(value) {
|
|
2772
|
+
if (!value) return void 0;
|
|
2773
|
+
if (typeof value === "number") return value;
|
|
2774
|
+
const num = sizeToNumber(value);
|
|
2775
|
+
if (Number.isNaN(num)) throw new ApplicationError(`Invalid max file size: "${value}"`);
|
|
2776
|
+
return num;
|
|
2777
|
+
}
|
|
2778
|
+
function runResult(init = {}) {
|
|
2779
|
+
const { files = 0, filesWithIssues = /* @__PURE__ */ new Set(), issues = 0, errors = 0, cachedFiles = 0 } = init;
|
|
2780
|
+
return {
|
|
2781
|
+
files,
|
|
2782
|
+
filesWithIssues,
|
|
2783
|
+
issues,
|
|
2784
|
+
errors,
|
|
2785
|
+
cachedFiles
|
|
2786
|
+
};
|
|
2787
|
+
}
|
|
2788
|
+
|
|
2789
|
+
//#endregion
|
|
2790
|
+
//#region \0@oxc-project+runtime@0.107.0/helpers/usingCtx.js
|
|
2791
|
+
function _usingCtx() {
|
|
2792
|
+
var r = "function" == typeof SuppressedError ? SuppressedError : function(r$1, e$1) {
|
|
2793
|
+
var n$1 = Error();
|
|
2794
|
+
return n$1.name = "SuppressedError", n$1.error = r$1, n$1.suppressed = e$1, n$1;
|
|
2795
|
+
}, e = {}, n = [];
|
|
2796
|
+
function using(r$1, e$1) {
|
|
2797
|
+
if (null != e$1) {
|
|
2798
|
+
if (Object(e$1) !== e$1) throw new TypeError("using declarations can only be used with objects, functions, null, or undefined.");
|
|
2799
|
+
if (r$1) var o = e$1[Symbol.asyncDispose || Symbol["for"]("Symbol.asyncDispose")];
|
|
2800
|
+
if (void 0 === o && (o = e$1[Symbol.dispose || Symbol["for"]("Symbol.dispose")], r$1)) var t = o;
|
|
2801
|
+
if ("function" != typeof o) throw new TypeError("Object is not disposable.");
|
|
2802
|
+
t && (o = function o$1() {
|
|
2803
|
+
try {
|
|
2804
|
+
t.call(e$1);
|
|
2805
|
+
} catch (r$2) {
|
|
2806
|
+
return Promise.reject(r$2);
|
|
2807
|
+
}
|
|
2808
|
+
}), n.push({
|
|
2809
|
+
v: e$1,
|
|
2810
|
+
d: o,
|
|
2811
|
+
a: r$1
|
|
2452
2812
|
});
|
|
2813
|
+
} else r$1 && n.push({
|
|
2814
|
+
d: e$1,
|
|
2815
|
+
a: r$1
|
|
2453
2816
|
});
|
|
2454
|
-
return
|
|
2455
|
-
}
|
|
2456
|
-
function countConfigErrors(configInfo) {
|
|
2457
|
-
return reportConfigurationErrors(configInfo.config);
|
|
2817
|
+
return e$1;
|
|
2458
2818
|
}
|
|
2819
|
+
return {
|
|
2820
|
+
e,
|
|
2821
|
+
u: using.bind(null, !1),
|
|
2822
|
+
a: using.bind(null, !0),
|
|
2823
|
+
d: function d() {
|
|
2824
|
+
var o, t = this.e, s = 0;
|
|
2825
|
+
function next() {
|
|
2826
|
+
for (; o = n.pop();) try {
|
|
2827
|
+
if (!o.a && 1 === s) return s = 0, n.push(o), Promise.resolve().then(next);
|
|
2828
|
+
if (o.d) {
|
|
2829
|
+
var r$1 = o.d.call(o.v);
|
|
2830
|
+
if (o.a) return s |= 2, Promise.resolve(r$1).then(next, err);
|
|
2831
|
+
} else s |= 1;
|
|
2832
|
+
} catch (r$2) {
|
|
2833
|
+
return err(r$2);
|
|
2834
|
+
}
|
|
2835
|
+
if (1 === s) return t !== e ? Promise.reject(t) : Promise.resolve();
|
|
2836
|
+
if (t !== e) throw t;
|
|
2837
|
+
}
|
|
2838
|
+
function err(n$1) {
|
|
2839
|
+
return t = t !== e ? new r(n$1, t) : n$1, next();
|
|
2840
|
+
}
|
|
2841
|
+
return next();
|
|
2842
|
+
}
|
|
2843
|
+
};
|
|
2844
|
+
}
|
|
2845
|
+
|
|
2846
|
+
//#endregion
|
|
2847
|
+
//#region src/lint/lint.ts
|
|
2848
|
+
const version = npmPackage.version;
|
|
2849
|
+
const { opFilterAsync } = operators;
|
|
2850
|
+
async function runLint(cfg) {
|
|
2851
|
+
const reporter = new LintReporter(cfg.reporter, cfg.options);
|
|
2852
|
+
const configErrors = /* @__PURE__ */ new Set();
|
|
2853
|
+
const verboseLevel = calcVerboseLevel(cfg.options);
|
|
2854
|
+
const useColor = cfg.options.color ?? true;
|
|
2855
|
+
if (verboseLevel >= 1 && cfg.options.showPerfSummary) enablePerformanceMeasurements();
|
|
2856
|
+
const timer = getTimeMeasurer();
|
|
2857
|
+
const logDictRequests = truthy(getEnvironmentVariable("CSPELL_ENABLE_DICTIONARY_LOGGING"));
|
|
2858
|
+
if (logDictRequests) dictionaryCacheEnableLogging(true);
|
|
2859
|
+
const lintResult = await run();
|
|
2860
|
+
if (logDictRequests) await writeDictionaryLog();
|
|
2861
|
+
await reporter.result(lintResult);
|
|
2862
|
+
const elapsed = timer();
|
|
2863
|
+
if (getFeatureFlags().getFlag("timer") || verboseLevel >= 1 || cfg.options.showPerfSummary) console.error(`Elapsed Time: ${elapsed.toFixed(2)}ms`);
|
|
2864
|
+
return lintResult;
|
|
2459
2865
|
async function run() {
|
|
2460
|
-
if (cfg.options.root) setEnvironmentVariable(ENV_CSPELL_GLOB_ROOT, cfg.root);
|
|
2461
|
-
const configInfo = await readConfig(cfg.configFile, cfg.root, cfg.options.stopConfigSearchAt);
|
|
2462
|
-
if (cfg.options.defaultConfiguration !== void 0) configInfo.config.loadDefaultConfiguration = cfg.options.defaultConfiguration;
|
|
2463
|
-
configInfo.config = mergeSettings(configInfo.config, cfg.cspellSettingsFromCliOptions);
|
|
2464
|
-
const reporterConfig = clean({
|
|
2465
|
-
maxNumberOfProblems: configInfo.config.maxNumberOfProblems,
|
|
2466
|
-
maxDuplicateProblems: configInfo.config.maxDuplicateProblems,
|
|
2467
|
-
minWordLength: configInfo.config.minWordLength,
|
|
2468
|
-
...cfg.options,
|
|
2469
|
-
console
|
|
2470
|
-
});
|
|
2471
|
-
const reporters = cfg.options.reporter ?? configInfo.config.reporters;
|
|
2472
|
-
reporter.config = reporterConfig;
|
|
2473
|
-
await reporter.loadReportersAndFinalize(reporters);
|
|
2474
|
-
setLogger(getLoggerFromReporter(reporter, useColor));
|
|
2475
|
-
const globInfo = await determineGlobs(configInfo, cfg);
|
|
2476
|
-
const { fileGlobs, excludeGlobs } = globInfo;
|
|
2477
|
-
const hasFileLists = !!cfg.fileLists.length;
|
|
2478
|
-
if (!fileGlobs.length && !hasFileLists && !cfg.files?.length) return runResult();
|
|
2479
|
-
header(fileGlobs, excludeGlobs);
|
|
2480
|
-
checkGlobs(fileGlobs, reporter);
|
|
2481
|
-
if (verboseLevel > 1) reporter.info(`Config Files Found:\n ${relativeToCwd(configInfo.source)}\n`, MessageTypes.Info);
|
|
2482
|
-
const configErrors$1 = await countConfigErrors(configInfo);
|
|
2483
|
-
if (configErrors$1 && cfg.options.exitCode !== false && !cfg.options.continueOnError) return runResult({ errors: configErrors$1 });
|
|
2484
|
-
const { root } = cfg;
|
|
2485
2866
|
try {
|
|
2486
|
-
|
|
2867
|
+
var _usingCtx$1 = _usingCtx();
|
|
2868
|
+
const _ = _usingCtx$1.u(measurePerf("runLint"));
|
|
2869
|
+
if (cfg.options.root) setEnvironmentVariable(ENV_CSPELL_GLOB_ROOT, cfg.root);
|
|
2870
|
+
const configInfo = await readConfig(cfg.configFile, cfg.root, cfg.options.stopConfigSearchAt);
|
|
2871
|
+
const processFileOptions = getProcessFileOptions(configInfo);
|
|
2872
|
+
if (cfg.options.defaultConfiguration !== void 0) configInfo.config.loadDefaultConfiguration = cfg.options.defaultConfiguration;
|
|
2873
|
+
configInfo.config = mergeSettings(configInfo.config, cfg.cspellSettingsFromCliOptions);
|
|
2874
|
+
const reporterConfig = clean({
|
|
2875
|
+
maxNumberOfProblems: configInfo.config.maxNumberOfProblems,
|
|
2876
|
+
maxDuplicateProblems: configInfo.config.maxDuplicateProblems,
|
|
2877
|
+
minWordLength: configInfo.config.minWordLength,
|
|
2487
2878
|
...cfg.options,
|
|
2488
|
-
|
|
2489
|
-
}
|
|
2490
|
-
const
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
const
|
|
2495
|
-
|
|
2496
|
-
|
|
2879
|
+
console
|
|
2880
|
+
});
|
|
2881
|
+
const reporters = cfg.options.reporter ?? configInfo.config.reporters;
|
|
2882
|
+
reporter.config = reporterConfig;
|
|
2883
|
+
await reporter.loadReportersAndFinalize(reporters);
|
|
2884
|
+
setLogger(getLoggerFromReporter(reporter, useColor));
|
|
2885
|
+
const globInfo = await determineGlobs(configInfo, cfg);
|
|
2886
|
+
const { fileGlobs, excludeGlobs } = globInfo;
|
|
2887
|
+
const hasFileLists = !!cfg.fileLists.length;
|
|
2888
|
+
if (!fileGlobs.length && !hasFileLists && !cfg.files?.length) return runResult();
|
|
2889
|
+
header(fileGlobs, excludeGlobs);
|
|
2890
|
+
checkGlobs(fileGlobs, reporter);
|
|
2891
|
+
if (verboseLevel > 1) reporter.info(`Config Files Found:\n ${relativeToCwd(configInfo.source)}\n`, MessageTypes$1.Info);
|
|
2892
|
+
const configErrorCount = countConfigErrors(configInfo, processFileOptions);
|
|
2893
|
+
if (configErrorCount && cfg.options.exitCode !== false && !cfg.options.continueOnError) return runResult({ errors: configErrorCount });
|
|
2894
|
+
const { root } = cfg;
|
|
2895
|
+
try {
|
|
2896
|
+
const cacheSettings = await calcCacheSettings(configInfo.config, {
|
|
2897
|
+
...cfg.options,
|
|
2898
|
+
version
|
|
2899
|
+
}, root);
|
|
2900
|
+
const result = await processFiles(await determineFilesToCheck(configInfo, cfg, reporter, globInfo), {
|
|
2901
|
+
chalk,
|
|
2902
|
+
configInfo,
|
|
2903
|
+
cfg,
|
|
2904
|
+
verboseLevel,
|
|
2905
|
+
useColor,
|
|
2906
|
+
configErrors,
|
|
2907
|
+
userSettings: configInfo.config,
|
|
2908
|
+
lintReporter: reporter,
|
|
2909
|
+
cacheSettings
|
|
2910
|
+
});
|
|
2911
|
+
if (configErrorCount && cfg.options.exitCode !== false) result.errors ||= configErrorCount;
|
|
2912
|
+
return result;
|
|
2913
|
+
} catch (e) {
|
|
2914
|
+
const err = toApplicationError(e);
|
|
2915
|
+
reporter.error("Linter", err);
|
|
2916
|
+
return runResult({ errors: 1 });
|
|
2917
|
+
}
|
|
2918
|
+
} catch (_) {
|
|
2919
|
+
_usingCtx$1.e = _;
|
|
2920
|
+
} finally {
|
|
2921
|
+
_usingCtx$1.d();
|
|
2497
2922
|
}
|
|
2498
2923
|
}
|
|
2499
2924
|
function header(files, cliExcludes) {
|
|
@@ -2509,7 +2934,19 @@ async function runLint(cfg) {
|
|
|
2509
2934
|
files: ${formattedFiles}
|
|
2510
2935
|
wordsOnly: ${yesNo(!!cfg.options.wordsOnly)}
|
|
2511
2936
|
unique: ${yesNo(!!cfg.options.unique)}
|
|
2512
|
-
`, MessageTypes.Info);
|
|
2937
|
+
`, MessageTypes$1.Info);
|
|
2938
|
+
}
|
|
2939
|
+
function getProcessFileOptions(configInfo) {
|
|
2940
|
+
return {
|
|
2941
|
+
reporter,
|
|
2942
|
+
chalk,
|
|
2943
|
+
configInfo,
|
|
2944
|
+
cfg,
|
|
2945
|
+
verboseLevel,
|
|
2946
|
+
useColor,
|
|
2947
|
+
configErrors,
|
|
2948
|
+
userSettings: configInfo.config
|
|
2949
|
+
};
|
|
2513
2950
|
}
|
|
2514
2951
|
}
|
|
2515
2952
|
function checkGlobs(globs, reporter) {
|
|
@@ -2531,6 +2968,22 @@ async function determineGlobs(configInfo, cfg) {
|
|
|
2531
2968
|
normalizedExcludes
|
|
2532
2969
|
};
|
|
2533
2970
|
}
|
|
2971
|
+
async function* filesToProcessAsync(filenames) {
|
|
2972
|
+
let sequence = 0;
|
|
2973
|
+
for await (const filename of filenames) yield {
|
|
2974
|
+
filename,
|
|
2975
|
+
sequence: sequence++
|
|
2976
|
+
};
|
|
2977
|
+
}
|
|
2978
|
+
function filesToProcess(files) {
|
|
2979
|
+
const filenames = [...files];
|
|
2980
|
+
const sequenceSize = filenames.length;
|
|
2981
|
+
return filenames.map((filename, sequence) => ({
|
|
2982
|
+
filename,
|
|
2983
|
+
sequence,
|
|
2984
|
+
sequenceSize
|
|
2985
|
+
}));
|
|
2986
|
+
}
|
|
2534
2987
|
async function determineFilesToCheck(configInfo, cfg, reporter, globInfo) {
|
|
2535
2988
|
async function _determineFilesToCheck() {
|
|
2536
2989
|
const { fileLists } = cfg;
|
|
@@ -2541,7 +2994,7 @@ async function determineFilesToCheck(configInfo, cfg, reporter, globInfo) {
|
|
|
2541
2994
|
const globsToExclude = globsToExcludeRaw.filter((g) => !globPattern(g).startsWith("!"));
|
|
2542
2995
|
if (globsToExclude.length !== globsToExcludeRaw.length) {
|
|
2543
2996
|
const msg = `Negative glob exclusions are not supported: ${globsToExcludeRaw.map((g) => globPattern(g)).filter((g) => g.startsWith("!")).join(", ")}`;
|
|
2544
|
-
reporter.info(msg, MessageTypes.Warning);
|
|
2997
|
+
reporter.info(msg, MessageTypes$1.Warning);
|
|
2545
2998
|
}
|
|
2546
2999
|
const globMatcher = buildGlobMatcher(globsToExclude, root, true);
|
|
2547
3000
|
const globOptions = {
|
|
@@ -2558,7 +3011,7 @@ async function determineFilesToCheck(configInfo, cfg, reporter, globInfo) {
|
|
|
2558
3011
|
const cliFiles = cfg.options.mustFindFiles ? rawCliFiles : rawCliFiles && pipeAsync(rawCliFiles, opFilterAsync(isFile));
|
|
2559
3012
|
const foundFiles = hasFileLists ? concatAsyncIterables(cliFiles, await useFileLists(fileLists, includeFilter)) : cliFiles || await findFiles(fileGlobs, globOptions);
|
|
2560
3013
|
const filtered = gitIgnore ? await gitIgnore.filterOutIgnored(foundFiles) : foundFiles;
|
|
2561
|
-
return isAsyncIterable(filtered) ? pipeAsync(filtered, opFilterExcludedFiles) :
|
|
3014
|
+
return isAsyncIterable(filtered) ? pipeAsync(filtered, opFilterExcludedFiles, filesToProcessAsync) : filesToProcess(pipe(filtered, opFilterExcludedFiles));
|
|
2562
3015
|
}
|
|
2563
3016
|
function isExcluded(filename, globMatcherExclude) {
|
|
2564
3017
|
if (isBinaryFile(toFileURL(filename))) return true;
|
|
@@ -2567,13 +3020,13 @@ async function determineFilesToCheck(configInfo, cfg, reporter, globInfo) {
|
|
|
2567
3020
|
const r = globMatcherExclude.matchEx(absFilename);
|
|
2568
3021
|
if (r.matched) {
|
|
2569
3022
|
const { glob: glob$2, source } = extractGlobSource(r.pattern);
|
|
2570
|
-
if (calcVerboseLevel(cfg.options) > 1) reporter.info(`Excluded File: ${path$1.relative(root, absFilename)}; Excluded by ${glob$2} from ${source}`, MessageTypes.Info);
|
|
3023
|
+
if (calcVerboseLevel(cfg.options) > 1) reporter.info(`Excluded File: ${path$1.relative(root, absFilename)}; Excluded by ${glob$2} from ${source}`, MessageTypes$1.Info);
|
|
2571
3024
|
}
|
|
2572
3025
|
return r.matched;
|
|
2573
3026
|
}
|
|
2574
3027
|
function filterOutExcludedFilesFn(globMatcherExclude) {
|
|
2575
3028
|
const excludeInfo = globMatcherExclude.patterns.map(extractGlobSource).map(({ glob: glob$2, source }) => `Glob: ${glob$2} from ${source}`).filter(uniqueFn());
|
|
2576
|
-
if (calcVerboseLevel(cfg.options) > 1) reporter.info(`Exclusion Globs: \n ${excludeInfo.join("\n ")}\n`, MessageTypes.Info);
|
|
3029
|
+
if (calcVerboseLevel(cfg.options) > 1) reporter.info(`Exclusion Globs: \n ${excludeInfo.join("\n ")}\n`, MessageTypes$1.Info);
|
|
2577
3030
|
return (filename) => !isExcluded(filename, globMatcherExclude);
|
|
2578
3031
|
}
|
|
2579
3032
|
return _determineFilesToCheck();
|
|
@@ -2585,16 +3038,6 @@ function extractGlobSource(g) {
|
|
|
2585
3038
|
source
|
|
2586
3039
|
};
|
|
2587
3040
|
}
|
|
2588
|
-
function runResult(init = {}) {
|
|
2589
|
-
const { files = 0, filesWithIssues = /* @__PURE__ */ new Set(), issues = 0, errors = 0, cachedFiles = 0 } = init;
|
|
2590
|
-
return {
|
|
2591
|
-
files,
|
|
2592
|
-
filesWithIssues,
|
|
2593
|
-
issues,
|
|
2594
|
-
errors,
|
|
2595
|
-
cachedFiles
|
|
2596
|
-
};
|
|
2597
|
-
}
|
|
2598
3041
|
function yesNo(value) {
|
|
2599
3042
|
return value ? "Yes" : "No";
|
|
2600
3043
|
}
|
|
@@ -2653,30 +3096,15 @@ async function* concatAsyncIterables(...iterables) {
|
|
|
2653
3096
|
}
|
|
2654
3097
|
async function writeDictionaryLog() {
|
|
2655
3098
|
const fields = (getEnvironmentVariable("CSPELL_ENABLE_DICTIONARY_LOG_FIELDS") || "time, word, value").split(",").map((f) => f.trim());
|
|
2656
|
-
const data = fields.join(", ") + "\n" +
|
|
3099
|
+
const data = fields.join(", ") + "\n" + dictionaryCacheGetLog().filter((d) => d.method === "has").map((d) => fields.map((f) => f in d ? `${d[f]}` : "").join(", ")).join("\n") + "\n";
|
|
2657
3100
|
await writeFileOrStream(getEnvironmentVariable("CSPELL_ENABLE_DICTIONARY_LOG_FILE") || "cspell-dictionary-log.csv", data);
|
|
2658
3101
|
}
|
|
2659
3102
|
function globPattern(g) {
|
|
2660
3103
|
return typeof g === "string" ? g : g.glob;
|
|
2661
3104
|
}
|
|
2662
|
-
var LinterError = class extends Error {
|
|
2663
|
-
constructor(message) {
|
|
2664
|
-
super(message);
|
|
2665
|
-
}
|
|
2666
|
-
toString() {
|
|
2667
|
-
return this.message;
|
|
2668
|
-
}
|
|
2669
|
-
};
|
|
2670
3105
|
function calcVerboseLevel(options) {
|
|
2671
3106
|
return options.verboseLevel ?? (options.verbose ? 1 : 0);
|
|
2672
3107
|
}
|
|
2673
|
-
function processMaxFileSize(value) {
|
|
2674
|
-
if (!value) return void 0;
|
|
2675
|
-
if (typeof value === "number") return value;
|
|
2676
|
-
const num = sizeToNumber(value);
|
|
2677
|
-
if (Number.isNaN(num)) throw new ApplicationError(`Invalid max file size: "${value}"`);
|
|
2678
|
-
return num;
|
|
2679
|
-
}
|
|
2680
3108
|
|
|
2681
3109
|
//#endregion
|
|
2682
3110
|
//#region src/lint/LintRequest.ts
|
|
@@ -3010,5 +3438,5 @@ function parseApplicationFeatureFlags(flags) {
|
|
|
3010
3438
|
}
|
|
3011
3439
|
|
|
3012
3440
|
//#endregion
|
|
3013
|
-
export {
|
|
3014
|
-
//# sourceMappingURL=application-
|
|
3441
|
+
export { CheckFailed as C, ApplicationError as S, padLeft as _, parseApplicationFeatureFlags as a, pruneAnsiTextStart as b, listDictionaries as c, validateUnitSize as d, unindent as f, tableToLines as g, getReporter as h, lint as i, ReportChoicesAll as l, npmPackage as m, checkText as n, suggestions as o, DEFAULT_CACHE_LOCATION as p, createInit as r, trace as s, IncludeExcludeFlag as t, cvtLinterCliCommandOptionsToLinterCliOptions as u, padWidth as v, console as w, width as x, pruneAnsiTextEnd as y };
|
|
3442
|
+
//# sourceMappingURL=application-DaQrXF9X.js.map
|