cspell 9.0.1 → 9.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -59
- package/dist/esm/app.mjs +4 -15
- package/dist/esm/application.d.mts +3 -1
- package/dist/esm/application.mjs +14 -6
- package/dist/esm/cli-reporter.js +2 -1
- package/dist/esm/commandConfig.d.ts +3 -0
- package/dist/esm/commandConfig.js +18 -0
- package/dist/esm/commandDictionaries.d.ts +3 -0
- package/dist/esm/commandDictionaries.js +40 -0
- package/dist/esm/commandHelpers.d.ts +18 -0
- package/dist/esm/commandHelpers.js +30 -0
- package/dist/esm/commandInit.d.ts +3 -0
- package/dist/esm/commandInit.js +25 -0
- package/dist/esm/commandLint.js +13 -26
- package/dist/esm/commandTrace.js +2 -0
- package/dist/esm/config/adjustConfig.d.ts +7 -0
- package/dist/esm/config/adjustConfig.js +137 -0
- package/dist/esm/config/config.d.ts +5 -0
- package/dist/esm/config/config.js +18 -0
- package/dist/esm/config/configInit.d.ts +3 -0
- package/dist/esm/config/configInit.js +104 -0
- package/dist/esm/config/constants.d.ts +17 -0
- package/dist/esm/config/constants.js +23 -0
- package/dist/esm/config/index.d.ts +3 -0
- package/dist/esm/config/index.js +2 -0
- package/dist/esm/config/options.d.ts +62 -0
- package/dist/esm/config/options.js +2 -0
- package/dist/esm/config/updateConfig.d.ts +3 -0
- package/dist/esm/config/updateConfig.js +2 -0
- package/dist/esm/dictionaries/index.d.ts +3 -0
- package/dist/esm/dictionaries/index.js +2 -0
- package/dist/esm/dictionaries/listDictionaries.d.ts +33 -0
- package/dist/esm/dictionaries/listDictionaries.js +131 -0
- package/dist/esm/emitters/dictionaryListEmitter.d.ts +19 -0
- package/dist/esm/emitters/dictionaryListEmitter.js +82 -0
- package/dist/esm/emitters/helpers.d.ts +14 -0
- package/dist/esm/emitters/helpers.js +67 -0
- package/dist/esm/emitters/traceEmitter.d.ts +1 -10
- package/dist/esm/emitters/traceEmitter.js +1 -69
- package/dist/esm/lint/LintRequest.d.ts +3 -2
- package/dist/esm/lint/LintRequest.js +41 -5
- package/dist/esm/lint/index.d.ts +1 -1
- package/dist/esm/lint/index.js +1 -1
- package/dist/esm/lint/lint.js +28 -66
- package/dist/esm/options.d.ts +101 -4
- package/dist/esm/options.js +1 -0
- package/dist/esm/pkgInfo.d.ts +1 -1
- package/dist/esm/pkgInfo.js +1 -1
- package/dist/esm/util/InMemoryReporter.d.ts +10 -7
- package/dist/esm/util/InMemoryReporter.js +20 -13
- package/dist/esm/util/LintFileResult.d.ts +14 -0
- package/dist/esm/util/LintFileResult.js +2 -0
- package/dist/esm/util/cache/CSpellLintResultCache.d.ts +3 -3
- package/dist/esm/util/cache/DiskCache.d.ts +4 -4
- package/dist/esm/util/configFileHelper.d.ts +1 -1
- package/dist/esm/util/configFileHelper.js +2 -2
- package/dist/esm/util/extractContext.d.ts +5 -0
- package/dist/esm/util/extractContext.js +75 -0
- package/dist/esm/util/fileHelper.d.ts +2 -11
- package/dist/esm/util/fileHelper.js +9 -1
- package/dist/esm/util/pad.d.ts +16 -0
- package/dist/esm/util/pad.js +61 -1
- package/dist/esm/util/reporters.d.ts +21 -5
- package/dist/esm/util/reporters.js +178 -31
- package/dist/esm/util/table.d.ts +31 -4
- package/dist/esm/util/table.js +76 -16
- package/dist/esm/util/util.d.ts +5 -0
- package/dist/esm/util/util.js +5 -0
- package/package.json +16 -15
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DictionaryPathFormat } from './DictionaryPathFormat.js';
|
|
2
|
+
export interface PathInterface {
|
|
3
|
+
relative(from: string, to: string): string;
|
|
4
|
+
basename(path: string): string;
|
|
5
|
+
sep: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function trimMidPath(s: string, w: number, sep: string): string;
|
|
8
|
+
export declare function trimMid(s: string, w: number): string;
|
|
9
|
+
export declare function formatDictionaryLocation(dictSource: string, maxWidth: number, { cwd, dictionaryPathFormat: format, iPath, }: {
|
|
10
|
+
cwd: string;
|
|
11
|
+
dictionaryPathFormat: DictionaryPathFormat;
|
|
12
|
+
iPath: PathInterface;
|
|
13
|
+
}): string;
|
|
14
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export function trimMidPath(s, w, sep) {
|
|
2
|
+
if (s.length <= w)
|
|
3
|
+
return s;
|
|
4
|
+
const parts = s.split(sep);
|
|
5
|
+
if (parts[parts.length - 1].length > w)
|
|
6
|
+
return trimMid(s, w);
|
|
7
|
+
function join(left, right) {
|
|
8
|
+
// if (left === right) return parts.join(sep);
|
|
9
|
+
return [...parts.slice(0, left), '…', ...parts.slice(right)].join(sep);
|
|
10
|
+
}
|
|
11
|
+
let left = 0, right = parts.length, last = '';
|
|
12
|
+
for (let i = 0; i < parts.length; ++i) {
|
|
13
|
+
const incLeft = i & 1 ? 1 : 0;
|
|
14
|
+
const incRight = incLeft ? 0 : -1;
|
|
15
|
+
const next = join(left + incLeft, right + incRight);
|
|
16
|
+
if (next.length > w)
|
|
17
|
+
break;
|
|
18
|
+
left += incLeft;
|
|
19
|
+
right += incRight;
|
|
20
|
+
last = next;
|
|
21
|
+
}
|
|
22
|
+
for (let i = left + 1; i < right; ++i) {
|
|
23
|
+
const next = join(i, right);
|
|
24
|
+
if (next.length > w)
|
|
25
|
+
break;
|
|
26
|
+
last = next;
|
|
27
|
+
}
|
|
28
|
+
for (let i = right - 1; i > left; --i) {
|
|
29
|
+
const next = join(left, i);
|
|
30
|
+
if (next.length > w)
|
|
31
|
+
break;
|
|
32
|
+
last = next;
|
|
33
|
+
}
|
|
34
|
+
return last || trimMid(s, w);
|
|
35
|
+
}
|
|
36
|
+
export function trimMid(s, w) {
|
|
37
|
+
s = s.trim();
|
|
38
|
+
if (s.length <= w) {
|
|
39
|
+
return s;
|
|
40
|
+
}
|
|
41
|
+
const l = Math.floor((w - 1) / 2);
|
|
42
|
+
const r = Math.ceil((w - 1) / 2);
|
|
43
|
+
return s.slice(0, l) + '…' + s.slice(-r);
|
|
44
|
+
}
|
|
45
|
+
export function formatDictionaryLocation(dictSource, maxWidth, { cwd, dictionaryPathFormat: format, iPath, }) {
|
|
46
|
+
let relPath = cwd ? iPath.relative(cwd, dictSource) : dictSource;
|
|
47
|
+
const idxNodeModule = relPath.lastIndexOf('node_modules');
|
|
48
|
+
const isNodeModule = idxNodeModule >= 0;
|
|
49
|
+
if (format === 'hide')
|
|
50
|
+
return '';
|
|
51
|
+
if (format === 'short') {
|
|
52
|
+
const prefix = isNodeModule
|
|
53
|
+
? '[node_modules]/'
|
|
54
|
+
: relPath.startsWith('..' + iPath.sep + '..')
|
|
55
|
+
? '…/'
|
|
56
|
+
: relPath.startsWith('..' + iPath.sep)
|
|
57
|
+
? '../'
|
|
58
|
+
: '';
|
|
59
|
+
return prefix + iPath.basename(dictSource);
|
|
60
|
+
}
|
|
61
|
+
if (format === 'full')
|
|
62
|
+
return dictSource;
|
|
63
|
+
relPath = isNodeModule ? relPath.slice(idxNodeModule) : relPath;
|
|
64
|
+
const usePath = relPath.length < dictSource.length ? relPath : dictSource;
|
|
65
|
+
return trimMidPath(usePath, maxWidth, iPath.sep);
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import type { TraceResult } from '../application.mjs';
|
|
2
2
|
import type { DictionaryPathFormat } from './DictionaryPathFormat.js';
|
|
3
|
-
|
|
4
|
-
relative(from: string, to: string): string;
|
|
5
|
-
basename(path: string): string;
|
|
6
|
-
sep: string;
|
|
7
|
-
}
|
|
3
|
+
import { type PathInterface } from './helpers.js';
|
|
8
4
|
export interface EmitTraceOptions {
|
|
9
5
|
/** current working directory */
|
|
10
6
|
cwd: string;
|
|
@@ -20,9 +16,4 @@ export declare function calcTraceResultsReport(word: string, found: boolean, res
|
|
|
20
16
|
table: string;
|
|
21
17
|
errors: string;
|
|
22
18
|
};
|
|
23
|
-
declare function trimMidPath(s: string, w: number, sep: string): string;
|
|
24
|
-
export declare const __testing__: {
|
|
25
|
-
trimMidPath: typeof trimMidPath;
|
|
26
|
-
};
|
|
27
|
-
export {};
|
|
28
19
|
//# sourceMappingURL=traceEmitter.d.ts.map
|
|
@@ -2,6 +2,7 @@ import * as iPath from 'node:path';
|
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import { console } from '../console.js';
|
|
4
4
|
import { tableToLines } from '../util/table.js';
|
|
5
|
+
import { formatDictionaryLocation } from './helpers.js';
|
|
5
6
|
const maxWidth = 120;
|
|
6
7
|
const colWidthDictionaryName = 20;
|
|
7
8
|
export function emitTraceResults(word, found, results, options) {
|
|
@@ -66,15 +67,6 @@ function emitErrors(results) {
|
|
|
66
67
|
return chalk.bold(r.dictName) + '\n\t' + chalk.red(errors);
|
|
67
68
|
});
|
|
68
69
|
}
|
|
69
|
-
function trimMid(s, w) {
|
|
70
|
-
s = s.trim();
|
|
71
|
-
if (s.length <= w) {
|
|
72
|
-
return s;
|
|
73
|
-
}
|
|
74
|
-
const l = Math.floor((w - 3) / 2);
|
|
75
|
-
const r = Math.ceil((w - 3) / 2);
|
|
76
|
-
return s.slice(0, l) + '...' + s.slice(-r);
|
|
77
|
-
}
|
|
78
70
|
function calcFoundChar(r) {
|
|
79
71
|
const errors = r.errors?.map((e) => e.message)?.join('\n\t') || '';
|
|
80
72
|
let color = chalk.dim;
|
|
@@ -89,67 +81,7 @@ function calcFoundChar(r) {
|
|
|
89
81
|
char = errors ? 'X' : char;
|
|
90
82
|
return color(char);
|
|
91
83
|
}
|
|
92
|
-
function formatDictionaryLocation(dictSource, maxWidth, { cwd, dictionaryPathFormat: format, iPath, }) {
|
|
93
|
-
let relPath = cwd ? iPath.relative(cwd, dictSource) : dictSource;
|
|
94
|
-
const idxNodeModule = relPath.lastIndexOf('node_modules');
|
|
95
|
-
const isNodeModule = idxNodeModule >= 0;
|
|
96
|
-
if (format === 'hide')
|
|
97
|
-
return '';
|
|
98
|
-
if (format === 'short') {
|
|
99
|
-
const prefix = isNodeModule
|
|
100
|
-
? '[node_modules]/'
|
|
101
|
-
: relPath.startsWith('..' + iPath.sep + '..')
|
|
102
|
-
? '.../'
|
|
103
|
-
: relPath.startsWith('..' + iPath.sep)
|
|
104
|
-
? '../'
|
|
105
|
-
: '';
|
|
106
|
-
return prefix + iPath.basename(dictSource);
|
|
107
|
-
}
|
|
108
|
-
if (format === 'full')
|
|
109
|
-
return dictSource;
|
|
110
|
-
relPath = isNodeModule ? relPath.slice(idxNodeModule) : relPath;
|
|
111
|
-
const usePath = relPath.length < dictSource.length ? relPath : dictSource;
|
|
112
|
-
return trimMidPath(usePath, maxWidth, iPath.sep);
|
|
113
|
-
}
|
|
114
84
|
function colorize(fn) {
|
|
115
85
|
return (s) => (s ? fn(s) : '');
|
|
116
86
|
}
|
|
117
|
-
function trimMidPath(s, w, sep) {
|
|
118
|
-
if (s.length <= w)
|
|
119
|
-
return s;
|
|
120
|
-
const parts = s.split(sep);
|
|
121
|
-
if (parts[parts.length - 1].length > w)
|
|
122
|
-
return trimMid(s, w);
|
|
123
|
-
function join(left, right) {
|
|
124
|
-
// if (left === right) return parts.join(sep);
|
|
125
|
-
return [...parts.slice(0, left), '...', ...parts.slice(right)].join(sep);
|
|
126
|
-
}
|
|
127
|
-
let left = 0, right = parts.length, last = '';
|
|
128
|
-
for (let i = 0; i < parts.length; ++i) {
|
|
129
|
-
const incLeft = i & 1 ? 1 : 0;
|
|
130
|
-
const incRight = incLeft ? 0 : -1;
|
|
131
|
-
const next = join(left + incLeft, right + incRight);
|
|
132
|
-
if (next.length > w)
|
|
133
|
-
break;
|
|
134
|
-
left += incLeft;
|
|
135
|
-
right += incRight;
|
|
136
|
-
last = next;
|
|
137
|
-
}
|
|
138
|
-
for (let i = left + 1; i < right; ++i) {
|
|
139
|
-
const next = join(i, right);
|
|
140
|
-
if (next.length > w)
|
|
141
|
-
break;
|
|
142
|
-
last = next;
|
|
143
|
-
}
|
|
144
|
-
for (let i = right - 1; i > left; --i) {
|
|
145
|
-
const next = join(left, i);
|
|
146
|
-
if (next.length > w)
|
|
147
|
-
break;
|
|
148
|
-
last = next;
|
|
149
|
-
}
|
|
150
|
-
return last || trimMid(s, w);
|
|
151
|
-
}
|
|
152
|
-
export const __testing__ = {
|
|
153
|
-
trimMidPath,
|
|
154
|
-
};
|
|
155
87
|
//# sourceMappingURL=traceEmitter.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type CSpellUserSettings, type UnknownWordsConfiguration } from '@cspell/cspell-types';
|
|
2
2
|
import type { CSpellConfigFile, LinterCliOptions, LinterOptions } from '../options.js';
|
|
3
3
|
import type { GlobSrcInfo } from '../util/glob.js';
|
|
4
4
|
import type { FinalizedReporter } from '../util/reporters.js';
|
|
@@ -10,7 +10,6 @@ export declare class LintRequest {
|
|
|
10
10
|
readonly fileGlobs: string[];
|
|
11
11
|
readonly options: LinterCliOptions & Deprecated;
|
|
12
12
|
readonly reporter: FinalizedReporter;
|
|
13
|
-
readonly uniqueFilter: (issue: Issue) => boolean;
|
|
14
13
|
readonly locale: string;
|
|
15
14
|
readonly configFile: string | CSpellConfigFile | undefined;
|
|
16
15
|
readonly excludes: GlobSrcInfo[];
|
|
@@ -19,7 +18,9 @@ export declare class LintRequest {
|
|
|
19
18
|
readonly enableGlobDot: boolean | undefined;
|
|
20
19
|
readonly fileLists: string[];
|
|
21
20
|
readonly files: string[] | undefined;
|
|
21
|
+
readonly cspellSettingsFromCliOptions: CSpellUserSettings;
|
|
22
22
|
constructor(fileGlobs: string[], options: LinterCliOptions & Deprecated, reporter: FinalizedReporter);
|
|
23
23
|
}
|
|
24
|
+
export declare function extractUnknownWordsConfig(options: LinterCliOptions): UnknownWordsConfiguration;
|
|
24
25
|
export {};
|
|
25
26
|
//# sourceMappingURL=LintRequest.d.ts.map
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as path from 'node:path';
|
|
2
|
+
import { unknownWordsChoices } from '@cspell/cspell-types';
|
|
2
3
|
import { calcExcludeGlobInfo } from '../util/glob.js';
|
|
3
4
|
const defaultContextRange = 20;
|
|
4
5
|
export class LintRequest {
|
|
5
6
|
fileGlobs;
|
|
6
7
|
options;
|
|
7
8
|
reporter;
|
|
8
|
-
uniqueFilter;
|
|
9
9
|
locale;
|
|
10
10
|
configFile;
|
|
11
11
|
excludes;
|
|
@@ -14,6 +14,7 @@ export class LintRequest {
|
|
|
14
14
|
enableGlobDot;
|
|
15
15
|
fileLists;
|
|
16
16
|
files;
|
|
17
|
+
cspellSettingsFromCliOptions;
|
|
17
18
|
constructor(fileGlobs, options, reporter) {
|
|
18
19
|
this.fileGlobs = fileGlobs;
|
|
19
20
|
this.options = options;
|
|
@@ -23,12 +24,23 @@ export class LintRequest {
|
|
|
23
24
|
this.excludes = calcExcludeGlobInfo(this.root, options.exclude);
|
|
24
25
|
this.locale = options.locale ?? options.local ?? '';
|
|
25
26
|
this.enableGlobDot = options.dot;
|
|
26
|
-
|
|
27
|
-
this.uniqueFilter = () => true;
|
|
28
|
-
this.showContext =
|
|
29
|
-
options.showContext === true ? defaultContextRange : options.showContext ? options.showContext : 0;
|
|
27
|
+
this.showContext = Math.max(options.showContext === true ? defaultContextRange : options.showContext ? options.showContext : 0, 0);
|
|
30
28
|
this.fileLists = (options.fileList ?? options.fileLists) || [];
|
|
31
29
|
this.files = mergeFiles(options.file, options.files);
|
|
30
|
+
const noConfigSearch = options.configSearch === false ? true : options.configSearch === true ? false : undefined;
|
|
31
|
+
const dictionaries = [
|
|
32
|
+
...(options.disableDictionary ?? []).map((d) => `!${d}`), // first disable dictionaries
|
|
33
|
+
...(options.dictionary ?? []).map((d) => `!!${d}`), // Use `!!` to ensure dictionaries are enabled
|
|
34
|
+
];
|
|
35
|
+
const languageSettings = [
|
|
36
|
+
// Use `*` to match all languages and locales
|
|
37
|
+
{ languageId: '*', locale: '*', dictionaries },
|
|
38
|
+
];
|
|
39
|
+
this.cspellSettingsFromCliOptions = {
|
|
40
|
+
...(noConfigSearch !== undefined ? { noConfigSearch } : {}),
|
|
41
|
+
...extractUnknownWordsConfig(options),
|
|
42
|
+
languageSettings,
|
|
43
|
+
};
|
|
32
44
|
}
|
|
33
45
|
}
|
|
34
46
|
function mergeFiles(a, b) {
|
|
@@ -44,4 +56,28 @@ function merge(a, b) {
|
|
|
44
56
|
return a;
|
|
45
57
|
return [...a, ...b];
|
|
46
58
|
}
|
|
59
|
+
export function extractUnknownWordsConfig(options) {
|
|
60
|
+
const config = {};
|
|
61
|
+
if (!options.report)
|
|
62
|
+
return config;
|
|
63
|
+
switch (options.report) {
|
|
64
|
+
case 'all': {
|
|
65
|
+
config.unknownWords = unknownWordsChoices.ReportAll;
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
case 'simple': {
|
|
69
|
+
config.unknownWords = unknownWordsChoices.ReportSimple;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
case 'typos': {
|
|
73
|
+
config.unknownWords = unknownWordsChoices.ReportCommonTypos;
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
case 'flagged': {
|
|
77
|
+
config.unknownWords = unknownWordsChoices.ReportFlagged;
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return config;
|
|
82
|
+
}
|
|
47
83
|
//# sourceMappingURL=LintRequest.js.map
|
package/dist/esm/lint/index.d.ts
CHANGED
package/dist/esm/lint/index.js
CHANGED
package/dist/esm/lint/lint.js
CHANGED
|
@@ -8,7 +8,7 @@ import chalk from 'chalk';
|
|
|
8
8
|
import { _debug as cspellDictionaryDebug } from 'cspell-dictionary';
|
|
9
9
|
import { findRepoRoot, GitIgnore } from 'cspell-gitignore';
|
|
10
10
|
import { GlobMatcher } from 'cspell-glob';
|
|
11
|
-
import { ENV_CSPELL_GLOB_ROOT, extractDependencies, extractImportErrors, getDefaultConfigLoader, getDictionary, isBinaryFile as cspellIsBinaryFile, setLogger, shouldCheckDocument, spellCheckDocument, Text as cspellText, } from 'cspell-lib';
|
|
11
|
+
import { ENV_CSPELL_GLOB_ROOT, extractDependencies, extractImportErrors, getDefaultConfigLoader, getDictionary, isBinaryFile as cspellIsBinaryFile, mergeSettings, setLogger, shouldCheckDocument, spellCheckDocument, Text as cspellText, } from 'cspell-lib';
|
|
12
12
|
import { console } from '../console.js';
|
|
13
13
|
import { getEnvironmentVariable, setEnvironmentVariable, truthy } from '../environment.js';
|
|
14
14
|
import { getFeatureFlags } from '../featureFlags/index.js';
|
|
@@ -16,10 +16,11 @@ import { npmPackage } from '../pkgInfo.js';
|
|
|
16
16
|
import { calcCacheSettings, createCache } from '../util/cache/index.js';
|
|
17
17
|
import { readConfig } from '../util/configFileHelper.js';
|
|
18
18
|
import { CheckFailed, toApplicationError, toError } from '../util/errors.js';
|
|
19
|
-
import {
|
|
19
|
+
import { extractContext } from '../util/extractContext.js';
|
|
20
|
+
import { fileInfoToDocument, filenameToUri, findFiles, isBinaryFile, isFile, isNotDir, readFileInfo, readFileListFiles, relativeToCwd, resolveFilename, } from '../util/fileHelper.js';
|
|
20
21
|
import { buildGlobMatcher, extractGlobsFromMatcher, extractPatterns, normalizeFileOrGlobsToRoot, normalizeGlobsToRoot, } from '../util/glob.js';
|
|
21
22
|
import { prefetchIterable } from '../util/prefetch.js';
|
|
22
|
-
import {
|
|
23
|
+
import { extractReporterIssueOptions, LintReporter, mergeReportIssueOptions } from '../util/reporters.js';
|
|
23
24
|
import { getTimeMeasurer } from '../util/timer.js';
|
|
24
25
|
import * as util from '../util/util.js';
|
|
25
26
|
import { writeFileOrStream } from '../util/writeFile.js';
|
|
@@ -28,8 +29,7 @@ const BATCH_SIZE = 8;
|
|
|
28
29
|
const debugStats = false;
|
|
29
30
|
const { opFilterAsync } = operators;
|
|
30
31
|
export async function runLint(cfg) {
|
|
31
|
-
|
|
32
|
-
setLogger(getLoggerFromReporter(reporter));
|
|
32
|
+
const reporter = new LintReporter(cfg.reporter, cfg.options);
|
|
33
33
|
const configErrors = new Set();
|
|
34
34
|
const timer = getTimeMeasurer();
|
|
35
35
|
const logDictRequests = truthy(getEnvironmentVariable('CSPELL_ENABLE_DICTIONARY_LOGGING'));
|
|
@@ -49,6 +49,7 @@ export async function runLint(cfg) {
|
|
|
49
49
|
function prefetch(filename, configInfo, cache) {
|
|
50
50
|
if (isBinaryFile(filename, cfg.root))
|
|
51
51
|
return { filename, result: Promise.resolve({ skip: true }) };
|
|
52
|
+
const reportIssueOptions = extractReporterIssueOptions(configInfo.config);
|
|
52
53
|
async function fetch() {
|
|
53
54
|
const getElapsedTimeMs = getTimeMeasurer();
|
|
54
55
|
const cachedResult = await cache.getCachedLintResults(filename);
|
|
@@ -62,7 +63,7 @@ export async function runLint(cfg) {
|
|
|
62
63
|
if (!checkResult.shouldCheck)
|
|
63
64
|
return { skip: true };
|
|
64
65
|
const fileInfo = await readFileInfo(filename, undefined, true);
|
|
65
|
-
return { fileInfo };
|
|
66
|
+
return { fileInfo, reportIssueOptions };
|
|
66
67
|
}
|
|
67
68
|
const result = fetch();
|
|
68
69
|
return { filename, result };
|
|
@@ -71,10 +72,11 @@ export async function runLint(cfg) {
|
|
|
71
72
|
if (prefetch?.fileResult)
|
|
72
73
|
return prefetch.fileResult;
|
|
73
74
|
const getElapsedTimeMs = getTimeMeasurer();
|
|
75
|
+
const reportIssueOptions = prefetch?.reportIssueOptions;
|
|
74
76
|
const cachedResult = await cache.getCachedLintResults(filename);
|
|
75
77
|
if (cachedResult) {
|
|
76
78
|
reporter.debug(`Filename: ${filename}, using cache`);
|
|
77
|
-
return { ...cachedResult, elapsedTimeMs: getElapsedTimeMs() };
|
|
79
|
+
return { ...cachedResult, elapsedTimeMs: getElapsedTimeMs(), reportIssueOptions };
|
|
78
80
|
}
|
|
79
81
|
const result = {
|
|
80
82
|
fileInfo: {
|
|
@@ -85,6 +87,7 @@ export async function runLint(cfg) {
|
|
|
85
87
|
errors: 0,
|
|
86
88
|
configErrors: 0,
|
|
87
89
|
elapsedTimeMs: 0,
|
|
90
|
+
reportIssueOptions,
|
|
88
91
|
};
|
|
89
92
|
const fileInfo = prefetch?.fileInfo || (await readFileInfo(filename, undefined, true));
|
|
90
93
|
if (fileInfo.errorCode) {
|
|
@@ -122,6 +125,7 @@ export async function runLint(cfg) {
|
|
|
122
125
|
}
|
|
123
126
|
result.elapsedTimeMs = getElapsedTimeMs();
|
|
124
127
|
const config = spellResult.settingsUsed ?? {};
|
|
128
|
+
result.reportIssueOptions = mergeReportIssueOptions(spellResult.settingsUsed || configInfo.config, reportIssueOptions);
|
|
125
129
|
result.configErrors += await reportConfigurationErrors(config);
|
|
126
130
|
const elapsed = result.elapsedTimeMs;
|
|
127
131
|
const dictionaries = config.dictionaries || [];
|
|
@@ -144,9 +148,7 @@ export async function runLint(cfg) {
|
|
|
144
148
|
return result;
|
|
145
149
|
}
|
|
146
150
|
function mapIssue({ doc: _, ...tdo }) {
|
|
147
|
-
const context = cfg.showContext
|
|
148
|
-
? extractContext(tdo, cfg.showContext)
|
|
149
|
-
: { text: tdo.line.text.trimEnd(), offset: tdo.line.offset };
|
|
151
|
+
const context = cfg.showContext ? extractContext(tdo, cfg.showContext) : undefined;
|
|
150
152
|
return util.clean({ ...tdo, context });
|
|
151
153
|
}
|
|
152
154
|
async function processFiles(files, configInfo, cacheSettings) {
|
|
@@ -154,23 +156,6 @@ export async function runLint(cfg) {
|
|
|
154
156
|
const status = runResult();
|
|
155
157
|
const cache = createCache(cacheSettings);
|
|
156
158
|
const failFast = cfg.options.failFast ?? configInfo.config.failFast ?? false;
|
|
157
|
-
const emitProgressBegin = (filename, fileNum, fileCount) => reporter.progress({
|
|
158
|
-
type: 'ProgressFileBegin',
|
|
159
|
-
fileNum,
|
|
160
|
-
fileCount,
|
|
161
|
-
filename,
|
|
162
|
-
});
|
|
163
|
-
const emitProgressComplete = (filename, fileNum, fileCount, result) => reporter.progress(util.clean({
|
|
164
|
-
type: 'ProgressFileComplete',
|
|
165
|
-
fileNum,
|
|
166
|
-
fileCount,
|
|
167
|
-
filename,
|
|
168
|
-
elapsedTimeMs: result?.elapsedTimeMs,
|
|
169
|
-
processed: result?.processed,
|
|
170
|
-
numErrors: result?.issues.length || result?.errors,
|
|
171
|
-
cached: result?.cached,
|
|
172
|
-
perf: result?.perf,
|
|
173
|
-
}));
|
|
174
159
|
function* prefetchFiles(files) {
|
|
175
160
|
const iter = prefetchIterable(pipe(files, opMap((filename) => prefetch(filename, configInfo, cache))), BATCH_SIZE);
|
|
176
161
|
for (const v of iter) {
|
|
@@ -189,12 +174,13 @@ export async function runLint(cfg) {
|
|
|
189
174
|
errors: 0,
|
|
190
175
|
configErrors: 0,
|
|
191
176
|
elapsedTimeMs: 1,
|
|
177
|
+
reportIssueOptions: undefined,
|
|
192
178
|
};
|
|
193
179
|
async function processPrefetchFileResult(pf, index) {
|
|
194
180
|
const { filename, result: pFetchResult } = pf;
|
|
195
181
|
const getElapsedTimeMs = getTimeMeasurer();
|
|
196
182
|
const fetchResult = await pFetchResult;
|
|
197
|
-
emitProgressBegin(filename, index, fileCount ?? index);
|
|
183
|
+
reporter.emitProgressBegin(filename, index, fileCount ?? index);
|
|
198
184
|
if (fetchResult?.skip) {
|
|
199
185
|
return {
|
|
200
186
|
filename,
|
|
@@ -230,15 +216,13 @@ export async function runLint(cfg) {
|
|
|
230
216
|
}
|
|
231
217
|
}
|
|
232
218
|
for await (const fileP of loadAndProcessFiles()) {
|
|
233
|
-
const { filename, fileNum, result } =
|
|
219
|
+
const { filename, fileNum, result } = fileP;
|
|
234
220
|
status.files += 1;
|
|
235
221
|
status.cachedFiles = (status.cachedFiles || 0) + (result.cached ? 1 : 0);
|
|
236
|
-
emitProgressComplete(filename, fileNum, fileCount ?? fileNum, result);
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
status.filesWithIssues.add(filename);
|
|
241
|
-
status.issues += result.issues.length;
|
|
222
|
+
const numIssues = reporter.emitProgressComplete(filename, fileNum, fileCount ?? fileNum, result);
|
|
223
|
+
if (numIssues || result.errors) {
|
|
224
|
+
status.filesWithIssues.add(relativeToCwd(filename, cfg.root));
|
|
225
|
+
status.issues += numIssues;
|
|
242
226
|
status.errors += result.errors;
|
|
243
227
|
if (failFast) {
|
|
244
228
|
return status;
|
|
@@ -286,10 +270,11 @@ export async function runLint(cfg) {
|
|
|
286
270
|
if (cfg.options.root) {
|
|
287
271
|
setEnvironmentVariable(ENV_CSPELL_GLOB_ROOT, cfg.root);
|
|
288
272
|
}
|
|
289
|
-
const configInfo = await readConfig(cfg.configFile, cfg.root);
|
|
273
|
+
const configInfo = await readConfig(cfg.configFile, cfg.root, cfg.options.stopConfigSearchAt);
|
|
290
274
|
if (cfg.options.defaultConfiguration !== undefined) {
|
|
291
275
|
configInfo.config.loadDefaultConfiguration = cfg.options.defaultConfiguration;
|
|
292
276
|
}
|
|
277
|
+
configInfo.config = mergeSettings(configInfo.config, cfg.cspellSettingsFromCliOptions);
|
|
293
278
|
const reporterConfig = util.clean({
|
|
294
279
|
maxNumberOfProblems: configInfo.config.maxNumberOfProblems,
|
|
295
280
|
maxDuplicateProblems: configInfo.config.maxDuplicateProblems,
|
|
@@ -298,7 +283,8 @@ export async function runLint(cfg) {
|
|
|
298
283
|
console,
|
|
299
284
|
});
|
|
300
285
|
const reporters = cfg.options.reporter ?? configInfo.config.reporters;
|
|
301
|
-
reporter =
|
|
286
|
+
reporter.config = reporterConfig;
|
|
287
|
+
await reporter.loadReportersAndFinalize(reporters);
|
|
302
288
|
setLogger(getLoggerFromReporter(reporter));
|
|
303
289
|
const globInfo = await determineGlobs(configInfo, cfg);
|
|
304
290
|
const { fileGlobs, excludeGlobs } = globInfo;
|
|
@@ -311,14 +297,18 @@ export async function runLint(cfg) {
|
|
|
311
297
|
checkGlobs(fileGlobs, reporter);
|
|
312
298
|
reporter.info(`Config Files Found:\n ${configInfo.source}\n`, MessageTypes.Info);
|
|
313
299
|
const configErrors = await countConfigErrors(configInfo);
|
|
314
|
-
if (configErrors && cfg.options.exitCode !== false)
|
|
300
|
+
if (configErrors && cfg.options.exitCode !== false && !cfg.options.continueOnError) {
|
|
315
301
|
return runResult({ errors: configErrors });
|
|
302
|
+
}
|
|
316
303
|
// Get Exclusions from the config files.
|
|
317
304
|
const { root } = cfg;
|
|
318
305
|
try {
|
|
319
306
|
const cacheSettings = await calcCacheSettings(configInfo.config, { ...cfg.options, version }, root);
|
|
320
307
|
const files = await determineFilesToCheck(configInfo, cfg, reporter, globInfo);
|
|
321
308
|
const result = await processFiles(files, configInfo, cacheSettings);
|
|
309
|
+
if (configErrors && cfg.options.exitCode !== false) {
|
|
310
|
+
result.errors ||= configErrors;
|
|
311
|
+
}
|
|
322
312
|
debugStats && console.error('stats: %o', getDefaultConfigLoader().getStats());
|
|
323
313
|
return result;
|
|
324
314
|
}
|
|
@@ -433,34 +423,6 @@ async function determineFilesToCheck(configInfo, cfg, reporter, globInfo) {
|
|
|
433
423
|
}
|
|
434
424
|
return _determineFilesToCheck();
|
|
435
425
|
}
|
|
436
|
-
function extractContext(tdo, contextRange) {
|
|
437
|
-
const { line, offset } = tdo;
|
|
438
|
-
const textOffsetInLine = offset - line.offset;
|
|
439
|
-
let left = Math.max(textOffsetInLine - contextRange, 0);
|
|
440
|
-
let right = Math.min(line.text.length, textOffsetInLine + contextRange + tdo.text.length);
|
|
441
|
-
const lineText = line.text;
|
|
442
|
-
const isLetter = /^[a-z]$/i;
|
|
443
|
-
const isSpace = /^\s$/;
|
|
444
|
-
for (let n = contextRange / 2; n > 0 && left > 0; n--, left--) {
|
|
445
|
-
if (!isLetter.test(lineText[left - 1])) {
|
|
446
|
-
break;
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
for (let n = contextRange / 2; n > 0 && right < lineText.length; n--, right++) {
|
|
450
|
-
if (!isLetter.test(lineText[right])) {
|
|
451
|
-
break;
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
// remove leading space
|
|
455
|
-
for (; left < textOffsetInLine && isSpace.test(lineText[left]); left++) {
|
|
456
|
-
/* do nothing */
|
|
457
|
-
}
|
|
458
|
-
const context = {
|
|
459
|
-
text: line.text.slice(left, right).trimEnd(),
|
|
460
|
-
offset: left + line.offset,
|
|
461
|
-
};
|
|
462
|
-
return context;
|
|
463
|
-
}
|
|
464
426
|
function extractGlobSource(g) {
|
|
465
427
|
const { glob, rawGlob, source } = g;
|
|
466
428
|
return {
|