cspell 8.11.0 → 8.12.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 +2 -0
- package/bin.mjs +4 -1
- package/dist/esm/app.d.mts +2 -2
- package/dist/esm/app.mjs +8 -8
- package/dist/esm/application.d.mts +2 -2
- package/dist/esm/application.mjs +13 -11
- package/dist/esm/cli-reporter.d.ts +26 -4
- package/dist/esm/cli-reporter.js +139 -68
- package/dist/esm/commandCheck.js +3 -2
- package/dist/esm/commandLink.js +1 -0
- package/dist/esm/commandLint.js +38 -3
- package/dist/esm/commandSuggestion.js +1 -1
- package/dist/esm/commandTrace.js +2 -1
- package/dist/esm/console.d.ts +25 -0
- package/dist/esm/console.js +53 -0
- package/dist/esm/dirname.d.ts +2 -0
- package/dist/esm/dirname.js +13 -0
- package/dist/esm/emitters/suggestionsEmitter.js +1 -0
- package/dist/esm/emitters/traceEmitter.d.ts +1 -1
- package/dist/esm/emitters/traceEmitter.js +1 -0
- package/dist/esm/featureFlags/featureFlags.js +1 -0
- package/dist/esm/index.d.mts +3 -2
- package/dist/esm/index.mjs +1 -1
- package/dist/esm/lint/lint.js +6 -4
- package/dist/esm/models.d.ts +15 -0
- package/dist/esm/models.js +2 -0
- package/dist/esm/options.d.ts +29 -0
- package/dist/esm/pkgInfo.d.ts +14 -0
- package/dist/esm/pkgInfo.js +7 -0
- package/dist/{lib/file-entry-cache.d.cts → esm/util/cache/file-entry-cache.d.mts} +2 -2
- package/dist/esm/util/cache/file-entry-cache.mjs +5 -0
- package/dist/esm/util/cache/fileEntryCache.d.ts +2 -2
- package/dist/esm/util/cache/fileEntryCache.js +3 -3
- package/dist/esm/util/fileHelper.d.ts +2 -3
- package/dist/esm/util/fileHelper.js +11 -14
- package/dist/esm/util/reporters.js +1 -1
- package/dist/esm/util/unindent.d.ts +14 -0
- package/dist/esm/util/unindent.js +55 -0
- package/package.json +17 -17
- package/dist/esm/app.d.ts +0 -5
- package/dist/esm/app.js +0 -45
- package/dist/esm/application.d.ts +0 -15
- package/dist/esm/application.js +0 -88
- package/dist/esm/cli-reporter.d.mts +0 -16
- package/dist/esm/cli-reporter.mjs +0 -304
- package/dist/esm/commandCheck.d.mts +0 -3
- package/dist/esm/commandCheck.mjs +0 -51
- package/dist/esm/commandLink.d.mts +0 -3
- package/dist/esm/commandLink.mjs +0 -47
- package/dist/esm/commandLint.d.mts +0 -3
- package/dist/esm/commandLint.mjs +0 -202
- package/dist/esm/commandSuggestion.d.mts +0 -3
- package/dist/esm/commandSuggestion.mjs +0 -61
- package/dist/esm/commandTrace.d.mts +0 -3
- package/dist/esm/commandTrace.mjs +0 -85
- package/dist/esm/emitters/DictionaryPathFormat.d.mts +0 -3
- package/dist/esm/emitters/DictionaryPathFormat.mjs +0 -12
- package/dist/esm/emitters/suggestionsEmitter.d.mts +0 -13
- package/dist/esm/emitters/suggestionsEmitter.mjs +0 -78
- package/dist/esm/emitters/traceEmitter.d.mts +0 -27
- package/dist/esm/emitters/traceEmitter.mjs +0 -148
- package/dist/esm/featureFlags/featureFlags.d.mts +0 -4
- package/dist/esm/featureFlags/featureFlags.mjs +0 -20
- package/dist/esm/featureFlags/index.d.mts +0 -2
- package/dist/esm/featureFlags/index.mjs +0 -2
- package/dist/esm/index.d.ts +0 -5
- package/dist/esm/index.js +0 -4
- package/dist/esm/link.d.mts +0 -8
- package/dist/esm/link.mjs +0 -39
- package/dist/esm/lint/LintRequest.d.mts +0 -25
- package/dist/esm/lint/LintRequest.mjs +0 -47
- package/dist/esm/lint/index.d.mts +0 -3
- package/dist/esm/lint/index.mjs +0 -3
- package/dist/esm/lint/lint.d.mts +0 -4
- package/dist/esm/lint/lint.mjs +0 -508
- package/dist/esm/options.d.mts +0 -211
- package/dist/esm/options.mjs +0 -8
- package/dist/esm/repl/index.d.mts +0 -18
- package/dist/esm/repl/index.mjs +0 -52
- package/dist/esm/util/InMemoryReporter.d.mts +0 -28
- package/dist/esm/util/InMemoryReporter.mjs +0 -42
- package/dist/esm/util/async.d.mts +0 -3
- package/dist/esm/util/async.mjs +0 -4
- package/dist/esm/util/cache/CSpellLintResultCache.d.mts +0 -20
- package/dist/esm/util/cache/CSpellLintResultCache.mjs +0 -2
- package/dist/esm/util/cache/CacheOptions.d.mts +0 -34
- package/dist/esm/util/cache/CacheOptions.mjs +0 -2
- package/dist/esm/util/cache/DiskCache.d.mts +0 -63
- package/dist/esm/util/cache/DiskCache.mjs +0 -214
- package/dist/esm/util/cache/DummyCache.d.mts +0 -11
- package/dist/esm/util/cache/DummyCache.mjs +0 -18
- package/dist/esm/util/cache/ObjectCollection.d.mts +0 -17
- package/dist/esm/util/cache/ObjectCollection.mjs +0 -127
- package/dist/esm/util/cache/createCache.d.mts +0 -31
- package/dist/esm/util/cache/createCache.mjs +0 -69
- package/dist/esm/util/cache/fileEntryCache.d.mts +0 -9
- package/dist/esm/util/cache/fileEntryCache.mjs +0 -79
- package/dist/esm/util/cache/index.d.mts +0 -4
- package/dist/esm/util/cache/index.mjs +0 -2
- package/dist/esm/util/constants.d.mts +0 -5
- package/dist/esm/util/constants.mjs +0 -5
- package/dist/esm/util/errors.d.mts +0 -23
- package/dist/esm/util/errors.mjs +0 -55
- package/dist/esm/util/fileHelper.d.mts +0 -65
- package/dist/esm/util/fileHelper.mjs +0 -161
- package/dist/esm/util/glob.d.mts +0 -45
- package/dist/esm/util/glob.mjs +0 -137
- package/dist/esm/util/pad.d.mts +0 -6
- package/dist/esm/util/pad.mjs +0 -28
- package/dist/esm/util/prefetch.d.mts +0 -2
- package/dist/esm/util/prefetch.mjs +0 -15
- package/dist/esm/util/reporters.d.mts +0 -14
- package/dist/esm/util/reporters.mjs +0 -62
- package/dist/esm/util/stdin.d.mts +0 -2
- package/dist/esm/util/stdin.mjs +0 -5
- package/dist/esm/util/table.d.mts +0 -14
- package/dist/esm/util/table.mjs +0 -55
- package/dist/esm/util/timer.d.mts +0 -4
- package/dist/esm/util/timer.mjs +0 -9
- package/dist/esm/util/types.d.mts +0 -7
- package/dist/esm/util/types.mjs +0 -5
- package/dist/esm/util/util.d.mts +0 -9
- package/dist/esm/util/util.mjs +0 -25
- package/dist/lib/file-entry-cache.cjs +0 -32
- package/dist/lib/pkgInfo.cjs +0 -6
- package/dist/lib/pkgInfo.d.cts +0 -3
package/README.md
CHANGED
|
@@ -188,6 +188,8 @@ Options:
|
|
|
188
188
|
--debug Output information useful for debugging
|
|
189
189
|
cspell.json files.
|
|
190
190
|
--reporter <module|path> Specify one or more reporters to use.
|
|
191
|
+
--issue-template [template] Use a custom issue template. See --help
|
|
192
|
+
--issue-template for details.
|
|
191
193
|
-h, --help display help for command
|
|
192
194
|
|
|
193
195
|
More Examples:
|
package/bin.mjs
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { format } from 'node:util';
|
|
3
|
+
|
|
2
4
|
import { CommanderError, program } from 'commander';
|
|
3
5
|
|
|
4
6
|
import * as app from './dist/esm/app.mjs';
|
|
5
7
|
|
|
6
8
|
app.run(program, process.argv).catch((e) => {
|
|
7
9
|
if (!(e instanceof CommanderError) && !(e instanceof app.CheckFailed)) {
|
|
8
|
-
|
|
10
|
+
const msg = e instanceof app.ApplicationError ? e.message : format(e);
|
|
11
|
+
process.stdout.write(msg + '\n');
|
|
9
12
|
// It is possible an explicit exit code was set, use it if it was.
|
|
10
13
|
process.exitCode = process.exitCode || 1;
|
|
11
14
|
}
|
package/dist/esm/app.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Command } from 'commander';
|
|
2
|
-
export { LinterCliOptions as Options } from './options.
|
|
3
|
-
export { CheckFailed } from './util/errors.
|
|
2
|
+
export { LinterCliOptions as Options } from './options.js';
|
|
3
|
+
export { ApplicationError, CheckFailed } from './util/errors.js';
|
|
4
4
|
export declare function run(command?: Command, argv?: string[]): Promise<void>;
|
|
5
5
|
//# sourceMappingURL=app.d.mts.map
|
package/dist/esm/app.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Option as CommanderOption, program } from 'commander';
|
|
2
2
|
import { satisfies as semverSatisfies } from 'semver';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { ApplicationError } from './util/errors.
|
|
10
|
-
export { CheckFailed } from './util/errors.
|
|
3
|
+
import { commandCheck } from './commandCheck.js';
|
|
4
|
+
import { commandLink } from './commandLink.js';
|
|
5
|
+
import { commandLint } from './commandLint.js';
|
|
6
|
+
import { commandSuggestion } from './commandSuggestion.js';
|
|
7
|
+
import { commandTrace } from './commandTrace.js';
|
|
8
|
+
import { npmPackage } from './pkgInfo.js';
|
|
9
|
+
import { ApplicationError } from './util/errors.js';
|
|
10
|
+
export { ApplicationError, CheckFailed } from './util/errors.js';
|
|
11
11
|
export async function run(command, argv) {
|
|
12
12
|
const prog = command || program;
|
|
13
13
|
const args = argv || process.argv;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { CSpellReporter, RunResult } from '@cspell/cspell-types';
|
|
2
2
|
import type { CheckTextInfo, FeatureFlags, TraceWordResult } from 'cspell-lib';
|
|
3
|
-
import type { TimedSuggestionsForWordResult } from './emitters/suggestionsEmitter.
|
|
4
|
-
import type { BaseOptions, LegacyOptions, LinterCliOptions, SuggestionOptions, TraceOptions } from './options.
|
|
3
|
+
import type { TimedSuggestionsForWordResult } from './emitters/suggestionsEmitter.js';
|
|
4
|
+
import type { BaseOptions, LegacyOptions, LinterCliOptions, SuggestionOptions, TraceOptions } from './options.js';
|
|
5
5
|
export type { TraceResult } from 'cspell-lib';
|
|
6
6
|
export { IncludeExcludeFlag } from 'cspell-lib';
|
|
7
7
|
export type AppError = NodeJS.ErrnoException;
|
package/dist/esm/application.mjs
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import { opMap, opTap, pipeAsync, toAsyncIterable } from '@cspell/cspell-pipe';
|
|
2
2
|
import { checkTextDocument, getDefaultSettings, getGlobalSettingsAsync, mergeSettings, SuggestionError, suggestionsForWords, traceWordsAsync, } from 'cspell-lib';
|
|
3
|
-
import { getReporter } from './cli-reporter.
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import
|
|
3
|
+
import { getReporter } from './cli-reporter.js';
|
|
4
|
+
import { console } from './console.js';
|
|
5
|
+
import { getFeatureFlags, parseFeatureFlags } from './featureFlags/index.js';
|
|
6
|
+
import { LintRequest, runLint } from './lint/index.js';
|
|
7
|
+
import { fixLegacy } from './options.js';
|
|
8
|
+
import { simpleRepl } from './repl/index.js';
|
|
9
|
+
import { fileInfoToDocument, readConfig, readFileInfo } from './util/fileHelper.js';
|
|
10
|
+
import { finalizeReporter } from './util/reporters.js';
|
|
11
|
+
import { readStdin } from './util/stdin.js';
|
|
12
|
+
import { getTimeMeasurer } from './util/timer.js';
|
|
13
|
+
import * as util from './util/util.js';
|
|
13
14
|
export { IncludeExcludeFlag } from 'cspell-lib';
|
|
14
15
|
export function lint(fileGlobs, options, reporter) {
|
|
15
16
|
options = fixLegacy(options);
|
|
16
|
-
const
|
|
17
|
+
const reporterOptions = { ...options, console };
|
|
18
|
+
const cfg = new LintRequest(fileGlobs, options, finalizeReporter(reporter) ?? getReporter({ ...options, fileGlobs }, reporterOptions));
|
|
17
19
|
return runLint(cfg);
|
|
18
20
|
}
|
|
19
21
|
export async function* trace(words, options) {
|
|
@@ -1,14 +1,36 @@
|
|
|
1
|
-
import type { Issue
|
|
1
|
+
import type { Issue } from '@cspell/cspell-types';
|
|
2
|
+
import type { ChalkInstance } from 'chalk';
|
|
3
|
+
import { CSpellReporterConfiguration } from './models.js';
|
|
2
4
|
import type { LinterCliOptions } from './options.js';
|
|
3
5
|
import type { FinalizedReporter } from './util/reporters.js';
|
|
6
|
+
export interface TemplateSubstitutions extends Record<string, string> {
|
|
7
|
+
$col: string;
|
|
8
|
+
$contextFull: string;
|
|
9
|
+
$contextLeft: string;
|
|
10
|
+
$contextRight: string;
|
|
11
|
+
$filename: string;
|
|
12
|
+
$padContext: string;
|
|
13
|
+
$padRowCol: string;
|
|
14
|
+
$row: string;
|
|
15
|
+
$suggestions: string;
|
|
16
|
+
$text: string;
|
|
17
|
+
$uri: string;
|
|
18
|
+
$quickFix: string;
|
|
19
|
+
$message: string;
|
|
20
|
+
$messageColored: string;
|
|
21
|
+
}
|
|
4
22
|
export interface ReporterIssue extends Issue {
|
|
5
23
|
filename: string;
|
|
6
24
|
}
|
|
7
|
-
|
|
25
|
+
interface IOChalk {
|
|
26
|
+
readonly chalk: ChalkInstance;
|
|
27
|
+
}
|
|
28
|
+
export interface ReporterOptions extends Pick<LinterCliOptions, 'debug' | 'issues' | 'issuesSummaryReport' | 'legacy' | 'progress' | 'relative' | 'root' | 'showContext' | 'showPerfSummary' | 'showSuggestions' | 'silent' | 'summary' | 'verbose' | 'wordsOnly'> {
|
|
8
29
|
fileGlobs: string[];
|
|
9
30
|
}
|
|
10
|
-
export declare function getReporter(options: ReporterOptions, config?:
|
|
11
|
-
declare function formatIssue(templateStr: string, issue: ReporterIssue, maxIssueTextWidth: number): string;
|
|
31
|
+
export declare function getReporter(options: ReporterOptions, config?: CSpellReporterConfiguration): FinalizedReporter;
|
|
32
|
+
declare function formatIssue(io: IOChalk, templateStr: string, issue: ReporterIssue, maxIssueTextWidth: number): string;
|
|
33
|
+
export declare function checkTemplate(template: string): true | Error;
|
|
12
34
|
export declare const __testing__: {
|
|
13
35
|
formatIssue: typeof formatIssue;
|
|
14
36
|
};
|
package/dist/esm/cli-reporter.js
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
import
|
|
1
|
+
import assert from 'node:assert';
|
|
2
2
|
import { format } from 'node:util';
|
|
3
|
-
import
|
|
4
|
-
import
|
|
3
|
+
import { toFileDirURL, toFilePathOrHref, toFileURL, urlRelative } from '@cspell/url';
|
|
4
|
+
import { Chalk } from 'chalk';
|
|
5
|
+
import { makeTemplate } from 'chalk-template';
|
|
5
6
|
import { isSpellingDictionaryLoadError } from 'cspell-lib';
|
|
6
|
-
import {
|
|
7
|
+
import { console as customConsole } from './console.js';
|
|
8
|
+
import { ApplicationError } from './util/errors.js';
|
|
7
9
|
import { uniqueFilterFnGenerator } from './util/util.js';
|
|
8
10
|
const templateIssue = `{green $filename}:{yellow $row:$col} - $message ({red $text}) $quickFix`;
|
|
9
11
|
const templateIssueNoFix = `{green $filename}:{yellow $row:$col} - $message ({red $text})`;
|
|
10
12
|
const templateIssueWithSuggestions = `{green $filename}:{yellow $row:$col} - $message ({red $text}) Suggestions: {yellow [$suggestions]}`;
|
|
11
13
|
const templateIssueWithContext = `{green $filename}:{yellow $row:$col} $padRowCol- $message ({red $text})$padContext -- {gray $contextLeft}{red {underline $text}}{gray $contextRight}`;
|
|
12
14
|
const templateIssueWithContextWithSuggestions = `{green $filename}:{yellow $row:$col} $padRowCol- $message ({red $text})$padContext -- {gray $contextLeft}{red {underline $text}}{gray $contextRight}\n\t Suggestions: {yellow [$suggestions]}`;
|
|
13
|
-
const templateIssueLegacy =
|
|
15
|
+
const templateIssueLegacy = `{green $filename}[$row, $col]: $message: {red $text}`;
|
|
14
16
|
const templateIssueWordsOnly = '$text';
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
17
|
+
const console = undefined;
|
|
18
|
+
assert(!console);
|
|
18
19
|
/**
|
|
19
20
|
*
|
|
20
21
|
* @param template - The template to use for the issue.
|
|
@@ -22,7 +23,7 @@ function consoleError(...params) {
|
|
|
22
23
|
* @param reportedIssuesCollection - optional collection to store reported issues.
|
|
23
24
|
* @returns issueEmitter function
|
|
24
25
|
*/
|
|
25
|
-
function genIssueEmitter(template, uniqueIssues, reportedIssuesCollection) {
|
|
26
|
+
function genIssueEmitter(io, template, uniqueIssues, reportedIssuesCollection) {
|
|
26
27
|
const uniqueFilter = uniqueIssues ? uniqueFilterFnGenerator((issue) => issue.text) : () => true;
|
|
27
28
|
const defaultWidth = 10;
|
|
28
29
|
let maxWidth = defaultWidth;
|
|
@@ -35,56 +36,69 @@ function genIssueEmitter(template, uniqueIssues, reportedIssuesCollection) {
|
|
|
35
36
|
uri = issue.uri;
|
|
36
37
|
}
|
|
37
38
|
maxWidth = Math.max(maxWidth * 0.999, issue.text.length, 10);
|
|
38
|
-
const issueText = formatIssue(template, issue, Math.ceil(maxWidth));
|
|
39
|
+
const issueText = formatIssue(io, template, issue, Math.ceil(maxWidth));
|
|
39
40
|
reportedIssuesCollection?.push(issueText);
|
|
40
|
-
|
|
41
|
+
io.writeLine(issueText);
|
|
41
42
|
};
|
|
42
43
|
}
|
|
43
44
|
function nullEmitter() {
|
|
44
45
|
/* empty */
|
|
45
46
|
}
|
|
46
|
-
function
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
return filename;
|
|
50
|
-
return '.' + path.sep + rel;
|
|
51
|
-
}
|
|
52
|
-
function relativeUriFilename(uri, fsPathRoot) {
|
|
53
|
-
const fsPath = URI.parse(uri).fsPath;
|
|
54
|
-
const rel = path.relative(fsPathRoot, fsPath);
|
|
47
|
+
function relativeUriFilename(uri, rootURL) {
|
|
48
|
+
const url = toFileURL(uri);
|
|
49
|
+
const rel = urlRelative(rootURL, url);
|
|
55
50
|
if (rel.startsWith('..'))
|
|
56
|
-
return
|
|
57
|
-
return
|
|
51
|
+
return toFilePathOrHref(url);
|
|
52
|
+
return rel;
|
|
58
53
|
}
|
|
59
|
-
function reportProgress(p,
|
|
54
|
+
function reportProgress(io, p, cwdURL, options) {
|
|
60
55
|
if (p.type === 'ProgressFileComplete') {
|
|
61
|
-
return reportProgressFileComplete(p);
|
|
56
|
+
return reportProgressFileComplete(io, p, cwdURL, options);
|
|
62
57
|
}
|
|
63
58
|
if (p.type === 'ProgressFileBegin') {
|
|
64
|
-
return reportProgressFileBegin(p,
|
|
59
|
+
return reportProgressFileBegin(io, p, cwdURL);
|
|
65
60
|
}
|
|
66
61
|
}
|
|
67
|
-
function
|
|
62
|
+
function determineFilename(io, p, cwd) {
|
|
68
63
|
const fc = '' + p.fileCount;
|
|
69
64
|
const fn = (' '.repeat(fc.length) + p.fileNum).slice(-fc.length);
|
|
70
65
|
const idx = fn + '/' + fc;
|
|
71
|
-
const filename = chalk.gray(
|
|
72
|
-
|
|
66
|
+
const filename = io.chalk.gray(relativeUriFilename(p.filename, cwd));
|
|
67
|
+
return { idx, filename };
|
|
73
68
|
}
|
|
74
|
-
function
|
|
75
|
-
const
|
|
69
|
+
function reportProgressFileBegin(io, p, cwdURL) {
|
|
70
|
+
const { idx, filename } = determineFilename(io, p, cwdURL);
|
|
71
|
+
if (io.getColorLevel() > 0) {
|
|
72
|
+
io.clearLine?.(0);
|
|
73
|
+
io.write(`${idx} ${filename}\r`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function reportProgressFileComplete(io, p, cwd, options) {
|
|
77
|
+
const { idx, filename } = determineFilename(io, p, cwd);
|
|
78
|
+
const { verbose, debug } = options;
|
|
79
|
+
const time = reportTime(io, p.elapsedTimeMs, !!p.cached);
|
|
76
80
|
const skipped = p.processed === false ? ' skipped' : '';
|
|
77
|
-
const hasErrors = p.numErrors ? chalk.red ` X` : '';
|
|
78
|
-
|
|
81
|
+
const hasErrors = p.numErrors ? io.chalk.red ` X` : '';
|
|
82
|
+
const newLine = (skipped && (verbose || debug)) || hasErrors || isSlow(p.elapsedTimeMs) || io.getColorLevel() < 1 ? '\n' : '';
|
|
83
|
+
const msg = `${idx} ${filename} ${time}${skipped}${hasErrors}${newLine || '\r'}`;
|
|
84
|
+
io.write(msg);
|
|
79
85
|
}
|
|
80
|
-
function reportTime(elapsedTimeMs, cached) {
|
|
86
|
+
function reportTime(io, elapsedTimeMs, cached) {
|
|
81
87
|
if (cached)
|
|
82
|
-
return chalk.green('cached');
|
|
88
|
+
return io.chalk.green('cached');
|
|
83
89
|
if (elapsedTimeMs === undefined)
|
|
84
90
|
return '-';
|
|
85
|
-
const
|
|
91
|
+
const slow = isSlow(elapsedTimeMs);
|
|
92
|
+
const color = !slow ? io.chalk.white : slow === 1 ? io.chalk.yellow : io.chalk.redBright;
|
|
86
93
|
return color(elapsedTimeMs.toFixed(2) + 'ms');
|
|
87
94
|
}
|
|
95
|
+
function isSlow(elapsedTmeMs) {
|
|
96
|
+
if (!elapsedTmeMs || elapsedTmeMs < 1000)
|
|
97
|
+
return 0;
|
|
98
|
+
if (elapsedTmeMs < 2000)
|
|
99
|
+
return 1;
|
|
100
|
+
return 2;
|
|
101
|
+
}
|
|
88
102
|
export function getReporter(options, config) {
|
|
89
103
|
const perfStats = {
|
|
90
104
|
filesProcessed: 0,
|
|
@@ -94,7 +108,7 @@ export function getReporter(options, config) {
|
|
|
94
108
|
perf: Object.create(null),
|
|
95
109
|
};
|
|
96
110
|
const uniqueIssues = config?.unique || false;
|
|
97
|
-
const
|
|
111
|
+
const defaultIssueTemplate = options.wordsOnly
|
|
98
112
|
? templateIssueWordsOnly
|
|
99
113
|
: options.legacy
|
|
100
114
|
? templateIssueLegacy
|
|
@@ -108,23 +122,38 @@ export function getReporter(options, config) {
|
|
|
108
122
|
? templateIssueNoFix
|
|
109
123
|
: templateIssue;
|
|
110
124
|
const { fileGlobs, silent, summary, issues, progress: showProgress, verbose, debug } = options;
|
|
125
|
+
const issueTemplate = config?.issueTemplate || defaultIssueTemplate;
|
|
126
|
+
assertCheckTemplate(issueTemplate);
|
|
127
|
+
const console = config?.console || customConsole;
|
|
128
|
+
const stdio = {
|
|
129
|
+
...console.stdoutChannel,
|
|
130
|
+
chalk: new Chalk({ level: console.stdoutChannel.getColorLevel() }),
|
|
131
|
+
};
|
|
132
|
+
const stderr = {
|
|
133
|
+
...console.stderrChannel,
|
|
134
|
+
chalk: new Chalk({ level: console.stderrChannel.getColorLevel() }),
|
|
135
|
+
};
|
|
136
|
+
const consoleError = (msg) => stderr.writeLine(msg);
|
|
137
|
+
function createInfoLog(wrap) {
|
|
138
|
+
return (msg) => console.info(wrap(msg));
|
|
139
|
+
}
|
|
111
140
|
const emitters = {
|
|
112
|
-
Debug: !silent && debug ? (
|
|
113
|
-
Info: !silent && verbose ? (
|
|
114
|
-
Warning: (
|
|
141
|
+
Debug: !silent && debug ? createInfoLog(stdio.chalk.cyan) : nullEmitter,
|
|
142
|
+
Info: !silent && verbose ? createInfoLog(stdio.chalk.yellow) : nullEmitter,
|
|
143
|
+
Warning: createInfoLog(stdio.chalk.yellow),
|
|
115
144
|
};
|
|
116
145
|
function infoEmitter(message, msgType) {
|
|
117
146
|
emitters[msgType]?.(message);
|
|
118
147
|
}
|
|
119
|
-
const
|
|
120
|
-
const fsPathRoot = root.fsPath;
|
|
148
|
+
const rootURL = toFileDirURL(options.root || process.cwd());
|
|
121
149
|
function relativeIssue(fn) {
|
|
122
150
|
const fnFilename = options.relative
|
|
123
|
-
? (uri) => relativeUriFilename(uri,
|
|
124
|
-
: (uri) =>
|
|
151
|
+
? (uri) => relativeUriFilename(uri, rootURL)
|
|
152
|
+
: (uri) => toFilePathOrHref(toFileURL(uri, rootURL));
|
|
125
153
|
return (i) => {
|
|
154
|
+
const fullFilename = i.uri ? toFilePathOrHref(toFileURL(i.uri, rootURL)) : '';
|
|
126
155
|
const filename = i.uri ? fnFilename(i.uri) : '';
|
|
127
|
-
const r = { ...i, filename };
|
|
156
|
+
const r = { ...i, filename, fullFilename };
|
|
128
157
|
fn(r);
|
|
129
158
|
};
|
|
130
159
|
}
|
|
@@ -134,7 +163,7 @@ export function getReporter(options, config) {
|
|
|
134
163
|
if (isSpellingDictionaryLoadError(error)) {
|
|
135
164
|
error = error.cause;
|
|
136
165
|
}
|
|
137
|
-
const errorText = format(chalk.red(message), error.toString());
|
|
166
|
+
const errorText = format(stderr.chalk.red(message), error.toString());
|
|
138
167
|
errorCollection?.push(errorText);
|
|
139
168
|
consoleError(errorText);
|
|
140
169
|
}
|
|
@@ -144,6 +173,10 @@ export function getReporter(options, config) {
|
|
|
144
173
|
}
|
|
145
174
|
const { files, issues, cachedFiles, filesWithIssues, errors } = result;
|
|
146
175
|
const numFilesWithIssues = filesWithIssues.size;
|
|
176
|
+
if (stderr.getColorLevel() > 0) {
|
|
177
|
+
stderr.write('\r');
|
|
178
|
+
stderr.clearLine(0);
|
|
179
|
+
}
|
|
147
180
|
if (issuesCollection?.length || errorCollection?.length) {
|
|
148
181
|
consoleError('-------------------------------------------');
|
|
149
182
|
}
|
|
@@ -198,14 +231,14 @@ export function getReporter(options, config) {
|
|
|
198
231
|
}
|
|
199
232
|
function progress(p) {
|
|
200
233
|
if (!silent && showProgress) {
|
|
201
|
-
reportProgress(p,
|
|
234
|
+
reportProgress(stderr, p, rootURL, options);
|
|
202
235
|
}
|
|
203
236
|
if (p.type === 'ProgressFileComplete') {
|
|
204
237
|
collectPerfStats(p);
|
|
205
238
|
}
|
|
206
239
|
}
|
|
207
240
|
return {
|
|
208
|
-
issue: relativeIssue(silent || !issues ? nullEmitter : genIssueEmitter(issueTemplate, uniqueIssues, issuesCollection)),
|
|
241
|
+
issue: relativeIssue(silent || !issues ? nullEmitter : genIssueEmitter(stdio, issueTemplate, uniqueIssues, issuesCollection)),
|
|
209
242
|
error: silent ? nullEmitter : errorEmitter,
|
|
210
243
|
info: infoEmitter,
|
|
211
244
|
debug: emitters.Debug,
|
|
@@ -213,7 +246,7 @@ export function getReporter(options, config) {
|
|
|
213
246
|
result: !silent && summary ? resultEmitter : nullEmitter,
|
|
214
247
|
};
|
|
215
248
|
}
|
|
216
|
-
function formatIssue(templateStr, issue, maxIssueTextWidth) {
|
|
249
|
+
function formatIssue(io, templateStr, issue, maxIssueTextWidth) {
|
|
217
250
|
function clean(t) {
|
|
218
251
|
return t.replace(/\s+/, ' ');
|
|
219
252
|
}
|
|
@@ -225,9 +258,9 @@ function formatIssue(templateStr, issue, maxIssueTextWidth) {
|
|
|
225
258
|
const rowText = row.toString();
|
|
226
259
|
const colText = col.toString();
|
|
227
260
|
const padRowCol = ' '.repeat(Math.max(1, 8 - (rowText.length + colText.length)));
|
|
228
|
-
const suggestions = formatSuggestions(issue);
|
|
261
|
+
const suggestions = formatSuggestions(io, issue);
|
|
229
262
|
const msg = issue.message || (issue.isFlagged ? 'Forbidden word' : 'Unknown word');
|
|
230
|
-
const
|
|
263
|
+
const messageColored = issue.isFlagged ? `{yellow ${msg}}` : msg;
|
|
231
264
|
const substitutions = {
|
|
232
265
|
$col: colText,
|
|
233
266
|
$contextFull: contextFull,
|
|
@@ -240,16 +273,19 @@ function formatIssue(templateStr, issue, maxIssueTextWidth) {
|
|
|
240
273
|
$suggestions: suggestions,
|
|
241
274
|
$text: text,
|
|
242
275
|
$uri: uri,
|
|
243
|
-
$quickFix: formatQuickFix(issue),
|
|
276
|
+
$quickFix: formatQuickFix(io, issue),
|
|
277
|
+
$message: msg,
|
|
278
|
+
$messageColored: messageColored,
|
|
244
279
|
};
|
|
245
|
-
const t =
|
|
280
|
+
const t = templateStr.replaceAll('$messageColored', messageColored);
|
|
281
|
+
const chalkTemplate = makeTemplate(io.chalk);
|
|
246
282
|
return substitute(chalkTemplate(t), substitutions).trimEnd();
|
|
247
283
|
}
|
|
248
|
-
function formatSuggestions(issue) {
|
|
284
|
+
function formatSuggestions(io, issue) {
|
|
249
285
|
if (issue.suggestionsEx) {
|
|
250
286
|
return issue.suggestionsEx
|
|
251
287
|
.map((sug) => sug.isPreferred
|
|
252
|
-
? chalk.italic(chalk.bold(sug.wordAdjustedToMatchCase || sug.word)) + '*'
|
|
288
|
+
? io.chalk.italic(io.chalk.bold(sug.wordAdjustedToMatchCase || sug.word)) + '*'
|
|
253
289
|
: sug.wordAdjustedToMatchCase || sug.word)
|
|
254
290
|
.join(', ');
|
|
255
291
|
}
|
|
@@ -258,7 +294,7 @@ function formatSuggestions(issue) {
|
|
|
258
294
|
}
|
|
259
295
|
return '';
|
|
260
296
|
}
|
|
261
|
-
function formatQuickFix(issue) {
|
|
297
|
+
function formatQuickFix(io, issue) {
|
|
262
298
|
if (!issue.suggestionsEx?.length)
|
|
263
299
|
return '';
|
|
264
300
|
const preferred = issue.suggestionsEx
|
|
@@ -266,25 +302,21 @@ function formatQuickFix(issue) {
|
|
|
266
302
|
.map((sug) => sug.wordAdjustedToMatchCase || sug.word);
|
|
267
303
|
if (!preferred.length)
|
|
268
304
|
return '';
|
|
269
|
-
const fixes = preferred.map((w) => chalk.italic(chalk.yellow(w)));
|
|
305
|
+
const fixes = preferred.map((w) => io.chalk.italic(io.chalk.yellow(w)));
|
|
270
306
|
return `fix: (${fixes.join(', ')})`;
|
|
271
307
|
}
|
|
272
|
-
class TS extends Array {
|
|
273
|
-
raw;
|
|
274
|
-
constructor(s) {
|
|
275
|
-
super(s);
|
|
276
|
-
this.raw = [s];
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
function template(s) {
|
|
280
|
-
return new TS(s);
|
|
281
|
-
}
|
|
282
308
|
function substitute(text, substitutions) {
|
|
283
309
|
const subs = [];
|
|
284
310
|
for (const [match, replaceWith] of Object.entries(substitutions)) {
|
|
285
311
|
const len = match.length;
|
|
286
|
-
for (let i = text.indexOf(match); i >= 0; i = text.indexOf(match, i
|
|
287
|
-
|
|
312
|
+
for (let i = text.indexOf(match); i >= 0; i = text.indexOf(match, i)) {
|
|
313
|
+
const end = i + len;
|
|
314
|
+
const reg = /\b/y;
|
|
315
|
+
reg.lastIndex = end;
|
|
316
|
+
if (reg.test(text)) {
|
|
317
|
+
subs.push([i, end, replaceWith]);
|
|
318
|
+
}
|
|
319
|
+
i = end;
|
|
288
320
|
}
|
|
289
321
|
}
|
|
290
322
|
subs.sort((a, b) => a[0] - b[0]);
|
|
@@ -298,6 +330,45 @@ function substitute(text, substitutions) {
|
|
|
298
330
|
const parts = subs.map(sub);
|
|
299
331
|
return parts.join('') + text.slice(i);
|
|
300
332
|
}
|
|
333
|
+
function assertCheckTemplate(template) {
|
|
334
|
+
const r = checkTemplate(template);
|
|
335
|
+
if (r instanceof Error) {
|
|
336
|
+
throw r;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
export function checkTemplate(template) {
|
|
340
|
+
const chalk = new Chalk();
|
|
341
|
+
const chalkTemplate = makeTemplate(chalk);
|
|
342
|
+
const substitutions = {
|
|
343
|
+
$col: '<col>',
|
|
344
|
+
$contextFull: '<contextFull>',
|
|
345
|
+
$contextLeft: '<contextLeft>',
|
|
346
|
+
$contextRight: '<contextRight>',
|
|
347
|
+
$filename: '<filename>',
|
|
348
|
+
$padContext: '<padContext>',
|
|
349
|
+
$padRowCol: '<padRowCol>',
|
|
350
|
+
$row: '<row>',
|
|
351
|
+
$suggestions: '<suggestions>',
|
|
352
|
+
$text: '<text>',
|
|
353
|
+
$uri: '<uri>',
|
|
354
|
+
$quickFix: '<quickFix>',
|
|
355
|
+
$message: '<message>',
|
|
356
|
+
$messageColored: '<messageColored>',
|
|
357
|
+
};
|
|
358
|
+
try {
|
|
359
|
+
const t = chalkTemplate(template);
|
|
360
|
+
const result = substitute(t, substitutions);
|
|
361
|
+
const problems = [...result.matchAll(/\$[a-z]+/gi)].map((m) => m[0]);
|
|
362
|
+
if (problems.length) {
|
|
363
|
+
throw new Error(`Unresolved template variable${problems.length > 1 ? 's' : ''}: ${problems.map((v) => `'${v}'`).join(', ')}`);
|
|
364
|
+
}
|
|
365
|
+
return true;
|
|
366
|
+
}
|
|
367
|
+
catch (e) {
|
|
368
|
+
const msg = e instanceof Error ? e.message : `${e}`;
|
|
369
|
+
return new ApplicationError(msg);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
301
372
|
export const __testing__ = {
|
|
302
373
|
formatIssue,
|
|
303
374
|
};
|
package/dist/esm/commandCheck.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { Option as CommanderOption } from 'commander';
|
|
3
|
-
import * as App from './application.
|
|
4
|
-
import { checkText } from './application.
|
|
3
|
+
import * as App from './application.mjs';
|
|
4
|
+
import { checkText } from './application.mjs';
|
|
5
|
+
import { console } from './console.js';
|
|
5
6
|
import { CheckFailed } from './util/errors.js';
|
|
6
7
|
export function commandCheck(prog) {
|
|
7
8
|
return prog
|
package/dist/esm/commandLink.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { console } from './console.js';
|
|
1
2
|
import { addPathsToGlobalImports, addPathsToGlobalImportsResultToTable, listGlobalImports, listGlobalImportsResultToTable, removePathsFromGlobalImports, } from './link.js';
|
|
2
3
|
import { CheckFailed } from './util/errors.js';
|
|
3
4
|
import { tableToLines } from './util/table.js';
|
package/dist/esm/commandLint.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Option as CommanderOption } from 'commander';
|
|
2
|
-
import * as App from './application.
|
|
2
|
+
import * as App from './application.mjs';
|
|
3
3
|
import { DEFAULT_CACHE_LOCATION } from './util/cache/index.js';
|
|
4
4
|
import { CheckFailed } from './util/errors.js';
|
|
5
|
+
import { unindent } from './util/unindent.js';
|
|
5
6
|
// interface InitOptions extends Options {}
|
|
6
7
|
const usage = `\
|
|
7
8
|
[options] [globs...] [file://<path> ...] [stdin[://<path>]]
|
|
@@ -126,6 +127,7 @@ export function commandLint(prog) {
|
|
|
126
127
|
.hideHelp())
|
|
127
128
|
.addOption(crOpt('--issues-summary-report', 'Output a summary of issues found.').hideHelp())
|
|
128
129
|
.addOption(crOpt('--show-perf-summary', 'Output a performance summary report.').hideHelp())
|
|
130
|
+
.option('--issue-template [template]', 'Use a custom issue template. See --help --issue-template for details.')
|
|
129
131
|
// Planned options
|
|
130
132
|
// .option('--dictionary <dictionary name>', 'Enable a dictionary by name.', collect)
|
|
131
133
|
// .option('--no-dictionary <dictionary name>', 'Disable a dictionary by name.', collect)
|
|
@@ -157,6 +159,38 @@ export function commandLint(prog) {
|
|
|
157
159
|
});
|
|
158
160
|
return spellCheckCommand;
|
|
159
161
|
}
|
|
162
|
+
function helpIssueTemplate(opts) {
|
|
163
|
+
if (!('issueTemplate' in opts))
|
|
164
|
+
return '';
|
|
165
|
+
return unindent `
|
|
166
|
+
Issue Template:
|
|
167
|
+
Use "--issue-template" to set the template to use when reporting issues.
|
|
168
|
+
|
|
169
|
+
The template is a string that can contain the following placeholders:
|
|
170
|
+
- $filename - the file name
|
|
171
|
+
- $col - the column number
|
|
172
|
+
- $row - the row number
|
|
173
|
+
- $text - the word that is misspelled
|
|
174
|
+
- $message - the issues message: "unknown word", "word is misspelled", etc.
|
|
175
|
+
- $messageColored - the issues message with color based upon the message type.
|
|
176
|
+
- $uri - the URI of the file
|
|
177
|
+
- $suggestions - suggestions for the misspelled word (if requested)
|
|
178
|
+
- $quickFix - possible quick fixes for the misspelled word.
|
|
179
|
+
- $contextFull - the full context of the misspelled word.
|
|
180
|
+
- $contextLeft - the context to the left of the misspelled word.
|
|
181
|
+
- $contextRight - the context to the right of the misspelled word.
|
|
182
|
+
|
|
183
|
+
Color is supported using the following template pattern:
|
|
184
|
+
- \`{<style[.style]> <text>}\` - where \`<style>\` is a style name and \`<text>\` is the text to style.
|
|
185
|
+
|
|
186
|
+
Styles
|
|
187
|
+
- \`bold\`, \`italic\`, \`underline\`, \`strikethrough\`, \`dim\`, \`inverse\`
|
|
188
|
+
- \`black\`, \`red\`, \`green\`, \`yellow\`, \`blue\`, \`magenta\`, \`cyan\`, \`white\`
|
|
189
|
+
|
|
190
|
+
Example:
|
|
191
|
+
--issue-template '{green $filename}:{yellow $row}:{yellow $col} $message {red $text} $quickFix {dim $suggestions}'
|
|
192
|
+
`;
|
|
193
|
+
}
|
|
160
194
|
/**
|
|
161
195
|
* Add additional help text to the command.
|
|
162
196
|
* When the verbose flag is set, show the hidden options.
|
|
@@ -166,7 +200,8 @@ export function commandLint(prog) {
|
|
|
166
200
|
function augmentCommandHelp(context) {
|
|
167
201
|
const output = [];
|
|
168
202
|
const command = context.command;
|
|
169
|
-
const
|
|
203
|
+
const opts = command.opts();
|
|
204
|
+
const showHidden = !!opts.verbose;
|
|
170
205
|
const hiddenHelp = [];
|
|
171
206
|
const help = command.createHelp();
|
|
172
207
|
const hiddenOptions = command.options.filter((opt) => opt.hidden && showHidden);
|
|
@@ -179,7 +214,7 @@ function augmentCommandHelp(context) {
|
|
|
179
214
|
hiddenHelp.push(help.wrap(` ${options.flags.padEnd(flagColWidth)} ${options.description}`, process.stdout.columns || 80, indent));
|
|
180
215
|
}
|
|
181
216
|
output.push(...hiddenHelp, advanced);
|
|
182
|
-
return output.join('\n');
|
|
217
|
+
return helpIssueTemplate(opts) + output.join('\n');
|
|
183
218
|
}
|
|
184
219
|
/**
|
|
185
220
|
* Create Option - a helper function to create a commander option.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Option as CommanderOption } from 'commander';
|
|
2
|
-
import * as App from './application.
|
|
2
|
+
import * as App from './application.mjs';
|
|
3
3
|
import { emitSuggestionResult } from './emitters/suggestionsEmitter.js';
|
|
4
4
|
import { CheckFailed } from './util/errors.js';
|
|
5
5
|
function collect(value, previous) {
|
package/dist/esm/commandTrace.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Option as CommanderOption } from 'commander';
|
|
2
|
-
import * as App from './application.
|
|
2
|
+
import * as App from './application.mjs';
|
|
3
|
+
import { console } from './console.js';
|
|
3
4
|
import { isDictionaryPathFormat } from './emitters/DictionaryPathFormat.js';
|
|
4
5
|
import { emitTraceResults } from './emitters/traceEmitter.js';
|
|
5
6
|
import { CheckFailed } from './util/errors.js';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { WriteStream } from 'node:tty';
|
|
2
|
+
type Log = (format?: any, ...params: any[]) => void;
|
|
3
|
+
type IOStream = NodeJS.WritableStream & Pick<WriteStream, 'isTTY' | 'rows' | 'columns'> & Pick<Partial<WriteStream>, 'hasColors' | 'clearLine' | 'getColorDepth'>;
|
|
4
|
+
export interface IConsole {
|
|
5
|
+
readonly log: Log;
|
|
6
|
+
readonly error: Log;
|
|
7
|
+
readonly info: Log;
|
|
8
|
+
readonly warn: Log;
|
|
9
|
+
readonly stderrChannel: Channel;
|
|
10
|
+
readonly stdoutChannel: Channel;
|
|
11
|
+
}
|
|
12
|
+
export declare const console: IConsole;
|
|
13
|
+
export declare function log(...p: Parameters<typeof console.log>): void;
|
|
14
|
+
export declare function error(...p: Parameters<typeof console.error>): void;
|
|
15
|
+
export interface Channel {
|
|
16
|
+
stream: IOStream;
|
|
17
|
+
write: (msg: string) => void;
|
|
18
|
+
writeLine: (msg: string) => void;
|
|
19
|
+
clearLine: (dir: -1 | 0 | 1, callback?: () => void) => boolean;
|
|
20
|
+
printLine: (format?: any, ...params: any[]) => void;
|
|
21
|
+
getColorLevel: () => 0 | 1 | 2 | 3;
|
|
22
|
+
}
|
|
23
|
+
export declare function getColorLevel(stream: IOStream): 0 | 1 | 2 | 3;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=console.d.ts.map
|