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,137 @@
|
|
|
1
|
+
import assert from 'node:assert';
|
|
2
|
+
import { promises as fs } from 'node:fs';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { toFileDirURL, urlRelative } from '@cspell/url';
|
|
6
|
+
import { isCfgArrayNode, MutableCSpellConfigFile } from 'cspell-config-lib';
|
|
7
|
+
import { toError } from '../util/errors.js';
|
|
8
|
+
async function fileExists(url) {
|
|
9
|
+
if (url.protocol !== 'file:') {
|
|
10
|
+
return false; // Only check file URLs
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
const stats = await fs.stat(url);
|
|
14
|
+
return stats.isFile();
|
|
15
|
+
}
|
|
16
|
+
catch (e) {
|
|
17
|
+
const err = toError(e);
|
|
18
|
+
if (err.code === 'ENOENT')
|
|
19
|
+
return false;
|
|
20
|
+
throw e;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export async function resolveImports(configFile, imports) {
|
|
24
|
+
const fromConfigDir = new URL('./', configFile.url);
|
|
25
|
+
const fromCurrentDir = toFileDirURL('./');
|
|
26
|
+
const require = createRequire(fromConfigDir);
|
|
27
|
+
function isPackageName(name) {
|
|
28
|
+
try {
|
|
29
|
+
require.resolve(name, { paths: [fileURLToPath(fromConfigDir)] });
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const _imports = [];
|
|
37
|
+
for (const imp of imports) {
|
|
38
|
+
const url = new URL(imp, fromCurrentDir);
|
|
39
|
+
if (url.protocol !== 'file:') {
|
|
40
|
+
_imports.push(imp);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (await fileExists(url)) {
|
|
44
|
+
let rel = urlRelative(fromConfigDir, url);
|
|
45
|
+
if (!(rel.startsWith('./') || rel.startsWith('../'))) {
|
|
46
|
+
rel = './' + rel; // Ensure relative path starts with './' or '../'
|
|
47
|
+
}
|
|
48
|
+
_imports.push(rel);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (url.protocol !== 'file:') {
|
|
52
|
+
_imports.push(url.href);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (isPackageName(imp)) {
|
|
56
|
+
_imports.push(imp);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
throw new Error(`Cannot resolve import: ${imp}`);
|
|
60
|
+
}
|
|
61
|
+
return _imports;
|
|
62
|
+
}
|
|
63
|
+
function addImportsToMutableConfigFile(configFile, resolvedImports, comment) {
|
|
64
|
+
let importNode = configFile.getNode('import', []);
|
|
65
|
+
if (importNode.type === 'scalar') {
|
|
66
|
+
configFile.setValue('import', [importNode.value]);
|
|
67
|
+
importNode = configFile.getNode('import', []);
|
|
68
|
+
}
|
|
69
|
+
assert(isCfgArrayNode(importNode));
|
|
70
|
+
const knownImports = new Set(importNode.value);
|
|
71
|
+
for (const imp of resolvedImports) {
|
|
72
|
+
if (knownImports.has(imp))
|
|
73
|
+
continue;
|
|
74
|
+
importNode.push(imp);
|
|
75
|
+
}
|
|
76
|
+
if (comment) {
|
|
77
|
+
configFile.setComment('import', comment);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
export async function addImportsToConfigFile(configFile, imports, comment) {
|
|
81
|
+
const resolvedImports = await resolveImports(configFile, imports);
|
|
82
|
+
if (configFile instanceof MutableCSpellConfigFile) {
|
|
83
|
+
return addImportsToMutableConfigFile(configFile, resolvedImports, comment);
|
|
84
|
+
}
|
|
85
|
+
const settings = configFile.settings;
|
|
86
|
+
let importNode = settings.import;
|
|
87
|
+
if (!Array.isArray(importNode)) {
|
|
88
|
+
importNode = typeof importNode === 'string' ? [importNode] : [];
|
|
89
|
+
settings.import = importNode;
|
|
90
|
+
if (comment) {
|
|
91
|
+
configFile.setComment('import', comment);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
assert(Array.isArray(importNode));
|
|
95
|
+
const knownImports = new Set(importNode);
|
|
96
|
+
for (const imp of resolvedImports) {
|
|
97
|
+
if (knownImports.has(imp))
|
|
98
|
+
continue;
|
|
99
|
+
importNode.push(imp);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
export function setConfigFieldValue(configFile, key, value, comment) {
|
|
103
|
+
configFile.setValue(key, value);
|
|
104
|
+
if (comment !== undefined) {
|
|
105
|
+
configFile.setComment(key, comment);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
export function addDictionariesToConfigFile(configFile, dictionaries, comment) {
|
|
109
|
+
if (configFile instanceof MutableCSpellConfigFile) {
|
|
110
|
+
const found = configFile.getValue('dictionaries');
|
|
111
|
+
const dicts = configFile.getNode('dictionaries', []);
|
|
112
|
+
assert(isCfgArrayNode(dicts));
|
|
113
|
+
const knownDicts = new Set(dicts.value);
|
|
114
|
+
for (const dict of dictionaries) {
|
|
115
|
+
if (!knownDicts.has(dict)) {
|
|
116
|
+
dicts.push(dict);
|
|
117
|
+
knownDicts.add(dict);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (!found && comment) {
|
|
121
|
+
// Set the comment on the field, not the list.
|
|
122
|
+
configFile.setComment('dictionaries', comment);
|
|
123
|
+
}
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const settings = configFile.settings;
|
|
127
|
+
const dicts = settings.dictionaries || [];
|
|
128
|
+
const knownDicts = new Set(dicts);
|
|
129
|
+
for (const dict of dictionaries) {
|
|
130
|
+
if (!knownDicts.has(dict)) {
|
|
131
|
+
dicts.push(dict);
|
|
132
|
+
knownDicts.add(dict);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
setConfigFieldValue(configFile, 'dictionaries', dicts, comment);
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=adjustConfig.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { CSpellSettings } from '@cspell/cspell-types';
|
|
2
|
+
import type { CSpellConfigFile } from 'cspell-config-lib';
|
|
3
|
+
import type { CommentConfig } from './constants.js';
|
|
4
|
+
export declare function applyValuesToConfigFile(config: CSpellConfigFile, settings: CSpellSettings, defaultValues: CommentConfig, addComments: boolean): CSpellConfigFile;
|
|
5
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { setConfigFieldValue } from './adjustConfig.js';
|
|
2
|
+
export function applyValuesToConfigFile(config, settings, defaultValues, addComments) {
|
|
3
|
+
const currentSettings = config.settings || {};
|
|
4
|
+
for (const [k, entry] of Object.entries(defaultValues)) {
|
|
5
|
+
const { value: defaultValue, comment } = entry;
|
|
6
|
+
const key = k;
|
|
7
|
+
const newValue = settings[key];
|
|
8
|
+
const oldValue = currentSettings[key];
|
|
9
|
+
const value = newValue ?? oldValue ?? defaultValue;
|
|
10
|
+
if ((newValue === undefined && oldValue !== undefined) || value === undefined) {
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
const useComment = (addComments && oldValue === undefined && comment) || undefined;
|
|
14
|
+
setConfigFieldValue(config, key, value, useComment);
|
|
15
|
+
}
|
|
16
|
+
return config;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import { toFileDirURL, toFileURL } from '@cspell/url';
|
|
3
|
+
import { createReaderWriter, cspellConfigFileSchema, } from 'cspell-config-lib';
|
|
4
|
+
import { console } from '../console.js';
|
|
5
|
+
import { addDictionariesToConfigFile, addImportsToConfigFile } from './adjustConfig.js';
|
|
6
|
+
import { applyValuesToConfigFile } from './config.js';
|
|
7
|
+
import { defaultConfig } from './constants.js';
|
|
8
|
+
const schemaRef = cspellConfigFileSchema;
|
|
9
|
+
const defaultConfigJson = `\
|
|
10
|
+
{
|
|
11
|
+
}
|
|
12
|
+
`;
|
|
13
|
+
const defaultConfigYaml = `
|
|
14
|
+
`;
|
|
15
|
+
export async function configInit(options) {
|
|
16
|
+
const rw = createReaderWriter();
|
|
17
|
+
const url = determineFileNameURL(options);
|
|
18
|
+
const configFile = await createConfigFile(rw, url, options);
|
|
19
|
+
await applyOptionsToConfigFile(configFile, options);
|
|
20
|
+
await fs.mkdir(new URL('./', configFile.url), { recursive: true });
|
|
21
|
+
if (options.stdout) {
|
|
22
|
+
console.stdoutChannel.write(rw.serialize(configFile));
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
await rw.writeConfig(configFile);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async function applyOptionsToConfigFile(configFile, options) {
|
|
29
|
+
const settings = {};
|
|
30
|
+
const addComments = options.comments ||
|
|
31
|
+
(options.comments === undefined && !options.removeComments && !configFile.url.pathname.endsWith('.json'));
|
|
32
|
+
if (options.comments === false) {
|
|
33
|
+
configFile.removeAllComments();
|
|
34
|
+
}
|
|
35
|
+
if (options.schema ?? true) {
|
|
36
|
+
configFile.setSchema(schemaRef);
|
|
37
|
+
}
|
|
38
|
+
if (options.locale) {
|
|
39
|
+
settings.language = options.locale;
|
|
40
|
+
}
|
|
41
|
+
applyValuesToConfigFile(configFile, settings, defaultConfig, addComments);
|
|
42
|
+
if (options.import) {
|
|
43
|
+
await addImportsToConfigFile(configFile, options.import, (addComments && defaultConfig.import?.comment) || undefined);
|
|
44
|
+
}
|
|
45
|
+
if (options.dictionary) {
|
|
46
|
+
addDictionariesToConfigFile(configFile, options.dictionary, (addComments && defaultConfig.dictionaries?.comment) || undefined);
|
|
47
|
+
}
|
|
48
|
+
return configFile;
|
|
49
|
+
}
|
|
50
|
+
function determineFileNameURL(options) {
|
|
51
|
+
if (options.config) {
|
|
52
|
+
return toFileURL(options.config);
|
|
53
|
+
}
|
|
54
|
+
const defaultFileName = determineDefaultFileName(options);
|
|
55
|
+
const outputUrl = toFileURL(options.output || defaultFileName);
|
|
56
|
+
const path = outputUrl.pathname;
|
|
57
|
+
if (path.endsWith('.json') || path.endsWith('.jsonc') || path.endsWith('.yaml') || path.endsWith('.yml')) {
|
|
58
|
+
return outputUrl;
|
|
59
|
+
}
|
|
60
|
+
if (/\.{m,c}?{j,t}s$/.test(path)) {
|
|
61
|
+
throw new Error(`Unsupported file extension: ${path}`);
|
|
62
|
+
}
|
|
63
|
+
return new URL(defaultFileName, toFileDirURL(outputUrl));
|
|
64
|
+
}
|
|
65
|
+
function determineDefaultFileName(options) {
|
|
66
|
+
switch (options.format || 'yaml') {
|
|
67
|
+
case 'json': {
|
|
68
|
+
return 'cspell.json';
|
|
69
|
+
}
|
|
70
|
+
case 'jsonc': {
|
|
71
|
+
return 'cspell.jsonc';
|
|
72
|
+
}
|
|
73
|
+
case 'yaml': {
|
|
74
|
+
return 'cspell.config.yaml';
|
|
75
|
+
}
|
|
76
|
+
case 'yml': {
|
|
77
|
+
return 'cspell.config.yml';
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
throw new Error(`Unsupported format: ${options.format}`);
|
|
81
|
+
}
|
|
82
|
+
function getDefaultContent(options) {
|
|
83
|
+
switch (options.format) {
|
|
84
|
+
case undefined:
|
|
85
|
+
case 'yaml': {
|
|
86
|
+
return defaultConfigYaml;
|
|
87
|
+
}
|
|
88
|
+
case 'json':
|
|
89
|
+
case 'jsonc': {
|
|
90
|
+
return defaultConfigJson;
|
|
91
|
+
}
|
|
92
|
+
default: {
|
|
93
|
+
throw new Error(`Unsupported format: ${options.format}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
async function createConfigFile(rw, url, options) {
|
|
98
|
+
if (url.pathname.endsWith('package.json')) {
|
|
99
|
+
return rw.readConfig(url);
|
|
100
|
+
}
|
|
101
|
+
const content = await fs.readFile(url, 'utf8').catch(() => getDefaultContent(options));
|
|
102
|
+
return rw.parse({ url, content });
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=configInit.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { CSpellSettings } from '@cspell/cspell-types';
|
|
2
|
+
export declare const defaultConfig: CommentConfig;
|
|
3
|
+
export interface ConfigEntry<T, K extends keyof T> {
|
|
4
|
+
key?: K;
|
|
5
|
+
value: T[K];
|
|
6
|
+
comment?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ApplyToConfigEntry<T, K extends keyof T> extends ConfigEntry<T, K> {
|
|
9
|
+
update?: (prev: T[K], next: T[K]) => T[K];
|
|
10
|
+
}
|
|
11
|
+
export type CommentConfig = {
|
|
12
|
+
[K in keyof CSpellSettings]?: ConfigEntry<CSpellSettings, K>;
|
|
13
|
+
};
|
|
14
|
+
export type ApplyToConfig<T = CSpellSettings> = {
|
|
15
|
+
[K in keyof T]?: ApplyToConfigEntry<T, K>;
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const defaultConfig = {
|
|
2
|
+
$schema: { value: undefined, comment: ' The schema for the configuration file.' },
|
|
3
|
+
version: { value: '0.2', comment: ' The version of the configuration file format.' },
|
|
4
|
+
name: { value: undefined, comment: ' The name of the configuration. Use for display purposes only.' },
|
|
5
|
+
description: { value: undefined, comment: ' A description of the configuration.' },
|
|
6
|
+
language: { value: 'en', comment: ' The locale to use when spell checking. (e.g., en, en-GB, de-DE' },
|
|
7
|
+
import: { value: undefined, comment: ' Configuration or packages to import.' },
|
|
8
|
+
dictionaryDefinitions: { value: undefined, comment: ' Define user dictionaries.' },
|
|
9
|
+
dictionaries: { value: undefined, comment: ' Enable the dictionaries.' },
|
|
10
|
+
ignorePaths: { value: undefined, comment: ' Glob patterns of files to be skipped.' },
|
|
11
|
+
files: { value: undefined, comment: ' Glob patterns of files to be included.' },
|
|
12
|
+
words: { value: undefined, comment: ' Words to be considered correct.' },
|
|
13
|
+
ignoreWords: { value: undefined, comment: ' Words to be ignored.' },
|
|
14
|
+
flagWords: { value: undefined, comment: ' Words to be flagged as incorrect.' },
|
|
15
|
+
overrides: { value: undefined, comment: ' Set configuration based upon file globs.' },
|
|
16
|
+
languageSettings: { value: undefined, comment: ' Define language specific settings.' },
|
|
17
|
+
enabledFileTypes: { value: undefined, comment: ' Enable for specific file types.' },
|
|
18
|
+
caseSensitive: { value: undefined, comment: ' Enable case sensitive spell checking.' },
|
|
19
|
+
patterns: { value: undefined, comment: ' Regular expression patterns.' },
|
|
20
|
+
ignoreRegExpList: { value: undefined, comment: ' Regular expressions / patterns of text to be ignored.' },
|
|
21
|
+
includeRegExpList: { value: undefined, comment: ' Regular expressions / patterns of text to be included.' },
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export interface BaseConfigOptions {
|
|
2
|
+
/**
|
|
3
|
+
* The path to the configuration file to create / update.
|
|
4
|
+
* If not provided, a default file name will be used based on the format.
|
|
5
|
+
*/
|
|
6
|
+
config?: string;
|
|
7
|
+
/**
|
|
8
|
+
* The list of configuration files or dictionary packages to import.
|
|
9
|
+
* This can be a list of file paths, package names, or URLs.
|
|
10
|
+
*/
|
|
11
|
+
import?: string[];
|
|
12
|
+
/**
|
|
13
|
+
* The locale to use when spell checking (e.g., en, en-US, de).
|
|
14
|
+
*/
|
|
15
|
+
locale?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Whether to add comments to the configuration file.
|
|
18
|
+
* - `true` - comments will be added to the configuration file.
|
|
19
|
+
* - `false` - no comments will be added.
|
|
20
|
+
* - `undefined` - the default behavior will be used based on the format.
|
|
21
|
+
*/
|
|
22
|
+
comments?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Whether to remove all comments from the configuration file.
|
|
25
|
+
* - `true` - all comments will be removed.
|
|
26
|
+
* - `false` | `undefined` - no comments will be removed.
|
|
27
|
+
* @implies `comments: false`
|
|
28
|
+
*/
|
|
29
|
+
removeComments?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Whether to add the schema reference to the configuration file.
|
|
32
|
+
* - `true` - the schema reference will be added / updated.
|
|
33
|
+
* - `false` - no schema reference will be added.
|
|
34
|
+
*/
|
|
35
|
+
schema?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* The list of dictionaries to enable in the configuration file.
|
|
38
|
+
* These are added to an existing configuration file or a new one.
|
|
39
|
+
* Existing dictionaries will not be removed.
|
|
40
|
+
*/
|
|
41
|
+
dictionary?: string[];
|
|
42
|
+
/**
|
|
43
|
+
* Whether to write the configuration to stdout instead of a file.
|
|
44
|
+
*/
|
|
45
|
+
stdout?: boolean;
|
|
46
|
+
}
|
|
47
|
+
export interface InitOptions extends BaseConfigOptions {
|
|
48
|
+
/**
|
|
49
|
+
* The path where the configuration file will be written, it can be a file path or a URL.
|
|
50
|
+
* If not provided, a default file name will be used based on the format.
|
|
51
|
+
* The default will be `cspell.config.yaml` or `cspell.json` based on the format.
|
|
52
|
+
* @conflicts `config` - If `config` is provided, it will be used instead of `output`.
|
|
53
|
+
*/
|
|
54
|
+
output?: string;
|
|
55
|
+
/**
|
|
56
|
+
* The format of the configuration file.
|
|
57
|
+
* @conflicts `config` - If `config` is provided, the format will be inferred from the file extension.
|
|
58
|
+
*/
|
|
59
|
+
format?: 'yaml' | 'yml' | 'json' | 'jsonc';
|
|
60
|
+
}
|
|
61
|
+
export type UpdateConfigOptions = BaseConfigOptions;
|
|
62
|
+
//# sourceMappingURL=options.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { DictionariesOptions } from '../options.js';
|
|
2
|
+
export interface ListDictionariesResult {
|
|
3
|
+
/**
|
|
4
|
+
* The name of the dictionary.
|
|
5
|
+
*/
|
|
6
|
+
name: string;
|
|
7
|
+
/**
|
|
8
|
+
* The description of the dictionary.
|
|
9
|
+
*/
|
|
10
|
+
description?: string | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* The path to the dictionary file.
|
|
13
|
+
*/
|
|
14
|
+
path?: string | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* True if the dictionary is enabled.
|
|
17
|
+
*/
|
|
18
|
+
enabled: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* The inline dictionaries supported by the dictionary.
|
|
21
|
+
*/
|
|
22
|
+
inline?: string[] | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* the languages locales supported by the dictionary.
|
|
25
|
+
*/
|
|
26
|
+
locales?: string[] | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* The file types supported by the dictionary.
|
|
29
|
+
*/
|
|
30
|
+
fileTypes?: string[] | undefined;
|
|
31
|
+
}
|
|
32
|
+
export declare function listDictionaries(options: DictionariesOptions): Promise<ListDictionariesResult[]>;
|
|
33
|
+
//# sourceMappingURL=listDictionaries.d.ts.map
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { combineTextAndLanguageSettings, getDefaultSettings, getGlobalSettingsAsync, mergeSettings } from 'cspell-lib';
|
|
2
|
+
import { readConfig } from '../util/configFileHelper.js';
|
|
3
|
+
const inlineDictionaries = {
|
|
4
|
+
'[words]': {
|
|
5
|
+
name: '[words]',
|
|
6
|
+
description: 'List of words to be included in the spell check.',
|
|
7
|
+
enabled: true,
|
|
8
|
+
},
|
|
9
|
+
'[flagWords]': {
|
|
10
|
+
name: '[flagWords]',
|
|
11
|
+
description: 'List of words to be flagged as incorrect.',
|
|
12
|
+
enabled: true,
|
|
13
|
+
},
|
|
14
|
+
'[ignoreWords]': {
|
|
15
|
+
name: '[ignoreWords]',
|
|
16
|
+
description: 'List of words to be ignored in the spell check.',
|
|
17
|
+
enabled: true,
|
|
18
|
+
},
|
|
19
|
+
'[suggestWords]': {
|
|
20
|
+
name: '[suggestWords]',
|
|
21
|
+
description: 'List of spelling suggestions for words.',
|
|
22
|
+
enabled: true,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
function splitList(list) {
|
|
26
|
+
if (!list)
|
|
27
|
+
return [];
|
|
28
|
+
if (typeof list === 'string') {
|
|
29
|
+
return list
|
|
30
|
+
.split(',')
|
|
31
|
+
.map((s) => s.trim())
|
|
32
|
+
.filter((s) => !!s);
|
|
33
|
+
}
|
|
34
|
+
return list.flatMap((s) => splitList(s));
|
|
35
|
+
}
|
|
36
|
+
function extractDictionaryLocalesAndFileTypes(config) {
|
|
37
|
+
const map = new Map();
|
|
38
|
+
function getDict(name) {
|
|
39
|
+
const found = map.get(name);
|
|
40
|
+
if (found)
|
|
41
|
+
return found;
|
|
42
|
+
const dict = { locales: new Set(), fileTypes: new Set() };
|
|
43
|
+
map.set(name, dict);
|
|
44
|
+
return dict;
|
|
45
|
+
}
|
|
46
|
+
const languageSettings = config.languageSettings || [];
|
|
47
|
+
for (const lang of languageSettings) {
|
|
48
|
+
const locales = splitList(lang.locale);
|
|
49
|
+
const fileTypes = splitList(lang.languageId);
|
|
50
|
+
const dicts = lang.dictionaries || [];
|
|
51
|
+
for (const dictName of dicts) {
|
|
52
|
+
const dict = getDict(dictName);
|
|
53
|
+
for (const locale of locales) {
|
|
54
|
+
if (locale)
|
|
55
|
+
dict.locales.add(locale);
|
|
56
|
+
}
|
|
57
|
+
for (const fileType of fileTypes) {
|
|
58
|
+
if (fileType)
|
|
59
|
+
dict.fileTypes.add(fileType);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return map;
|
|
64
|
+
}
|
|
65
|
+
function extractInlineDictionaries(dict) {
|
|
66
|
+
const iDict = dict;
|
|
67
|
+
const inline = [];
|
|
68
|
+
if (iDict.words?.length) {
|
|
69
|
+
inline.push('[words]');
|
|
70
|
+
}
|
|
71
|
+
if (iDict.flagWords?.length) {
|
|
72
|
+
inline.push('[flagWords]');
|
|
73
|
+
}
|
|
74
|
+
if (iDict.ignoreWords?.length) {
|
|
75
|
+
inline.push('[ignoreWords]');
|
|
76
|
+
}
|
|
77
|
+
if (iDict.suggestWords?.length) {
|
|
78
|
+
inline.push('[suggestWords]');
|
|
79
|
+
}
|
|
80
|
+
return inline.length ? inline : undefined;
|
|
81
|
+
}
|
|
82
|
+
function extractSpecialDictionaries(config) {
|
|
83
|
+
const specialDictionaries = [];
|
|
84
|
+
if (config.words?.length) {
|
|
85
|
+
specialDictionaries.push(inlineDictionaries['[words]']);
|
|
86
|
+
}
|
|
87
|
+
if (config.flagWords?.length) {
|
|
88
|
+
specialDictionaries.push(inlineDictionaries['[flagWords]']);
|
|
89
|
+
}
|
|
90
|
+
if (config.ignoreWords?.length) {
|
|
91
|
+
specialDictionaries.push(inlineDictionaries['[ignoreWords]']);
|
|
92
|
+
}
|
|
93
|
+
if (config.suggestWords?.length) {
|
|
94
|
+
specialDictionaries.push(inlineDictionaries['[suggestWords]']);
|
|
95
|
+
}
|
|
96
|
+
return specialDictionaries;
|
|
97
|
+
}
|
|
98
|
+
export async function listDictionaries(options) {
|
|
99
|
+
const configFile = await readConfig(options.config, undefined);
|
|
100
|
+
const loadDefault = options.defaultConfiguration ?? configFile.config.loadDefaultConfiguration ?? true;
|
|
101
|
+
const configBase = mergeSettings(await getDefaultSettings(loadDefault), await getGlobalSettingsAsync(), configFile.config);
|
|
102
|
+
const useFileType = options.fileType === 'text' ? 'plaintext' : options.fileType;
|
|
103
|
+
if (options.locale) {
|
|
104
|
+
configBase.language = options.locale;
|
|
105
|
+
}
|
|
106
|
+
const config = combineTextAndLanguageSettings(configBase, '', useFileType || configBase.languageId || 'plaintext');
|
|
107
|
+
const dictionaryLocalesAndFileTypes = extractDictionaryLocalesAndFileTypes(config);
|
|
108
|
+
const enabledDictionaries = new Set(config.dictionaries || []);
|
|
109
|
+
function toListDictionariesResult(dict) {
|
|
110
|
+
const inline = extractInlineDictionaries(dict);
|
|
111
|
+
return {
|
|
112
|
+
name: dict.name,
|
|
113
|
+
description: dict.description,
|
|
114
|
+
enabled: enabledDictionaries.has(dict.name),
|
|
115
|
+
path: dict.path,
|
|
116
|
+
inline,
|
|
117
|
+
locales: [...(dictionaryLocalesAndFileTypes.get(dict.name)?.locales || [])].sort(),
|
|
118
|
+
fileTypes: [...(dictionaryLocalesAndFileTypes.get(dict.name)?.fileTypes || [])].sort(),
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function filterDicts(dict) {
|
|
122
|
+
if (options.enabled === undefined)
|
|
123
|
+
return true;
|
|
124
|
+
return options.enabled === enabledDictionaries.has(dict.name);
|
|
125
|
+
}
|
|
126
|
+
const dictionaryDefinitions = (config.dictionaryDefinitions || []).filter(filterDicts);
|
|
127
|
+
dictionaryDefinitions.sort((a, b) => a.name.localeCompare(b.name));
|
|
128
|
+
const specialDicts = options.enabled !== false ? extractSpecialDictionaries(config) : [];
|
|
129
|
+
return [...specialDicts, ...dictionaryDefinitions.map(toListDictionariesResult)];
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=listDictionaries.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ListDictionariesResult } from '../dictionaries/index.js';
|
|
2
|
+
import type { DictionariesOptions } from '../options.js';
|
|
3
|
+
import type { DictionaryPathFormat } from './DictionaryPathFormat.js';
|
|
4
|
+
import { type PathInterface } from './helpers.js';
|
|
5
|
+
export interface EmitDictOptions {
|
|
6
|
+
/** current working directory */
|
|
7
|
+
cwd: string;
|
|
8
|
+
lineWidth?: number;
|
|
9
|
+
dictionaryPathFormat: DictionaryPathFormat;
|
|
10
|
+
iPath?: PathInterface;
|
|
11
|
+
color?: boolean | undefined;
|
|
12
|
+
options: DictionariesOptions;
|
|
13
|
+
}
|
|
14
|
+
export declare function emitListDictionariesResults(results: ListDictionariesResult[], options: EmitDictOptions): void;
|
|
15
|
+
export declare function calcListDictsResultsReport(results: ListDictionariesResult[], options: EmitDictOptions): {
|
|
16
|
+
table: string;
|
|
17
|
+
errors: string;
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=dictionaryListEmitter.d.ts.map
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import * as iPath from 'node:path';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { console } from '../console.js';
|
|
4
|
+
import { pruneTextEnd, pruneTextStart } from '../util/pad.js';
|
|
5
|
+
import { tableToLines } from '../util/table.js';
|
|
6
|
+
import { formatDictionaryLocation } from './helpers.js';
|
|
7
|
+
const maxWidth = 120;
|
|
8
|
+
export function emitListDictionariesResults(results, options) {
|
|
9
|
+
const report = calcListDictsResultsReport(results, options);
|
|
10
|
+
console.log(report.table);
|
|
11
|
+
if (report.errors) {
|
|
12
|
+
console.error('Errors:');
|
|
13
|
+
console.error(report.errors);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function calcListDictsResultsReport(results, options) {
|
|
17
|
+
if (options.color === true) {
|
|
18
|
+
chalk.level = 2;
|
|
19
|
+
}
|
|
20
|
+
else if (options.color === false) {
|
|
21
|
+
chalk.level = 0;
|
|
22
|
+
}
|
|
23
|
+
const col = new Intl.Collator();
|
|
24
|
+
results.sort((a, b) => col.compare(a.name, b.name));
|
|
25
|
+
const header = calcHeaders(options);
|
|
26
|
+
const rows = results.map((r) => dictTableRowToTableRow(emitDictResult(r, options)));
|
|
27
|
+
const t = tableToLines({
|
|
28
|
+
header,
|
|
29
|
+
rows,
|
|
30
|
+
terminalWidth: options.lineWidth || process.stdout.columns || maxWidth,
|
|
31
|
+
deliminator: ' ',
|
|
32
|
+
maxColumnWidths: {
|
|
33
|
+
locales: 12,
|
|
34
|
+
fileTypes: 40,
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
return {
|
|
38
|
+
table: t.map((line) => line.trimEnd()).join('\n'),
|
|
39
|
+
errors: '',
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function calcHeaders(options) {
|
|
43
|
+
const showLocation = options.dictionaryPathFormat !== 'hide' && (options.options.showLocation ?? true);
|
|
44
|
+
const showLocales = options.options.showLocales ?? true;
|
|
45
|
+
const showFileTypes = options.options.showFileTypes ?? true;
|
|
46
|
+
const headers = [['name', 'Dictionary']];
|
|
47
|
+
showLocales && headers.push(['locales', 'Locales']);
|
|
48
|
+
showFileTypes && headers.push(['fileTypes', 'File Types']);
|
|
49
|
+
showLocation && headers.push(['location', 'Dictionary Location']);
|
|
50
|
+
return headers;
|
|
51
|
+
}
|
|
52
|
+
function emitDictResult(r, options) {
|
|
53
|
+
const a = r.enabled ? '*' : ' ';
|
|
54
|
+
const dictColor = r.enabled ? chalk.yellowBright : chalk.rgb(200, 128, 50);
|
|
55
|
+
const n = (width) => dictColor(pruneTextEnd(r.name, width && width - a.length) + a);
|
|
56
|
+
const c = colorize(chalk.white);
|
|
57
|
+
const locales = (width) => c(pruneTextEnd(r.locales?.join(',') || '', width));
|
|
58
|
+
const fileTypes = (width) => c(pruneTextEnd(r.fileTypes?.join(',') || '', width));
|
|
59
|
+
if (!r.path) {
|
|
60
|
+
return {
|
|
61
|
+
name: n,
|
|
62
|
+
location: c(r.inline?.join(', ') || ''),
|
|
63
|
+
locales,
|
|
64
|
+
fileTypes,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
name: n,
|
|
69
|
+
location: (widthSrc) => c((r.path &&
|
|
70
|
+
pruneTextStart(formatDictionaryLocation(r.path, widthSrc ?? maxWidth, { iPath, ...options }), widthSrc ?? maxWidth)) ||
|
|
71
|
+
''),
|
|
72
|
+
locales,
|
|
73
|
+
fileTypes,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function dictTableRowToTableRow(row) {
|
|
77
|
+
return Object.fromEntries(Object.entries(row));
|
|
78
|
+
}
|
|
79
|
+
function colorize(fn) {
|
|
80
|
+
return (s) => (s ? fn(s) : '');
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=dictionaryListEmitter.js.map
|