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.
Files changed (69) hide show
  1. package/README.md +78 -59
  2. package/dist/esm/app.mjs +4 -15
  3. package/dist/esm/application.d.mts +3 -1
  4. package/dist/esm/application.mjs +14 -6
  5. package/dist/esm/cli-reporter.js +2 -1
  6. package/dist/esm/commandConfig.d.ts +3 -0
  7. package/dist/esm/commandConfig.js +18 -0
  8. package/dist/esm/commandDictionaries.d.ts +3 -0
  9. package/dist/esm/commandDictionaries.js +40 -0
  10. package/dist/esm/commandHelpers.d.ts +18 -0
  11. package/dist/esm/commandHelpers.js +30 -0
  12. package/dist/esm/commandInit.d.ts +3 -0
  13. package/dist/esm/commandInit.js +25 -0
  14. package/dist/esm/commandLint.js +13 -26
  15. package/dist/esm/commandTrace.js +2 -0
  16. package/dist/esm/config/adjustConfig.d.ts +7 -0
  17. package/dist/esm/config/adjustConfig.js +137 -0
  18. package/dist/esm/config/config.d.ts +5 -0
  19. package/dist/esm/config/config.js +18 -0
  20. package/dist/esm/config/configInit.d.ts +3 -0
  21. package/dist/esm/config/configInit.js +104 -0
  22. package/dist/esm/config/constants.d.ts +17 -0
  23. package/dist/esm/config/constants.js +23 -0
  24. package/dist/esm/config/index.d.ts +3 -0
  25. package/dist/esm/config/index.js +2 -0
  26. package/dist/esm/config/options.d.ts +62 -0
  27. package/dist/esm/config/options.js +2 -0
  28. package/dist/esm/config/updateConfig.d.ts +3 -0
  29. package/dist/esm/config/updateConfig.js +2 -0
  30. package/dist/esm/dictionaries/index.d.ts +3 -0
  31. package/dist/esm/dictionaries/index.js +2 -0
  32. package/dist/esm/dictionaries/listDictionaries.d.ts +33 -0
  33. package/dist/esm/dictionaries/listDictionaries.js +131 -0
  34. package/dist/esm/emitters/dictionaryListEmitter.d.ts +19 -0
  35. package/dist/esm/emitters/dictionaryListEmitter.js +82 -0
  36. package/dist/esm/emitters/helpers.d.ts +14 -0
  37. package/dist/esm/emitters/helpers.js +67 -0
  38. package/dist/esm/emitters/traceEmitter.d.ts +1 -10
  39. package/dist/esm/emitters/traceEmitter.js +1 -69
  40. package/dist/esm/lint/LintRequest.d.ts +3 -2
  41. package/dist/esm/lint/LintRequest.js +41 -5
  42. package/dist/esm/lint/index.d.ts +1 -1
  43. package/dist/esm/lint/index.js +1 -1
  44. package/dist/esm/lint/lint.js +28 -66
  45. package/dist/esm/options.d.ts +101 -4
  46. package/dist/esm/options.js +1 -0
  47. package/dist/esm/pkgInfo.d.ts +1 -1
  48. package/dist/esm/pkgInfo.js +1 -1
  49. package/dist/esm/util/InMemoryReporter.d.ts +10 -7
  50. package/dist/esm/util/InMemoryReporter.js +20 -13
  51. package/dist/esm/util/LintFileResult.d.ts +14 -0
  52. package/dist/esm/util/LintFileResult.js +2 -0
  53. package/dist/esm/util/cache/CSpellLintResultCache.d.ts +3 -3
  54. package/dist/esm/util/cache/DiskCache.d.ts +4 -4
  55. package/dist/esm/util/configFileHelper.d.ts +1 -1
  56. package/dist/esm/util/configFileHelper.js +2 -2
  57. package/dist/esm/util/extractContext.d.ts +5 -0
  58. package/dist/esm/util/extractContext.js +75 -0
  59. package/dist/esm/util/fileHelper.d.ts +2 -11
  60. package/dist/esm/util/fileHelper.js +9 -1
  61. package/dist/esm/util/pad.d.ts +16 -0
  62. package/dist/esm/util/pad.js +61 -1
  63. package/dist/esm/util/reporters.d.ts +21 -5
  64. package/dist/esm/util/reporters.js +178 -31
  65. package/dist/esm/util/table.d.ts +31 -4
  66. package/dist/esm/util/table.js +76 -16
  67. package/dist/esm/util/util.d.ts +5 -0
  68. package/dist/esm/util/util.js +5 -0
  69. package/package.json +16 -15
@@ -1,6 +1,6 @@
1
- import { CSpellSettings } from '@cspell/cspell-types';
1
+ import { CSpellSettings, ReporterConfiguration } from '@cspell/cspell-types';
2
2
  import type { CacheOptions } from './util/cache/index.js';
3
- export interface LinterOptions extends Omit<BaseOptions, 'config'>, Omit<CacheOptions, 'version'> {
3
+ export interface LinterOptions extends Omit<BaseOptions, 'config'>, Omit<CacheOptions, 'version'>, ReporterConfiguration {
4
4
  /**
5
5
  * Display verbose information
6
6
  */
@@ -33,8 +33,8 @@ export interface LinterOptions extends Omit<BaseOptions, 'config'>, Omit<CacheOp
33
33
  dot?: boolean;
34
34
  /**
35
35
  * Show part of a line where an issue is found.
36
- * if true, it will show the default number of characters on either side.
37
- * if a number, it will shat number of characters on either side.
36
+ * - if true, it will show the default number of characters on either side.
37
+ * - if a number, the number of characters to show on either side of the issue.
38
38
  */
39
39
  showContext?: boolean | number;
40
40
  /**
@@ -75,10 +75,22 @@ export interface LinterOptions extends Omit<BaseOptions, 'config'>, Omit<CacheOp
75
75
  * Files must be found and processed otherwise it is considered an error.
76
76
  */
77
77
  mustFindFiles?: boolean;
78
+ /**
79
+ * List of dictionary names to use.
80
+ */
81
+ dictionary?: string[] | undefined;
82
+ /**
83
+ * List of dictionary names to disable.
84
+ */
85
+ disableDictionary?: string[] | undefined;
78
86
  /**
79
87
  * Stop processing and exit if an issue or error is found.
80
88
  */
81
89
  failFast?: boolean;
90
+ /**
91
+ * Keep going even if an error is found.
92
+ */
93
+ continueOnError?: boolean;
82
94
  /**
83
95
  * Optional list of reporters to use, overriding any specified in the
84
96
  * configuration.
@@ -94,11 +106,34 @@ export interface LinterOptions extends Omit<BaseOptions, 'config'>, Omit<CacheOp
94
106
  config?: string | CSpellConfigFile;
95
107
  }
96
108
  export interface TraceOptions extends BaseOptions {
109
+ /**
110
+ * Use stdin for the input.
111
+ */
97
112
  stdin?: boolean;
113
+ /**
114
+ * Enable the `allowCompoundWords` option.
115
+ */
98
116
  allowCompoundWords?: boolean;
117
+ /**
118
+ * Ignore case and accents when searching for words.
119
+ */
99
120
  ignoreCase?: boolean;
121
+ /**
122
+ * Show all dictionaries, not just the ones that contain the words or are enabled.
123
+ */
100
124
  all?: boolean;
125
+ /**
126
+ * Show only dictionaries that contain the words.
127
+ * If `all` is set, this option is ignored.
128
+ */
101
129
  onlyFound?: boolean;
130
+ /**
131
+ * Names of dictionaries to use.
132
+ */
133
+ dictionary?: string[] | undefined;
134
+ /**
135
+ * Configure how to display the dictionary path.
136
+ */
102
137
  dictionaryPath?: 'hide' | 'long' | 'short' | 'full';
103
138
  }
104
139
  export interface SuggestionOptions extends BaseOptions {
@@ -136,6 +171,51 @@ export interface SuggestionOptions extends BaseOptions {
136
171
  */
137
172
  repl?: boolean;
138
173
  }
174
+ export interface DictionariesOptions {
175
+ /**
176
+ * Path to configuration file.
177
+ */
178
+ config?: string;
179
+ /**
180
+ * Load the default configuration
181
+ * @default true
182
+ */
183
+ defaultConfiguration?: boolean;
184
+ /**
185
+ * Use color in the output.
186
+ * `true` to force color, `false` to turn off color.
187
+ * `undefined` to use color if the output is a TTY.
188
+ */
189
+ color?: boolean | undefined;
190
+ /**
191
+ * Show enabled:
192
+ * - `true` to show only enabled dictionaries.
193
+ * - `false` to show only disabled dictionaries.
194
+ * - `undefined` to show all dictionaries.
195
+ */
196
+ enabled?: boolean | undefined;
197
+ /**
198
+ * The locale to use when listing dictionaries.
199
+ */
200
+ locale?: string;
201
+ /**
202
+ * The file type to use when listing dictionaries.
203
+ */
204
+ fileType?: string;
205
+ /**
206
+ * show the language locales supported by the dictionary.
207
+ */
208
+ showLocales?: boolean;
209
+ /**
210
+ * show the file types supported by the dictionary.
211
+ */
212
+ showFileTypes?: boolean;
213
+ /**
214
+ * Dhow the location of the dictionary.
215
+ */
216
+ showLocation?: boolean;
217
+ pathFormat?: 'hide' | 'short' | 'long' | 'full';
218
+ }
139
219
  export interface LegacyOptions {
140
220
  local?: string;
141
221
  }
@@ -247,7 +327,24 @@ export interface LinterCliOptions extends LinterOptions {
247
327
  * @since 8.12.0
248
328
  */
249
329
  issueTemplate?: string;
330
+ /**
331
+ * Prevents searching for local configuration files
332
+ *
333
+ * When `--no-config-search` is passed on the command line, this will be `true`.
334
+ * If the flag is not passed, it defaults to `false`.
335
+ */
336
+ configSearch?: boolean;
337
+ /**
338
+ * Directory paths at which CSpell should stop searching for configuration files.
339
+ *
340
+ * These are set via one or more `--stop-config-search-at <dir>` CLI options.
341
+ * If no flags are passed, this will be `undefined`.
342
+ */
343
+ stopConfigSearchAt?: string[];
344
+ report?: ReportChoices | undefined;
250
345
  }
346
+ export type ReportChoices = 'all' | 'simple' | 'typos' | 'flagged';
347
+ export declare const ReportChoicesAll: readonly ReportChoices[];
251
348
  export declare function fixLegacy<T extends LegacyFixes>(opts: T & LegacyOptions): Omit<T & LegacyOptions, 'local'>;
252
349
  export interface CSpellConfigFile {
253
350
  url: URL;
@@ -1,3 +1,4 @@
1
+ export const ReportChoicesAll = ['all', 'simple', 'typos', 'flagged'];
1
2
  export function fixLegacy(opts) {
2
3
  const { local, ...rest } = opts;
3
4
  if (local && !rest.locale) {
@@ -1,6 +1,6 @@
1
1
  export { pkgDir } from './dirname.js';
2
2
  export declare const name = "cspell";
3
- export declare const version = "9.0.1";
3
+ export declare const version = "9.1.0";
4
4
  export declare const engines: {
5
5
  node: string;
6
6
  };
@@ -1,7 +1,7 @@
1
1
  // This file is generated by tools/patch-version.mjs
2
2
  export { pkgDir } from './dirname.js';
3
3
  export const name = 'cspell';
4
- export const version = '9.0.1';
4
+ export const version = '9.1.0';
5
5
  export const engines = { node: '>=20' };
6
6
  export const npmPackage = { name, version, engines };
7
7
  //# sourceMappingURL=pkgInfo.js.map
@@ -17,12 +17,15 @@ export declare class InMemoryReporter implements CSpellReporter, InMemoryResult
17
17
  progressCount: number;
18
18
  issues: Issue[];
19
19
  runResult: RunResult | undefined;
20
- issue: (issue: Issue) => void;
21
- error: (message: string, error: Error) => void;
22
- info: (message: string) => void;
23
- debug: (message: string) => void;
24
- progress: (p: ProgressItem) => void;
25
- result: (r: RunResult) => void;
26
- dump: () => InMemoryResult;
20
+ issue(issue: Issue): void;
21
+ error(message: string, error: Error): void;
22
+ info(message: string): void;
23
+ debug(message: string): void;
24
+ progress(p: ProgressItem): void;
25
+ result(r: RunResult): void;
26
+ dump(): InMemoryResult;
27
+ get features(): {
28
+ issueType: boolean;
29
+ };
27
30
  }
28
31
  //# sourceMappingURL=InMemoryReporter.d.ts.map
@@ -11,32 +11,39 @@ export class InMemoryReporter {
11
11
  progressCount = 0;
12
12
  issues = [];
13
13
  runResult;
14
- issue = (issue) => {
14
+ issue(issue) {
15
15
  this.issues.push(issue);
16
16
  this.issueCount += 1;
17
17
  const { uri, row, col, text } = issue;
18
18
  this.log.push(`Issue: ${uri}[${row}, ${col}]: Unknown word: ${text}`);
19
- };
20
- error = (message, error) => {
19
+ }
20
+ error(message, error) {
21
21
  this.errorCount += 1;
22
22
  this.errors.push(error);
23
23
  this.log.push(`Error: ${message} ${error.toString()}`);
24
- };
25
- info = (message) => {
24
+ }
25
+ info(message) {
26
26
  this.infoCount += 1;
27
27
  this.log.push(`Info: ${message}`);
28
- };
29
- debug = (message) => {
28
+ }
29
+ debug(message) {
30
30
  this.debugCount += 1;
31
31
  this.log.push(`Debug: ${message}`);
32
- };
33
- progress = (p) => {
32
+ }
33
+ progress(p) {
34
34
  this.progressCount += 1;
35
35
  this.log.push(`Progress: ${p.type} ${p.fileNum} ${p.fileCount} ${p.filename}`);
36
- };
37
- result = (r) => {
36
+ }
37
+ result(r) {
38
38
  this.runResult = r;
39
- };
40
- dump = () => ({ log: this.log, issues: this.issues, runResult: this.runResult });
39
+ }
40
+ dump() {
41
+ return { log: this.log, issues: this.issues, runResult: this.runResult };
42
+ }
43
+ get features() {
44
+ return {
45
+ issueType: true,
46
+ };
47
+ }
41
48
  }
42
49
  //# sourceMappingURL=InMemoryReporter.js.map
@@ -0,0 +1,14 @@
1
+ import { Issue, ReportIssueOptions } from '@cspell/cspell-types';
2
+ import { FileInfo, Perf } from './fileHelper.js';
3
+ export interface LintFileResult {
4
+ fileInfo: FileInfo;
5
+ processed: boolean;
6
+ issues: Issue[];
7
+ errors: number;
8
+ configErrors: number;
9
+ elapsedTimeMs: number | undefined;
10
+ perf?: Perf | undefined;
11
+ cached?: boolean;
12
+ reportIssueOptions?: ReportIssueOptions | undefined;
13
+ }
14
+ //# sourceMappingURL=LintFileResult.d.ts.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=LintFileResult.js.map
@@ -1,13 +1,13 @@
1
- import type { FileResult } from '../../util/fileHelper.js';
1
+ import type { LintFileResult } from '../LintFileResult.js';
2
2
  export interface CSpellLintResultCache {
3
3
  /**
4
4
  * Retrieve cached lint results for a given file name, if present in the cache.
5
5
  */
6
- getCachedLintResults(filename: string): Promise<FileResult | undefined>;
6
+ getCachedLintResults(filename: string): Promise<LintFileResult | undefined>;
7
7
  /**
8
8
  * Set the cached lint results.
9
9
  */
10
- setCachedLintResults(result: FileResult, dependsUponFiles: string[]): void;
10
+ setCachedLintResults(result: LintFileResult, dependsUponFiles: string[]): void;
11
11
  /**
12
12
  * Persists the in-memory cache to disk.
13
13
  */
@@ -1,7 +1,7 @@
1
- import type { FileResult } from '../../util/fileHelper.js';
1
+ import type { LintFileResult } from '../../util/LintFileResult.js';
2
2
  import type { CSpellLintResultCache } from './CSpellLintResultCache.js';
3
3
  import type { FileDescriptor } from './fileEntryCache.js';
4
- export type CachedFileResult = Omit<FileResult, 'fileInfo' | 'elapsedTimeMs' | 'cached'>;
4
+ export type CachedFileResult = Omit<LintFileResult, 'fileInfo' | 'elapsedTimeMs' | 'cached'>;
5
5
  /**
6
6
  * This is the data cached.
7
7
  * Property names are short to help keep the cache file size small.
@@ -41,8 +41,8 @@ export declare class DiskCache implements CSpellLintResultCache {
41
41
  private ocCacheFileResult;
42
42
  readonly version: string;
43
43
  constructor(cacheFileLocation: string, useCheckSum: boolean, cspellVersion: string, useUniversalCache: boolean);
44
- getCachedLintResults(filename: string): Promise<FileResult | undefined>;
45
- setCachedLintResults({ fileInfo, elapsedTimeMs: _, cached: __, ...result }: FileResult, dependsUponFiles: string[]): void;
44
+ getCachedLintResults(filename: string): Promise<LintFileResult | undefined>;
45
+ setCachedLintResults({ fileInfo, elapsedTimeMs: _, cached: __, ...result }: LintFileResult, dependsUponFiles: string[]): void;
46
46
  reconcile(): void;
47
47
  reset(): void;
48
48
  private normalizeResult;
@@ -10,6 +10,6 @@ export interface FileConfigInfo {
10
10
  text: string;
11
11
  languageIds: string[];
12
12
  }
13
- export declare function readConfig(configFile: string | CSpellConfigFile | undefined, root: string | undefined): Promise<ConfigInfo>;
13
+ export declare function readConfig(configFile: string | CSpellConfigFile | undefined, root: string | undefined, stopConfigSearchAt?: (URL | string)[] | undefined): Promise<ConfigInfo>;
14
14
  export declare function readConfigFile(filename: string | URL): Promise<CSpellConfigFile>;
15
15
  //# sourceMappingURL=configFileHelper.d.ts.map
@@ -2,13 +2,13 @@ import { toFilePathOrHref } from '@cspell/url';
2
2
  import * as cspell from 'cspell-lib';
3
3
  import { environmentKeys, getEnvironmentVariable } from '../environment.js';
4
4
  import { filenameToUrl } from './fileHelper.js';
5
- export async function readConfig(configFile, root) {
5
+ export async function readConfig(configFile, root, stopConfigSearchAt) {
6
6
  configFile ??= getEnvironmentVariable(environmentKeys.CSPELL_CONFIG_PATH);
7
7
  if (configFile) {
8
8
  const cfgFile = typeof configFile === 'string' ? await readConfigHandleError(configFile) : configFile;
9
9
  return configFileToConfigInfo(cfgFile);
10
10
  }
11
- const config = await cspell.searchForConfig(root);
11
+ const config = await cspell.searchForConfig(root, { stopSearchAt: stopConfigSearchAt });
12
12
  const defaultConfigFile = getEnvironmentVariable(environmentKeys.CSPELL_DEFAULT_CONFIG_PATH);
13
13
  if (!config && defaultConfigFile) {
14
14
  const cfgFile = await readConfigFile(defaultConfigFile).catch(() => undefined);
@@ -0,0 +1,5 @@
1
+ import type { TextDocumentOffset, TextOffset } from '@cspell/cspell-types';
2
+ export declare function fixOffsetToBeginningOfChar(text: string, offset: number): number;
3
+ export declare function lineContext(lineText: string, start: number, end: number, contextRange: number): TextOffset;
4
+ export declare function extractContext(tdo: Pick<TextDocumentOffset, 'line' | 'offset' | 'text'>, contextRange: number): TextOffset;
5
+ //# sourceMappingURL=extractContext.d.ts.map
@@ -0,0 +1,75 @@
1
+ export function fixOffsetToBeginningOfChar(text, offset) {
2
+ const code = text.charCodeAt(offset) || 0;
3
+ return offset + ((code & 0xfc00) === 0xdc00 ? 1 : 0);
4
+ }
5
+ function prefCharIndex(text, offset, count = 1) {
6
+ if (offset - count < 0)
7
+ return 0;
8
+ for (; count > 0 && offset > 0; count--) {
9
+ let code = text.charCodeAt(--offset) || 0;
10
+ if (code === 0xfe0f) {
11
+ // Remove zero-width joiner
12
+ code = text.charCodeAt(--offset) || 0;
13
+ }
14
+ offset -= (code & 0xfc00) === 0xdc00 ? 1 : 0;
15
+ }
16
+ return offset < 0 ? 0 : offset;
17
+ }
18
+ function nextCharIndex(text, offset, count = 1) {
19
+ if (offset + count >= text.length)
20
+ return text.length;
21
+ for (; count > 0 && offset < text.length; count--) {
22
+ const code = text.charCodeAt(offset++) || 0;
23
+ offset += (code & 0xfc00) === 0xd800 ? 1 : 0;
24
+ if (text.charCodeAt(offset) === 0xfe0f) {
25
+ // Skip zero-width joiner
26
+ offset++;
27
+ }
28
+ }
29
+ return offset > text.length ? text.length : offset;
30
+ }
31
+ export function lineContext(lineText, start, end, contextRange) {
32
+ let left = prefCharIndex(lineText, start, contextRange);
33
+ let right = nextCharIndex(lineText, end, contextRange);
34
+ const isLetter = /^\p{L}$/u;
35
+ const isMark = /^\p{M}$/u;
36
+ for (let n = contextRange / 2; n > 0 && left > 0; n--, left--) {
37
+ const c = lineText[left - 1];
38
+ if (isMark.test(c)) {
39
+ if (!isLetter.test(lineText[left - 2])) {
40
+ break;
41
+ }
42
+ left--;
43
+ continue;
44
+ }
45
+ if (!isLetter.test(lineText[left - 1])) {
46
+ break;
47
+ }
48
+ }
49
+ for (let n = contextRange / 2; n > 0 && right < lineText.length; n--, right++) {
50
+ if (!isLetter.test(lineText[right])) {
51
+ break;
52
+ }
53
+ if (isMark.test(lineText[right + 1])) {
54
+ right++;
55
+ }
56
+ }
57
+ left = left < 0 ? 0 : left;
58
+ const t0 = lineText.slice(left, right);
59
+ const tLeft = t0.trimStart();
60
+ left = Math.min(left + t0.length - tLeft.length, start);
61
+ const text = tLeft.trimEnd();
62
+ const context = {
63
+ text,
64
+ offset: left,
65
+ };
66
+ return context;
67
+ }
68
+ export function extractContext(tdo, contextRange) {
69
+ const { line, offset, text } = tdo;
70
+ const start = offset - line.offset;
71
+ const context = lineContext(line.text, start, start + text.length, contextRange);
72
+ context.offset += line.offset;
73
+ return context;
74
+ }
75
+ //# sourceMappingURL=extractContext.js.map
@@ -1,5 +1,5 @@
1
1
  import type { BufferEncoding } from 'cspell-io';
2
- import type { Document, Issue } from 'cspell-lib';
2
+ import type { Document } from 'cspell-lib';
3
3
  import * as cspell from 'cspell-lib';
4
4
  import type { GlobOptions } from './glob.js';
5
5
  export interface FileInfo {
@@ -8,16 +8,6 @@ export interface FileInfo {
8
8
  errorCode?: string;
9
9
  }
10
10
  export type Perf = cspell.SpellCheckFilePerf;
11
- export interface FileResult {
12
- fileInfo: FileInfo;
13
- processed: boolean;
14
- issues: Issue[];
15
- errors: number;
16
- configErrors: number;
17
- elapsedTimeMs: number | undefined;
18
- perf?: Perf | undefined;
19
- cached?: boolean;
20
- }
21
11
  export declare function fileInfoToDocument(fileInfo: FileInfo, languageId: string | undefined, locale: string | undefined): Document;
22
12
  export declare function filenameToUrl(filename: string | URL, cwd?: string): URL;
23
13
  export declare function filenameToUri(filename: string, cwd?: string): URL;
@@ -50,4 +40,5 @@ export declare function readFileListFile(listFile: string): Promise<string[]>;
50
40
  export declare function isFile(filename: string): Promise<boolean>;
51
41
  export declare function isDir(filename: string): Promise<boolean>;
52
42
  export declare function isNotDir(filename: string): Promise<boolean>;
43
+ export declare function relativeToCwd(filename: string | URL, cwd?: string | URL): string;
53
44
  //# sourceMappingURL=fileHelper.d.ts.map
@@ -2,7 +2,7 @@ import { promises as fsp } from 'node:fs';
2
2
  import * as path from 'node:path';
3
3
  import streamConsumers from 'node:stream/consumers';
4
4
  import { fileURLToPath } from 'node:url';
5
- import { toFileDirURL, toFileURL } from '@cspell/url';
5
+ import { toFileDirURL, toFilePathOrHref, toFileURL, urlRelative } from '@cspell/url';
6
6
  import { readFileText as cioReadFile, toURL } from 'cspell-io';
7
7
  import { fileToDocument, isBinaryFile as isUriBinaryFile } from 'cspell-lib';
8
8
  import { asyncAwait, asyncFlatten, asyncMap, asyncPipe, mergeAsyncIterables } from './async.js';
@@ -154,4 +154,12 @@ export async function isDir(filename) {
154
154
  export function isNotDir(filename) {
155
155
  return isDir(filename).then((a) => !a);
156
156
  }
157
+ export function relativeToCwd(filename, cwd = process.cwd()) {
158
+ const urlCwd = toFileDirURL(cwd);
159
+ const url = toFileURL(filename, urlCwd);
160
+ const rel = urlRelative(urlCwd, url);
161
+ if (rel.startsWith('..'))
162
+ return toFilePathOrHref(url);
163
+ return rel;
164
+ }
157
165
  //# sourceMappingURL=fileHelper.js.map
@@ -3,4 +3,20 @@ export declare function padWidth(s: string, target: number): number;
3
3
  export declare function padLeft(s: string, w: number): string;
4
4
  export declare function width(s: string): number;
5
5
  export declare function ansiWidth(s: string): number;
6
+ /**
7
+ * Prune the end of a string to fit within a specified width, adding an ellipsis if necessary.
8
+ * @param str - the text to prune - ANSI is not supported
9
+ * @param maxWidth - the maximum width of the text
10
+ * @param pad - the string to use for padding, default is '…'
11
+ * @returns the pruned text
12
+ */
13
+ export declare function pruneTextEnd(str: string, maxWidth: number | undefined, pad?: string): string;
14
+ /**
15
+ * Prune the start of a string to fit within a specified width, adding an ellipsis if necessary.
16
+ * @param str - the text to prune - ANSI is not supported
17
+ * @param maxWidth - the maximum width of the text
18
+ * @param pad - the string to use for padding, default is '…'
19
+ * @returns the pruned text
20
+ */
21
+ export declare function pruneTextStart(str: string, maxWidth: number | undefined, pad?: string): string;
6
22
  //# sourceMappingURL=pad.d.ts.map
@@ -20,9 +20,69 @@ export function width(s) {
20
20
  return (s
21
21
  // eslint-disable-next-line no-control-regex, no-misleading-character-class
22
22
  .replaceAll(/[\u0000-\u001F\u0300-\u036F]/g, '')
23
- .replaceAll(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, '.').length);
23
+ .replaceAll(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, '.')
24
+ .replaceAll('…', '.')
25
+ .replaceAll(/\p{M}/gu, '').length);
24
26
  }
25
27
  export function ansiWidth(s) {
26
28
  return width(stripVTControlCharacters(s));
27
29
  }
30
+ /**
31
+ * Prune the end of a string to fit within a specified width, adding an ellipsis if necessary.
32
+ * @param str - the text to prune - ANSI is not supported
33
+ * @param maxWidth - the maximum width of the text
34
+ * @param pad - the string to use for padding, default is '…'
35
+ * @returns the pruned text
36
+ */
37
+ export function pruneTextEnd(str, maxWidth, pad = '…') {
38
+ if (!maxWidth || maxWidth <= 0)
39
+ return str;
40
+ if (str.length <= maxWidth)
41
+ return str;
42
+ const padWidth = width(pad);
43
+ const maxWidthWithPad = maxWidth - padWidth;
44
+ const letters = [...str];
45
+ let len = 0;
46
+ for (let i = 0; i < letters.length; i++) {
47
+ const c = letters[i];
48
+ len += width(c);
49
+ if (len > maxWidthWithPad) {
50
+ let j = i + 1;
51
+ while (j < letters.length && width(letters[j]) === 0) {
52
+ ++j;
53
+ }
54
+ return j === letters.length ? str : letters.slice(0, i).join('') + pad;
55
+ }
56
+ }
57
+ return str;
58
+ }
59
+ /**
60
+ * Prune the start of a string to fit within a specified width, adding an ellipsis if necessary.
61
+ * @param str - the text to prune - ANSI is not supported
62
+ * @param maxWidth - the maximum width of the text
63
+ * @param pad - the string to use for padding, default is '…'
64
+ * @returns the pruned text
65
+ */
66
+ export function pruneTextStart(str, maxWidth, pad = '…') {
67
+ if (!maxWidth || maxWidth <= 0)
68
+ return str;
69
+ if (str.length <= maxWidth)
70
+ return str;
71
+ const padWidth = width(pad);
72
+ const maxWidthWithPad = maxWidth - padWidth;
73
+ const letters = [...str];
74
+ let len = 0;
75
+ for (let i = letters.length - 1; i >= 1; i--) {
76
+ const c = letters[i];
77
+ len += width(c);
78
+ if (len > maxWidthWithPad) {
79
+ i += 1;
80
+ while (i < letters.length && width(letters[i]) === 0) {
81
+ ++i;
82
+ }
83
+ return pad + letters.slice(i).join('');
84
+ }
85
+ }
86
+ return str;
87
+ }
28
88
  //# sourceMappingURL=pad.js.map
@@ -1,9 +1,6 @@
1
- import type { CSpellReporter, FileSettings, ReporterConfiguration } from '@cspell/cspell-types';
1
+ import { type CSpellReporter, type CSpellSettings, type FeaturesSupportedByReporter, type FileSettings, type Issue, type ReporterConfiguration, type ReportIssueOptions, type RunResult } from '@cspell/cspell-types';
2
+ import { LintFileResult } from './LintFileResult.js';
2
3
  export type FinalizedReporter = Required<CSpellReporter>;
3
- /**
4
- * Mergers several cspell reporters into a single one
5
- */
6
- export declare function mergeReporters(...reporters: ReadonlyArray<CSpellReporter>): FinalizedReporter;
7
4
  /**
8
5
  * Loads reporter modules configured in cspell config file
9
6
  */
@@ -11,4 +8,23 @@ export declare function loadReporters(reporters: FileSettings['reporters'], defa
11
8
  export declare function finalizeReporter(reporter: undefined): undefined;
12
9
  export declare function finalizeReporter(reporter: CSpellReporter): FinalizedReporter;
13
10
  export declare function finalizeReporter(reporter: CSpellReporter | undefined): FinalizedReporter | undefined;
11
+ export declare function extractReporterIssueOptions(settings: CSpellSettings | ReportIssueOptions): ReportIssueOptions;
12
+ export declare function mergeReportIssueOptions(a: ReportIssueOptions | CSpellSettings, b: ReportIssueOptions | undefined): ReportIssueOptions;
13
+ export declare class LintReporter {
14
+ #private;
15
+ readonly defaultReporter: CSpellReporter;
16
+ constructor(defaultReporter: CSpellReporter, config: ReporterConfiguration);
17
+ get config(): ReporterConfiguration;
18
+ set config(config: ReporterConfiguration);
19
+ issue(issue: Issue, reportOptions?: ReportIssueOptions): void;
20
+ info(...params: Parameters<FinalizedReporter['info']>): void;
21
+ debug(...params: Parameters<FinalizedReporter['debug']>): void;
22
+ error(...params: Parameters<FinalizedReporter['error']>): void;
23
+ progress(...params: Parameters<FinalizedReporter['progress']>): void;
24
+ result(result: RunResult): Promise<void>;
25
+ get features(): FeaturesSupportedByReporter;
26
+ loadReportersAndFinalize(reporters: FileSettings['reporters']): Promise<void>;
27
+ emitProgressBegin(filename: string, fileNum: number, fileCount: number): void;
28
+ emitProgressComplete(filename: string, fileNum: number, fileCount: number, result: LintFileResult): number;
29
+ }
14
30
  //# sourceMappingURL=reporters.d.ts.map