cspell-lib 8.8.0 → 8.8.2

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 CHANGED
@@ -1,3 +1,93 @@
1
- # cspell-lib
1
+ # CSpell Library
2
2
 
3
- A library of useful functions used across various cspell tools.
3
+ `cspell-lib` is the workhorse behind cspell. It does all the heavy lifting necessary to spell check files.
4
+
5
+ ## Support Future Development
6
+
7
+ <!--- @@inject: ../../static/sponsor.md --->
8
+
9
+ - [![GitHub Sponsors](https://img.shields.io/badge/-black?style=social&logo=githubsponsors&label=GitHub%20Sponsor%3A%20Street%20Side%20Software)](https://github.com/sponsors/streetsidesoftware)
10
+ - [![Patreon](https://img.shields.io/badge/-black?style=social&logo=patreon&label=Patreon%3A%20Street%20Side%20Software)](https://patreon.com/streetsidesoftware)
11
+ - [![PayPal](https://img.shields.io/badge/-black?style=social&logo=paypal&label=PayPal%20Donate%3A%20Street%20Side%20Software)](https://www.paypal.com/donate/?hosted_button_id=26LNBP2Q6MKCY)
12
+ - [![Open Collective](https://img.shields.io/badge/-black?style=social&logo=opencollective&label=Open%20Collective%3A%20CSpell)](https://opencollective.com/cspell)
13
+
14
+ <!--- @@inject-end: ../../static/sponsor.md --->
15
+
16
+ ## Installation
17
+
18
+ ```
19
+ npm i -S cspell-lib
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ### Example - Check some text
25
+
26
+ Here is an example of using `spellCheckDocument` to spell check some text with a spelling issue.
27
+
28
+ ```ts
29
+ import assert from 'node:assert';
30
+
31
+ import { spellCheckDocument } from 'cspell-lib';
32
+
33
+ // cspell:ignore wordz coztom clockz cuztom
34
+ const customWords = ['wordz', 'cuztom', 'clockz'];
35
+
36
+ async function checkSpelling(phrase: string) {
37
+ const result = await spellCheckDocument(
38
+ { uri: 'text.txt', text: phrase, languageId: 'plaintext', locale: 'en' },
39
+ { generateSuggestions: true, noConfigSearch: true },
40
+ { words: customWords, suggestionsTimeout: 2000 }
41
+ );
42
+ return result.issues;
43
+ }
44
+
45
+ export async function run() {
46
+ console.log(`Start: ${new Date().toISOString()}`);
47
+ const r = await checkSpelling('These are my coztom wordz.');
48
+ console.log(`End: ${new Date().toISOString()}`);
49
+ // console.log(r);
50
+ assert(r.length === 1, 'Make sure we got 1 spelling issue back.');
51
+ assert(r[0].text === 'coztom');
52
+ assert(r[0].suggestions?.includes('cuztom'));
53
+ // console.log('%o', r);
54
+ }
55
+ ```
56
+
57
+ ### Example - Check a file
58
+
59
+ ```ts
60
+ import { resolve } from 'node:path';
61
+ import { pathToFileURL } from 'node:url';
62
+ import { spellCheckDocument } from 'cspell-lib';
63
+
64
+ export async function checkFile(filename: string) {
65
+ const uri = pathToFileURL(resolve(filename)).toString();
66
+ const result = await spellCheckDocument(
67
+ { uri },
68
+ { generateSuggestions: true, noConfigSearch: true },
69
+ { words: customWords, suggestionsTimeout: 2000 }
70
+ );
71
+ return result.issues;
72
+ }
73
+ ```
74
+
75
+ ## CSpell for Enterprise
76
+
77
+ <!--- @@inject: ../../static/tidelift.md --->
78
+
79
+ Available as part of the Tidelift Subscription.
80
+
81
+ The maintainers of cspell and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-cspell?utm_source=npm-cspell&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
82
+
83
+ <!--- @@inject-end: ../../static/tidelift.md --->
84
+
85
+ <!--- @@inject: ../../static/footer.md --->
86
+
87
+ <br/>
88
+
89
+ ---
90
+
91
+ <p align="center">Brought to you by<a href="https://streetsidesoftware.com" title="Street Side Software"><img width="16" alt="Street Side Software Logo" src="https://i.imgur.com/CyduuVY.png" /> Street Side Software</a></p>
92
+
93
+ <!--- @@inject-end: ../../static/footer.md --->
@@ -103,6 +103,7 @@ function _merge(left, right) {
103
103
  suggestWords: mergeWordsCached(_left.suggestWords, _right.suggestWords),
104
104
  enabledLanguageIds: replaceIfNotEmpty(_left.enabledLanguageIds, _right.enabledLanguageIds),
105
105
  enableFiletypes: mergeList(_left.enableFiletypes, _right.enableFiletypes),
106
+ enabledFileTypes: mergeObjects(_left.enabledFileTypes, _right.enabledFileTypes),
106
107
  ignoreRegExpList: mergeListUnique(_left.ignoreRegExpList, _right.ignoreRegExpList),
107
108
  patterns: mergeListUnique(_left.patterns, _right.patterns),
108
109
  dictionaryDefinitions: mergeListUnique(_left.dictionaryDefinitions, _right.dictionaryDefinitions),
@@ -1,59 +1,49 @@
1
1
  import { pathToFileURL } from 'node:url';
2
2
  import { CSpellConfigFileInMemory, CSpellConfigFileJson } from 'cspell-config-lib';
3
- import { isErrnoException } from '../util/errors.js';
4
- import { logError } from '../util/logger.js';
5
3
  import { getSourceDirectoryUrl, toFilePathOrHref } from '../util/url.js';
6
- import { ConfigStore } from './cfgStore.js';
4
+ import { GlobalConfigStore } from './cfgStore.js';
7
5
  import { configToRawSettings } from './Controller/configLoader/configToRawSettings.js';
8
- const packageName = 'cspell';
6
+ const globalConfig = new GlobalConfigStore();
9
7
  export async function getRawGlobalSettings() {
10
8
  return configToRawSettings(await getGlobalConfig());
11
9
  }
12
- export function getGlobalConfig() {
10
+ export async function getGlobalConfig() {
13
11
  const name = 'CSpell Configstore';
14
12
  const configPath = getGlobalConfigPath();
15
- const urlGlobal = configPath ? pathToFileURL(configPath) : new URL('global-config.json', getSourceDirectoryUrl());
13
+ let urlGlobal = configPath ? pathToFileURL(configPath) : new URL('global-config.json', getSourceDirectoryUrl());
16
14
  const source = {
17
15
  name,
18
16
  filename: toFilePathOrHref(urlGlobal),
19
17
  };
20
18
  const globalConf = { source };
21
19
  let hasGlobalConfig = false;
22
- try {
23
- const cfgStore = new ConfigStore(packageName);
24
- const cfg = cfgStore.all;
20
+ const found = await globalConfig.readConfigFile();
21
+ if (found && found.config && found.filename) {
22
+ const cfg = found.config;
23
+ urlGlobal = pathToFileURL(found.filename);
25
24
  // Only populate globalConf is there are values.
26
25
  if (cfg && Object.keys(cfg).length) {
27
26
  Object.assign(globalConf, cfg);
28
27
  globalConf.source = {
29
28
  name,
30
- filename: cfgStore.path,
29
+ filename: found.filename,
31
30
  };
32
31
  hasGlobalConfig = Object.keys(cfg).length > 0;
33
32
  }
34
33
  }
35
- catch (error) {
36
- if (!isErrnoException(error) ||
37
- !error.code ||
38
- !['ENOENT', 'EACCES', 'ENOTDIR', 'EISDIR'].includes(error.code)) {
39
- logError(error);
40
- }
41
- }
42
34
  const settings = { ...globalConf, name, source };
43
35
  const ConfigFile = hasGlobalConfig ? CSpellConfigFileJson : CSpellConfigFileInMemory;
44
- return Promise.resolve(new ConfigFile(urlGlobal, settings));
36
+ return new ConfigFile(urlGlobal, settings);
45
37
  }
46
38
  export async function writeRawGlobalSettings(settings) {
47
39
  const toWrite = {
48
40
  import: settings.import,
49
41
  };
50
- const cfgStore = new ConfigStore(packageName);
51
- cfgStore.set(toWrite);
42
+ await globalConfig.writeConfigFile(toWrite);
52
43
  }
53
44
  export function getGlobalConfigPath() {
54
45
  try {
55
- const cfgStore = new ConfigStore(packageName);
56
- return cfgStore.path;
46
+ return globalConfig.location || GlobalConfigStore.defaultLocation;
57
47
  }
58
48
  catch {
59
49
  return undefined;
@@ -1,4 +1,19 @@
1
- import ConfigStoreExport from 'configstore';
2
- export type ConfigStore = typeof ConfigStoreExport;
3
- export declare const ConfigStore: typeof ConfigStoreExport;
1
+ import { CSpellSettings } from '@cspell/cspell-types';
2
+ export declare const legacyLocationDir: string | undefined;
3
+ export declare const cspellGlobalLocationDir: string;
4
+ export declare const defaultConfigFileName = "cspell.json";
5
+ interface GlobalConfigFile {
6
+ filename: string;
7
+ config: CSpellSettings;
8
+ }
9
+ export declare class GlobalConfigStore {
10
+ #private;
11
+ constructor(filename?: string);
12
+ readConfigFile(): Promise<GlobalConfigFile | undefined>;
13
+ writeConfigFile(cfg: CSpellSettings): Promise<string>;
14
+ get location(): string | undefined;
15
+ static create(): GlobalConfigStore;
16
+ static defaultLocation: string;
17
+ }
18
+ export {};
4
19
  //# sourceMappingURL=cfgStore.d.ts.map
@@ -1,3 +1,60 @@
1
- import ConfigStoreExport from 'configstore';
2
- export const ConfigStore = ConfigStoreExport;
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import envPaths from 'env-paths';
4
+ import { xdgConfig } from 'xdg-basedir';
5
+ import { isDefined } from '../util/util.js';
6
+ const packageName = 'cspell';
7
+ export const legacyLocationDir = xdgConfig ? path.join(xdgConfig, 'configstore') : undefined;
8
+ export const cspellGlobalLocationDir = envPaths(packageName, { suffix: '' }).config;
9
+ export const defaultConfigFileName = 'cspell.json';
10
+ const searchOrder = [cspellGlobalLocationDir, legacyLocationDir].filter(isDefined);
11
+ export class GlobalConfigStore {
12
+ #foundLocation;
13
+ #baseFilename;
14
+ constructor(filename = defaultConfigFileName) {
15
+ this.#baseFilename = filename;
16
+ }
17
+ async #readConfigFile(location) {
18
+ try {
19
+ const json = await fs.readFile(location, 'utf8');
20
+ return { filename: location, config: JSON.parse(json) };
21
+ }
22
+ catch {
23
+ return undefined;
24
+ }
25
+ }
26
+ async readConfigFile() {
27
+ if (this.#foundLocation) {
28
+ const found = await this.#readConfigFile(this.#foundLocation);
29
+ if (found)
30
+ return found;
31
+ }
32
+ const firstFile = path.resolve(cspellGlobalLocationDir, this.#baseFilename);
33
+ const possibleLocations = new Set([
34
+ firstFile,
35
+ ...searchOrder.map((p) => path.resolve(p, defaultConfigFileName)),
36
+ ]);
37
+ for (const filename of possibleLocations) {
38
+ const found = await this.#readConfigFile(filename);
39
+ if (found) {
40
+ this.#foundLocation = found.filename;
41
+ return found;
42
+ }
43
+ }
44
+ return undefined;
45
+ }
46
+ async writeConfigFile(cfg) {
47
+ this.#foundLocation ??= path.join(cspellGlobalLocationDir, this.#baseFilename);
48
+ await fs.mkdir(path.dirname(this.#foundLocation), { recursive: true });
49
+ await fs.writeFile(this.#foundLocation, JSON.stringify(cfg, undefined, 2) + '\n');
50
+ return this.#foundLocation;
51
+ }
52
+ get location() {
53
+ return this.#foundLocation;
54
+ }
55
+ static create() {
56
+ return new this();
57
+ }
58
+ static defaultLocation = path.join(cspellGlobalLocationDir, defaultConfigFileName);
59
+ }
3
60
  //# sourceMappingURL=cfgStore.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cspell-lib",
3
- "version": "8.8.0",
3
+ "version": "8.8.2",
4
4
  "description": "A library of useful functions used across various cspell tools.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -24,11 +24,11 @@
24
24
  "scripts": {
25
25
  "clean": "shx rm -rf dist temp coverage \"*.tsbuildInfo\"",
26
26
  "clean-build": "pnpm clean && pnpm build",
27
- "build": "tsc -b . && pnpm run build:api",
27
+ "build": "tsc -b . -f && pnpm run build:api",
28
28
  "build:api": "rollup -c api/rollup.config.mjs",
29
- "build:esm": "tsc -b tsconfig.esm.json",
30
- "build:lib": "tsc -b src/lib/tsconfig.json",
31
- "watch": "tsc -b . --watch",
29
+ "build:esm": "tsc -b tsconfig.esm.json -f",
30
+ "build:lib": "tsc -b src/lib/tsconfig.json -f",
31
+ "watch": "tsc -b . --watch -f",
32
32
  "coverage": "vitest run --coverage --pool=forks",
33
33
  "test-watch": "vitest",
34
34
  "prepublishOnly": "pnpm run clean-build",
@@ -59,33 +59,34 @@
59
59
  },
60
60
  "homepage": "https://github.com/streetsidesoftware/cspell#readme",
61
61
  "dependencies": {
62
- "@cspell/cspell-bundled-dicts": "8.8.0",
63
- "@cspell/cspell-pipe": "8.8.0",
64
- "@cspell/cspell-resolver": "8.8.0",
65
- "@cspell/cspell-types": "8.8.0",
66
- "@cspell/dynamic-import": "8.8.0",
67
- "@cspell/strong-weak-map": "8.8.0",
62
+ "@cspell/cspell-bundled-dicts": "8.8.2",
63
+ "@cspell/cspell-pipe": "8.8.2",
64
+ "@cspell/cspell-resolver": "8.8.2",
65
+ "@cspell/cspell-types": "8.8.2",
66
+ "@cspell/dynamic-import": "8.8.2",
67
+ "@cspell/strong-weak-map": "8.8.2",
68
68
  "clear-module": "^4.1.2",
69
69
  "comment-json": "^4.2.3",
70
- "configstore": "^6.0.0",
71
- "cspell-config-lib": "8.8.0",
72
- "cspell-dictionary": "8.8.0",
73
- "cspell-glob": "8.8.0",
74
- "cspell-grammar": "8.8.0",
75
- "cspell-io": "8.8.0",
76
- "cspell-trie-lib": "8.8.0",
70
+ "cspell-config-lib": "8.8.2",
71
+ "cspell-dictionary": "8.8.2",
72
+ "cspell-glob": "8.8.2",
73
+ "cspell-grammar": "8.8.2",
74
+ "cspell-io": "8.8.2",
75
+ "cspell-trie-lib": "8.8.2",
76
+ "env-paths": "^3.0.0",
77
77
  "fast-equals": "^5.0.1",
78
78
  "gensequence": "^7.0.0",
79
79
  "import-fresh": "^3.3.0",
80
80
  "resolve-from": "^5.0.0",
81
81
  "vscode-languageserver-textdocument": "^1.0.11",
82
- "vscode-uri": "^3.0.8"
82
+ "vscode-uri": "^3.0.8",
83
+ "xdg-basedir": "^5.1.0"
83
84
  },
84
85
  "engines": {
85
86
  "node": ">=18"
86
87
  },
87
88
  "devDependencies": {
88
- "@cspell/dict-cpp": "^5.1.3",
89
+ "@cspell/dict-cpp": "^5.1.6",
89
90
  "@cspell/dict-csharp": "^4.0.2",
90
91
  "@cspell/dict-css": "^4.0.12",
91
92
  "@cspell/dict-fa-ir": "^4.0.0",
@@ -94,9 +95,10 @@
94
95
  "@cspell/dict-nl-nl": "^2.3.0",
95
96
  "@cspell/dict-python": "^4.1.11",
96
97
  "@types/configstore": "^6.0.2",
98
+ "configstore": "^6.0.0",
97
99
  "cspell-dict-nl-nl": "^1.1.2",
98
100
  "leaked-handles": "^5.2.0",
99
101
  "lorem-ipsum": "^2.0.8"
100
102
  },
101
- "gitHead": "a42bce675c00cb2d51809b3ae3894119ea4f5ce7"
103
+ "gitHead": "e82ec807677c040c38b7d5608c8a8d42185d3b24"
102
104
  }