cspell 9.1.5 → 9.2.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 CHANGED
@@ -13,10 +13,13 @@ A Spell Checker for Code!
13
13
  <!--- @@inject: ../../static/sponsor.md --->
14
14
 
15
15
  - [![GitHub Sponsors](https://img.shields.io/badge/-black?style=social&logo=githubsponsors&label=GitHub%20Sponsor%3A%20Street%20Side%20Software)](https://github.com/sponsors/streetsidesoftware)
16
- - [![Patreon](https://img.shields.io/badge/-black?style=social&logo=patreon&label=Patreon%3A%20Street%20Side%20Software)](https://patreon.com/streetsidesoftware)
17
16
  - [![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)
18
17
  - [![Open Collective](https://img.shields.io/badge/-black?style=social&logo=opencollective&label=Open%20Collective%3A%20CSpell)](https://opencollective.com/cspell)
19
18
 
19
+ <!---
20
+ - [![Patreon](https://img.shields.io/badge/-black?style=social&logo=patreon&label=Patreon%3A%20Street%20Side%20Software)](https://patreon.com/streetsidesoftware)
21
+ --->
22
+
20
23
  <!--- @@inject-end: ../../static/sponsor.md --->
21
24
 
22
25
  ## Features
package/dist/esm/app.d.ts CHANGED
@@ -3,17 +3,17 @@ import { Command } from "commander";
3
3
 
4
4
  //#region src/util/errors.d.ts
5
5
  declare class CheckFailed extends Error {
6
- readonly exitCode: string;
6
+ readonly exitCode: number;
7
7
  constructor(message: string, exitCode?: number);
8
8
  }
9
9
  declare class ApplicationError extends Error {
10
- readonly exitCode: string;
11
- readonly cause?: number;
10
+ readonly exitCode: number;
11
+ readonly cause?: Error | undefined;
12
12
  constructor(message: string, exitCode?: number, cause?: Error | undefined);
13
13
  }
14
14
  //#endregion
15
15
  //#region src/app.d.mts
16
16
  declare function run(command?: Command, argv?: string[]): Promise<void>;
17
17
  //#endregion
18
- export { ApplicationError, CheckFailed, LinterCliOptions as Options, run };
18
+ export { ApplicationError, CheckFailed, type LinterCliOptions as Options, run };
19
19
  //# sourceMappingURL=app.d.ts.map
package/dist/esm/app.js CHANGED
@@ -1,4 +1,4 @@
1
- import { ApplicationError, CheckFailed, DEFAULT_CACHE_LOCATION, IncludeExcludeFlag, ReportChoicesAll, checkText, console, createInit, lint, listDictionaries, npmPackage, parseApplicationFeatureFlags, suggestions, trace } from "./application-D-NwS6qb.js";
1
+ import { ApplicationError, CheckFailed, DEFAULT_CACHE_LOCATION, IncludeExcludeFlag, ReportChoicesAll, checkText, console, createInit, lint, listDictionaries, npmPackage, parseApplicationFeatureFlags, suggestions, trace } from "./application-BZlf5spr.js";
2
2
  import { Option, program } from "commander";
3
3
  import { satisfies } from "semver";
4
4
  import chalk from "chalk";
@@ -323,16 +323,16 @@ function decorateRowWith(row, ...decorators) {
323
323
 
324
324
  //#endregion
325
325
  //#region src/emitters/helpers.ts
326
- function trimMidPath(s, w, sep) {
326
+ function trimMidPath(s, w, sep$1) {
327
327
  if (s.length <= w) return s;
328
- const parts = s.split(sep);
328
+ const parts = s.split(sep$1);
329
329
  if (parts[parts.length - 1].length > w) return trimMid(s, w);
330
330
  function join(left$1, right$1) {
331
331
  return [
332
332
  ...parts.slice(0, left$1),
333
333
  "…",
334
334
  ...parts.slice(right$1)
335
- ].join(sep);
335
+ ].join(sep$1);
336
336
  }
337
337
  let left = 0, right = parts.length, last = "";
338
338
  for (let i = 0; i < parts.length; ++i) {
@@ -558,7 +558,6 @@ function commandLink(prog) {
558
558
  const imports = await listGlobalImports();
559
559
  const table = listGlobalImportsResultToTable(imports.list);
560
560
  tableToLines(table).forEach((line) => console.log(line));
561
- return;
562
561
  });
563
562
  linkCommand.command("add <dictionaries...>").alias("a").description("Add dictionaries any other settings to the cspell global config.").action(async (dictionaries) => {
564
563
  const r = await addPathsToGlobalImports(dictionaries);
@@ -566,14 +565,12 @@ function commandLink(prog) {
566
565
  console.log("Adding:");
567
566
  tableToLines(table).forEach((line) => console.log(line));
568
567
  if (r.error) throw new CheckFailed(r.error, 1);
569
- return;
570
568
  });
571
569
  linkCommand.command("remove <paths...>").alias("r").description("Remove matching paths / packages from the global config.").action(async (dictionaries) => {
572
570
  const r = await removePathsFromGlobalImports(dictionaries);
573
571
  console.log("Removing:");
574
572
  if (r.error) throw new CheckFailed(r.error, 1);
575
573
  r.removed.map((f) => console.log(f));
576
- return;
577
574
  });
578
575
  return linkCommand;
579
576
  }
@@ -703,7 +700,6 @@ function commandLint(prog) {
703
700
  const exitCode = useExitCode ? 1 : 0;
704
701
  throw new CheckFailed("check failed", exitCode);
705
702
  }
706
- return;
707
703
  });
708
704
  return spellCheckCommand;
709
705
  }
@@ -5,27 +5,25 @@ import * as cspell from "cspell-lib";
5
5
  import { ENV_CSPELL_GLOB_ROOT, IncludeExcludeFlag, SuggestionError, Text, checkTextDocument, combineTextAndLanguageSettings, createPerfTimer, extractDependencies, extractImportErrors, fileToDocument, getDefaultSettings, getDictionary, getGlobalSettingsAsync, getSystemFeatureFlags, isBinaryFile, isSpellingDictionaryLoadError, mergeSettings, setLogger, shouldCheckDocument, spellCheckDocument, suggestionsForWords, traceWordsAsync } from "cspell-lib";
6
6
  import assert from "node:assert";
7
7
  import { format, formatWithOptions } from "node:util";
8
- import { toFileDirURL, toFilePathOrHref, toFileURL, urlRelative } from "@cspell/url";
8
+ import { isUrlLike, toFileDirURL, toFilePathOrHref, toFileURL, urlRelative } from "@cspell/url";
9
9
  import { makeTemplate } from "chalk-template";
10
10
  import fs, { stat } from "node:fs/promises";
11
11
  import { MutableCSpellConfigFile, createReaderWriter, cspellConfigFileSchema, isCfgArrayNode } from "cspell-config-lib";
12
- import * as fs$1 from "node:fs";
13
- import { mkdirSync, promises } from "node:fs";
12
+ import { promises } from "node:fs";
14
13
  import { fileURLToPath } from "node:url";
15
14
  import * as path$1 from "node:path";
16
- import path, { dirname, isAbsolute, posix, relative, resolve } from "node:path";
15
+ import path, { isAbsolute, posix, relative, resolve, sep } from "node:path";
17
16
  import { opMap as opMap$1, pipe } from "@cspell/cspell-pipe/sync";
18
17
  import { IssueType, MessageTypes, unknownWordsChoices } from "@cspell/cspell-types";
19
18
  import { _debug } from "cspell-dictionary";
20
19
  import { GitIgnore, findRepoRoot } from "cspell-gitignore";
21
20
  import { GlobMatcher, fileOrGlobToGlob, workaroundPicomatchBug } from "cspell-glob";
22
- import * as crypto from "node:crypto";
21
+ import crypto from "node:crypto";
23
22
  import streamConsumers from "node:stream/consumers";
24
23
  import { readFileText, toURL } from "cspell-io";
25
24
  import { glob } from "tinyglobby";
26
25
  import * as readline from "node:readline";
27
- import { isMainThread } from "node:worker_threads";
28
- import fileEntryCache from "file-entry-cache";
26
+ import { parse, stringify } from "flatted";
29
27
  import { dynamicImport } from "@cspell/dynamic-import";
30
28
 
31
29
  //#region src/console.ts
@@ -275,7 +273,6 @@ function getReporter(options, config) {
275
273
  fn(r);
276
274
  };
277
275
  }
278
- const repeatIssues = false;
279
276
  const issuesCollection = void 0;
280
277
  const errorCollection = [];
281
278
  function errorEmitter(message, error) {
@@ -791,7 +788,7 @@ const pkgDir = _dirname;
791
788
  //#endregion
792
789
  //#region src/pkgInfo.ts
793
790
  const name = "cspell";
794
- const version$1 = "9.1.5";
791
+ const version$1 = "9.2.1";
795
792
  const engines = { node: ">=20" };
796
793
  const npmPackage = {
797
794
  name,
@@ -813,6 +810,7 @@ const STDIN = "stdin";
813
810
  const STDINProtocol = "stdin:";
814
811
  const STDINUrlPrefix = "stdin://";
815
812
  const FileUrlPrefix = "file://";
813
+ const FileUrlAbsPrefix = "file:///";
816
814
 
817
815
  //#endregion
818
816
  //#region src/util/glob.ts
@@ -972,7 +970,7 @@ function resolveStdinUrl(url, cwd) {
972
970
  assert(url.startsWith(STDINProtocol), `Expected url to start with ${STDINProtocol}`);
973
971
  const path$2 = decodeURIComponent(url).slice(STDINProtocol.length).replace(/^\/\//, "").replace(/^\/([a-z]:)/i, "$1");
974
972
  const fileUrl = toFileURL(path$2, cwd);
975
- return fileUrl.toString().replace(/^file:/, STDINProtocol) + (path$2 ? "" : "/");
973
+ return new URL(fileUrl.toString().replace(/^file:/, STDINProtocol) + (path$2 ? "" : "/"));
976
974
  }
977
975
 
978
976
  //#endregion
@@ -1005,15 +1003,17 @@ function isBinaryFile$1(filename, cwd) {
1005
1003
  if (uri.protocol.startsWith("stdin")) return false;
1006
1004
  return isBinaryFile(uri);
1007
1005
  }
1006
+ function resolveFilenameToUrl(filename, cwd) {
1007
+ if (filename instanceof URL) return filename;
1008
+ if (filename === STDIN) return new URL(STDINUrlPrefix);
1009
+ if (filename.startsWith(FileUrlAbsPrefix)) return new URL(filename);
1010
+ const cwdUrl = toFileDirURL(cwd || process.cwd());
1011
+ if (filename.startsWith(FileUrlPrefix)) return new URL(filename.slice(FileUrlPrefix.length), cwdUrl);
1012
+ if (isStdinUrl(filename)) return resolveStdinUrl(filename, cwdUrl);
1013
+ return toFileURL(filename, cwdUrl);
1014
+ }
1008
1015
  function resolveFilename(filename, cwd) {
1009
- cwd = cwd || process.cwd();
1010
- if (filename === STDIN) return STDINUrlPrefix;
1011
- if (filename.startsWith(FileUrlPrefix)) {
1012
- const url = new URL(filename.slice(FileUrlPrefix.length), toFileDirURL(cwd));
1013
- return fileURLToPath(url);
1014
- }
1015
- if (isStdinUrl(filename)) return resolveStdinUrl(filename, cwd);
1016
- return path$1.resolve(cwd, filename);
1016
+ return toFilePathOrHref(resolveFilenameToUrl(filename, cwd));
1017
1017
  }
1018
1018
  function readFileInfo(filename, encoding = UTF8, handleNotFound = false) {
1019
1019
  filename = resolveFilename(filename);
@@ -1114,78 +1114,237 @@ function relativeToCwd(filename, cwd = process.cwd()) {
1114
1114
  }
1115
1115
 
1116
1116
  //#endregion
1117
- //#region src/util/cache/file-entry-cache.mts
1118
- function createFromFile$1(pathToCache, useChecksum) {
1119
- return fileEntryCache.createFromFile(pathToCache, useChecksum);
1117
+ //#region src/util/cache/file-entry-cache/flatCache.ts
1118
+ var FlatCache = class {
1119
+ #cache;
1120
+ constructor(cacheFilename) {
1121
+ this.cacheFilename = cacheFilename;
1122
+ this.#cache = /* @__PURE__ */ new Map();
1123
+ }
1124
+ keys() {
1125
+ return this.#cache.keys();
1126
+ }
1127
+ set(key, value) {
1128
+ this.#cache.set(key, value);
1129
+ return this;
1130
+ }
1131
+ removeKey(key) {
1132
+ this.#cache.delete(key);
1133
+ }
1134
+ get(key) {
1135
+ return this.#cache.get(key);
1136
+ }
1137
+ async load(ifFound = true) {
1138
+ this.#cache.clear();
1139
+ try {
1140
+ const content = await fs.readFile(this.cacheFilename, "utf8");
1141
+ this.#cache = new Map(Object.entries(parse(content)));
1142
+ } catch (error) {
1143
+ if (!ifFound) throw error;
1144
+ }
1145
+ return this;
1146
+ }
1147
+ async save() {
1148
+ const dir = new URL(".", this.cacheFilename);
1149
+ await fs.mkdir(dir, { recursive: true });
1150
+ const content = stringify(Object.fromEntries(this.#cache.entries()));
1151
+ await fs.writeFile(this.cacheFilename, content, "utf8");
1152
+ }
1153
+ /**
1154
+ * Clear the cache and remove the cache file from disk.
1155
+ */
1156
+ async destroy() {
1157
+ this.#cache.clear();
1158
+ try {
1159
+ await fs.unlink(this.cacheFilename);
1160
+ } catch {}
1161
+ }
1162
+ };
1163
+ /**
1164
+ *
1165
+ * @param cachefile - The location of the cache file.
1166
+ * @returns
1167
+ */
1168
+ function loadCacheFile(cachefile) {
1169
+ const cache = new FlatCache(cachefile);
1170
+ return cache.load();
1120
1171
  }
1121
1172
 
1122
1173
  //#endregion
1123
- //#region src/util/cache/fileEntryCache.ts
1124
- function createFromFile(pathToCache, useCheckSum, useRelative) {
1125
- const absPathToCache = path$1.resolve(pathToCache);
1126
- const relDir = path$1.dirname(absPathToCache);
1127
- mkdirSync(relDir, { recursive: true });
1128
- const create = wrap(() => createFromFile$1(absPathToCache, useCheckSum));
1129
- const feCache = create();
1130
- const cacheWrapper = {
1131
- get cache() {
1132
- return feCache.cache;
1133
- },
1134
- getHash(buffer) {
1135
- return feCache.getHash(buffer);
1136
- },
1137
- hasFileChanged: wrap((cwd, file) => {
1138
- return feCache.hasFileChanged(resolveFile(cwd, file));
1139
- }),
1140
- analyzeFiles: wrap((cwd, files) => {
1141
- return feCache.analyzeFiles(resolveFiles(cwd, files));
1142
- }),
1143
- getFileDescriptor: wrap((cwd, file) => {
1144
- return feCache.getFileDescriptor(resolveFile(cwd, file));
1145
- }),
1146
- getUpdatedFiles: wrap((cwd, files) => {
1147
- return feCache.getUpdatedFiles(resolveFiles(cwd, files));
1148
- }),
1149
- normalizeEntries: wrap((cwd, files) => {
1150
- return feCache.normalizeEntries(resolveFiles(cwd, files));
1151
- }),
1152
- removeEntry: wrap((cwd, file) => {
1153
- return feCache.removeEntry(resolveFile(cwd, file));
1154
- }),
1155
- deleteCacheFile() {
1156
- feCache.deleteCacheFile();
1157
- },
1158
- destroy() {
1159
- feCache.destroy();
1160
- },
1161
- reconcile: wrap((_cwd, noPrune) => {
1162
- feCache.reconcile(noPrune);
1163
- })
1164
- };
1165
- return cacheWrapper;
1166
- function resolveFile(cwd, file) {
1167
- if (!useRelative) return normalizePath(file);
1168
- const r = path$1.relative(relDir, path$1.resolve(cwd, file));
1169
- return normalizePath(r);
1170
- }
1171
- function resolveFiles(cwd, files) {
1172
- return files?.map((file) => resolveFile(cwd, file));
1173
- }
1174
- function wrap(fn) {
1175
- return (...params) => {
1176
- const cwd = process.cwd();
1177
- try {
1178
- isMainThread && process.chdir(relDir);
1179
- return fn(cwd, ...params);
1180
- } finally {
1181
- isMainThread && process.chdir(cwd);
1182
- }
1174
+ //#region src/util/cache/file-entry-cache/file-entry-cache.ts
1175
+ async function createFromFile$1(cacheFileUrl, useChecksum, currentWorkingDir) {
1176
+ const cache = await loadCacheFile(cacheFileUrl);
1177
+ const fec = new ImplFileEntryCache(cache, useChecksum ?? false, currentWorkingDir);
1178
+ await fec.removeNotFoundFiles();
1179
+ return fec;
1180
+ }
1181
+ var ImplFileEntryCache = class {
1182
+ cache;
1183
+ useChecksum;
1184
+ #normalizedEntries = /* @__PURE__ */ new Map();
1185
+ /**
1186
+ * To enable relative paths as the key with current working directory
1187
+ */
1188
+ currentWorkingDir;
1189
+ constructor(cache, useChecksum, currentWorkingDir) {
1190
+ this.cache = cache;
1191
+ this.useChecksum = useChecksum || false;
1192
+ this.currentWorkingDir = currentWorkingDir ? fileURLToPath(currentWorkingDir) : void 0;
1193
+ }
1194
+ async removeNotFoundFiles() {
1195
+ for (const fPath of this.cache.keys()) try {
1196
+ const filePath = this.resolveKeyToFile(fPath);
1197
+ await fs.stat(filePath);
1198
+ } catch (error) {
1199
+ if (isNodeError(error) && error.code === "ENOENT") this.cache.removeKey(fPath);
1200
+ }
1201
+ }
1202
+ /**
1203
+ * Given a buffer, calculate md5 hash of its content.
1204
+ * @param buffer buffer to calculate hash on
1205
+ * @return content hash digest
1206
+ */
1207
+ #getHash(buffer) {
1208
+ return crypto.createHash("md5").update(buffer).digest("hex");
1209
+ }
1210
+ async getFileDescriptor(file) {
1211
+ let fstat;
1212
+ try {
1213
+ fstat = await fs.stat(file);
1214
+ } catch (error) {
1215
+ this.#removeEntry(file);
1216
+ return {
1217
+ key: file,
1218
+ notFound: true,
1219
+ err: toError$1(error)
1220
+ };
1221
+ }
1222
+ if (this.useChecksum) return this.#getFileDescriptorUsingChecksum(file);
1223
+ return this.#getFileDescriptorUsingMtimeAndSize(file, fstat);
1224
+ }
1225
+ #getFileDescriptorUsingMtimeAndSize(file, fstat) {
1226
+ const key = this.#getFileKey(file);
1227
+ let meta = this.cache.get(key);
1228
+ const cacheExists = !!meta;
1229
+ const cSize = fstat.size;
1230
+ const cTime = fstat.mtime.getTime();
1231
+ let isDifferentDate;
1232
+ let isDifferentSize;
1233
+ if (meta) {
1234
+ isDifferentDate = cTime !== meta.mtime;
1235
+ isDifferentSize = cSize !== meta.size;
1236
+ } else meta = {
1237
+ size: cSize,
1238
+ mtime: cTime
1239
+ };
1240
+ const nEntry = {
1241
+ key,
1242
+ changed: !cacheExists || isDifferentDate || isDifferentSize,
1243
+ meta
1244
+ };
1245
+ this.#normalizedEntries.set(key, nEntry);
1246
+ return nEntry;
1247
+ }
1248
+ async #getFileDescriptorUsingChecksum(file) {
1249
+ const key = this.#getFileKey(file);
1250
+ let meta = this.cache.get(key);
1251
+ const cacheExists = !!meta;
1252
+ let contentBuffer;
1253
+ try {
1254
+ contentBuffer = await fs.readFile(file);
1255
+ } catch {
1256
+ contentBuffer = "";
1257
+ }
1258
+ let isDifferent = true;
1259
+ const hash = this.#getHash(contentBuffer);
1260
+ if (meta) isDifferent = hash !== meta.hash;
1261
+ else meta = { hash };
1262
+ const nEntry = {
1263
+ key,
1264
+ changed: !cacheExists || isDifferent,
1265
+ meta
1266
+ };
1267
+ this.#normalizedEntries.set(key, nEntry);
1268
+ return nEntry;
1269
+ }
1270
+ /**
1271
+ * Remove an entry from the file-entry-cache. Useful to force the file to still be considered
1272
+ * modified the next time the process is run
1273
+ */
1274
+ #removeEntry(file) {
1275
+ const key = this.#getFileKey(file);
1276
+ this.#normalizedEntries.delete(key);
1277
+ this.cache.removeKey(key);
1278
+ }
1279
+ /**
1280
+ * Deletes the cache file from the disk and clears the memory cache
1281
+ */
1282
+ async destroy() {
1283
+ this.#normalizedEntries.clear();
1284
+ await this.cache.destroy();
1285
+ }
1286
+ async #getMetaForFileUsingCheckSum(cacheEntry) {
1287
+ const filePath = this.resolveKeyToFile(cacheEntry.key);
1288
+ const contentBuffer = await fs.readFile(filePath);
1289
+ const hash = this.#getHash(contentBuffer);
1290
+ const meta = {
1291
+ ...cacheEntry.meta,
1292
+ hash
1293
+ };
1294
+ delete meta.size;
1295
+ delete meta.mtime;
1296
+ return meta;
1297
+ }
1298
+ async #getMetaForFileUsingMtimeAndSize(cacheEntry) {
1299
+ const filePath = this.resolveKeyToFile(cacheEntry.key);
1300
+ const stat$1 = await fs.stat(filePath);
1301
+ const meta = {
1302
+ ...cacheEntry.meta,
1303
+ size: stat$1.size,
1304
+ mtime: stat$1.mtime.getTime()
1183
1305
  };
1306
+ delete meta.hash;
1307
+ return meta;
1308
+ }
1309
+ /**
1310
+ * Sync the files and persist them to the cache
1311
+ */
1312
+ async reconcile() {
1313
+ await this.removeNotFoundFiles();
1314
+ for (const [entryKey, cacheEntry] of this.#normalizedEntries.entries()) try {
1315
+ const meta = this.useChecksum ? await this.#getMetaForFileUsingCheckSum(cacheEntry) : await this.#getMetaForFileUsingMtimeAndSize(cacheEntry);
1316
+ this.cache.set(entryKey, meta);
1317
+ } catch (error) {
1318
+ if (!isNodeError(error) || error.code !== "ENOENT") throw error;
1319
+ }
1320
+ this.cache.save();
1321
+ }
1322
+ resolveKeyToFile(entryKey) {
1323
+ if (this.currentWorkingDir) return path.resolve(this.currentWorkingDir, entryKey);
1324
+ return entryKey;
1325
+ }
1326
+ #getFileKey(file) {
1327
+ if (this.currentWorkingDir && path.isAbsolute(file)) return normalizePath$1(path.relative(this.currentWorkingDir, file));
1328
+ return normalizePath$1(file);
1184
1329
  }
1330
+ };
1331
+ function isNodeError(error) {
1332
+ return typeof error === "object" && error !== null && "code" in error;
1185
1333
  }
1186
- function normalizePath(filePath) {
1187
- if (path$1.sep === "/") return filePath;
1188
- return filePath.split(path$1.sep).join("/");
1334
+ function toError$1(error) {
1335
+ if (error instanceof Error) return error;
1336
+ if (typeof error === "string") return new Error(error);
1337
+ return new Error("Unknown error", { cause: error });
1338
+ }
1339
+ function normalizePath$1(filePath) {
1340
+ if (path.sep === "/") return filePath;
1341
+ return filePath.split(path.sep).join("/");
1342
+ }
1343
+
1344
+ //#endregion
1345
+ //#region src/util/cache/fileEntryCache.ts
1346
+ function createFromFile(cacheFileUrl, useCheckSum, useRelative) {
1347
+ return createFromFile$1(cacheFileUrl, useCheckSum, useRelative ? new URL("./", cacheFileUrl) : void 0);
1189
1348
  }
1190
1349
 
1191
1350
  //#endregion
@@ -1230,31 +1389,29 @@ const META_DATA_VERSION_SUFFIX = "-" + META_DATA_BASE_VERSION + "-" + Object.key
1230
1389
  * Caches cspell results on disk
1231
1390
  */
1232
1391
  var DiskCache = class {
1233
- cacheFileLocation;
1234
1392
  cacheDir;
1235
- fileEntryCache;
1236
1393
  dependencyCache = /* @__PURE__ */ new Map();
1237
1394
  dependencyCacheTree = {};
1238
1395
  objectCollection = new ShallowObjectCollection();
1239
1396
  ocCacheFileResult = new ShallowObjectCollection();
1240
1397
  version;
1241
- constructor(cacheFileLocation, useCheckSum, cspellVersion, useUniversalCache) {
1398
+ constructor(cacheFileLocation, useCheckSum, cspellVersion, useUniversalCache, fileEntryCache) {
1399
+ this.cacheFileLocation = cacheFileLocation;
1242
1400
  this.useCheckSum = useCheckSum;
1243
1401
  this.cspellVersion = cspellVersion;
1244
1402
  this.useUniversalCache = useUniversalCache;
1245
- this.cacheFileLocation = resolve(cacheFileLocation);
1246
- this.cacheDir = dirname(this.cacheFileLocation);
1247
- this.fileEntryCache = createFromFile(this.cacheFileLocation, useCheckSum, useUniversalCache);
1403
+ this.fileEntryCache = fileEntryCache;
1404
+ this.cacheDir = fileURLToPath(new URL("./", cacheFileLocation));
1248
1405
  this.version = calcVersion(cspellVersion);
1249
1406
  }
1250
1407
  async getCachedLintResults(filename) {
1251
1408
  filename = normalizePath(filename);
1252
- const fileDescriptor = this.fileEntryCache.getFileDescriptor(filename);
1409
+ const fileDescriptor = await this.fileEntryCache.getFileDescriptor(filename);
1253
1410
  const meta = fileDescriptor.meta;
1254
1411
  const data = meta?.data;
1255
1412
  const result = data?.r;
1256
1413
  const versionMatches = this.version === data?.v;
1257
- if (fileDescriptor.notFound || fileDescriptor.changed || !meta || !result || !versionMatches || !this.checkDependencies(data.d)) return void 0;
1414
+ if (fileDescriptor.notFound || fileDescriptor.changed || !meta || !result || !versionMatches || !await this.checkDependencies(data.d)) return void 0;
1258
1415
  const dd = { ...data };
1259
1416
  if (dd.d) dd.d = setTreeEntry(this.dependencyCacheTree, dd.d);
1260
1417
  dd.r = dd.r && this.normalizeResult(dd.r);
@@ -1269,22 +1426,22 @@ var DiskCache = class {
1269
1426
  cached
1270
1427
  };
1271
1428
  }
1272
- setCachedLintResults({ fileInfo, elapsedTimeMs: _, cached: __,...result }, dependsUponFiles) {
1273
- const fileDescriptor = this.fileEntryCache.getFileDescriptor(fileInfo.filename);
1429
+ async setCachedLintResults({ fileInfo, elapsedTimeMs: _, cached: __,...result }, dependsUponFiles) {
1430
+ const fileDescriptor = await this.fileEntryCache.getFileDescriptor(fileInfo.filename);
1274
1431
  const meta = fileDescriptor.meta;
1275
1432
  if (fileDescriptor.notFound || !meta) return;
1276
1433
  const data = this.objectCollection.get({
1277
1434
  v: this.version,
1278
1435
  r: this.normalizeResult(result),
1279
- d: this.calcDependencyHashes(dependsUponFiles)
1436
+ d: await this.calcDependencyHashes(dependsUponFiles)
1280
1437
  });
1281
1438
  meta.data = data;
1282
1439
  }
1283
- reconcile() {
1284
- this.fileEntryCache.reconcile();
1440
+ async reconcile() {
1441
+ await this.fileEntryCache.reconcile();
1285
1442
  }
1286
- reset() {
1287
- this.fileEntryCache.destroy();
1443
+ async reset() {
1444
+ await this.fileEntryCache.destroy();
1288
1445
  this.dependencyCache.clear();
1289
1446
  this.dependencyCacheTree = {};
1290
1447
  this.objectCollection = new ShallowObjectCollection();
@@ -1301,19 +1458,19 @@ var DiskCache = class {
1301
1458
  reportIssueOptions
1302
1459
  });
1303
1460
  }
1304
- calcDependencyHashes(dependsUponFiles) {
1461
+ async calcDependencyHashes(dependsUponFiles) {
1305
1462
  dependsUponFiles.sort();
1306
1463
  const c = getTreeEntry(this.dependencyCacheTree, dependsUponFiles);
1307
1464
  if (c?.d) return c.d;
1308
- const dependencies = dependsUponFiles.map((f) => this.getDependency(f));
1465
+ const dependencies = await Promise.all(dependsUponFiles.map((f) => this.getDependency(f)));
1309
1466
  return setTreeEntry(this.dependencyCacheTree, dependencies);
1310
1467
  }
1311
- checkDependency(dep) {
1468
+ async checkDependency(dep) {
1312
1469
  const depFile = this.resolveFile(dep.f);
1313
1470
  const cDep = this.dependencyCache.get(depFile);
1314
1471
  if (cDep && compDep(dep, cDep)) return true;
1315
1472
  if (cDep) return false;
1316
- const d = this.getFileDep(depFile);
1473
+ const d = await this.getFileDep(depFile);
1317
1474
  if (compDep(dep, d)) {
1318
1475
  this.dependencyCache.set(depFile, dep);
1319
1476
  return true;
@@ -1321,19 +1478,23 @@ var DiskCache = class {
1321
1478
  this.dependencyCache.set(depFile, d);
1322
1479
  return false;
1323
1480
  }
1324
- getDependency(file) {
1481
+ async getDependency(file) {
1325
1482
  const dep = this.dependencyCache.get(file);
1326
1483
  if (dep) return dep;
1327
- const d = this.getFileDep(file);
1484
+ const d = await this.getFileDep(file);
1328
1485
  this.dependencyCache.set(file, d);
1329
1486
  return d;
1330
1487
  }
1331
- getFileDep(file) {
1488
+ async getFileDep(file) {
1489
+ if (isUrlLike(file)) {
1490
+ if (!file.startsWith("file://")) return getDependencyForUrl(file);
1491
+ file = toFilePathOrHref(file);
1492
+ }
1332
1493
  assert(isAbsolute(file), `Dependency must be absolute "${file}"`);
1333
1494
  const f = this.toRelFile(file);
1334
1495
  let h;
1335
1496
  try {
1336
- const buffer = fs$1.readFileSync(file);
1497
+ const buffer = await fs.readFile(file);
1337
1498
  h = this.getHash(buffer);
1338
1499
  } catch {
1339
1500
  return { f };
@@ -1343,21 +1504,43 @@ var DiskCache = class {
1343
1504
  h
1344
1505
  };
1345
1506
  }
1346
- checkDependencies(dependencies) {
1507
+ async checkDependencies(dependencies) {
1347
1508
  if (!dependencies) return false;
1348
- for (const dep of dependencies) if (!this.checkDependency(dep)) return false;
1509
+ for (const dep of dependencies) if (!await this.checkDependency(dep)) return false;
1349
1510
  return true;
1350
1511
  }
1351
1512
  getHash(buffer) {
1352
1513
  return crypto.createHash("md5").update(buffer).digest("hex");
1353
1514
  }
1354
1515
  resolveFile(file) {
1516
+ if (isUrlLike(file)) return file;
1355
1517
  return normalizePath(resolve(this.cacheDir, file));
1356
1518
  }
1357
1519
  toRelFile(file) {
1358
1520
  return normalizePath(this.useUniversalCache ? relative(this.cacheDir, file) : file);
1359
1521
  }
1360
1522
  };
1523
+ async function getDependencyForUrl(remoteUrl) {
1524
+ const url = new URL(remoteUrl);
1525
+ try {
1526
+ const response = await fetch(url, { method: "HEAD" });
1527
+ const h = response.headers.get("etag") || response.headers.get("last-modified") || response.headers.get("content-length") || "";
1528
+ return {
1529
+ f: url.href,
1530
+ h: h ? h.trim() : ""
1531
+ };
1532
+ } catch {
1533
+ return {
1534
+ f: url.href,
1535
+ h: ""
1536
+ };
1537
+ }
1538
+ }
1539
+ async function createDiskCache(cacheFileLocation, useCheckSum, cspellVersion, useUniversalCache) {
1540
+ const fileEntryCache = await createFromFile(cacheFileLocation, useCheckSum, useUniversalCache);
1541
+ const cache = new DiskCache(cacheFileLocation, useCheckSum, cspellVersion, useUniversalCache, fileEntryCache);
1542
+ return cache;
1543
+ }
1361
1544
  function getTreeEntry(tree, keys) {
1362
1545
  let r = tree;
1363
1546
  for (const k of keys) {
@@ -1389,6 +1572,10 @@ function compDep(a, b) {
1389
1572
  function calcVersion(version$2) {
1390
1573
  return version$2 + META_DATA_VERSION_SUFFIX;
1391
1574
  }
1575
+ function normalizePath(filePath) {
1576
+ if (sep === "/") return filePath;
1577
+ return filePath.split(sep).join("/");
1578
+ }
1392
1579
 
1393
1580
  //#endregion
1394
1581
  //#region src/util/cache/DummyCache.ts
@@ -1400,13 +1587,13 @@ var DummyCache = class {
1400
1587
  return Promise.resolve(void 0);
1401
1588
  }
1402
1589
  setCachedLintResults() {
1403
- return;
1590
+ return Promise.resolve();
1404
1591
  }
1405
1592
  reconcile() {
1406
- return;
1593
+ return Promise.resolve();
1407
1594
  }
1408
1595
  reset() {
1409
- return;
1596
+ return Promise.resolve();
1410
1597
  }
1411
1598
  };
1412
1599
 
@@ -1417,14 +1604,14 @@ const versionSuffix = "";
1417
1604
  /**
1418
1605
  * Creates CSpellLintResultCache (disk cache if caching is enabled in config or dummy otherwise)
1419
1606
  */
1420
- function createCache(options) {
1607
+ async function createCache(options) {
1421
1608
  const { useCache, cacheLocation, cacheStrategy, reset } = options;
1422
- const location = path.resolve(cacheLocation);
1609
+ const location = toFileURL(cacheLocation);
1423
1610
  const useChecksum = cacheStrategy === "content";
1424
1611
  const version$2 = normalizeVersion(options.version);
1425
1612
  const useUniversal = options.cacheFormat === "universal";
1426
- const cache = useCache ? new DiskCache(location, useChecksum, version$2, useUniversal) : new DummyCache();
1427
- reset && cache.reset();
1613
+ const cache = useCache ? await createDiskCache(location, useChecksum, version$2, useUniversal) : new DummyCache();
1614
+ if (reset) await cache.reset();
1428
1615
  return cache;
1429
1616
  }
1430
1617
  async function calcCacheSettings(config, cacheOptions, root) {
@@ -1752,14 +1939,12 @@ function getTimeMeasurer() {
1752
1939
  //#region src/util/writeFile.ts
1753
1940
  async function writeFileOrStream(filename, data) {
1754
1941
  switch (filename) {
1755
- case "stdout": {
1942
+ case "stdout":
1756
1943
  await writeStream(process.stdout, data);
1757
1944
  return;
1758
- }
1759
- case "stderr": {
1945
+ case "stderr":
1760
1946
  await writeStream(process.stderr, data);
1761
1947
  return;
1762
- }
1763
1948
  case "null": return;
1764
1949
  }
1765
1950
  return fs.writeFile(filename, data);
@@ -1796,7 +1981,7 @@ async function runLint(cfg) {
1796
1981
  result: Promise.resolve({ skip: true })
1797
1982
  };
1798
1983
  const reportIssueOptions = extractReporterIssueOptions(configInfo.config);
1799
- async function fetch() {
1984
+ async function fetch$1() {
1800
1985
  const getElapsedTimeMs = getTimeMeasurer();
1801
1986
  const cachedResult = await cache.getCachedLintResults(filename);
1802
1987
  if (cachedResult) {
@@ -1816,7 +2001,7 @@ async function runLint(cfg) {
1816
2001
  reportIssueOptions
1817
2002
  };
1818
2003
  }
1819
- const result = fetch();
2004
+ const result = fetch$1();
1820
2005
  return {
1821
2006
  filename,
1822
2007
  result
@@ -1902,7 +2087,7 @@ async function runLint(cfg) {
1902
2087
  reporter.debug(JSON.stringify(debugCfg, void 0, 2));
1903
2088
  }
1904
2089
  const dep = calcDependencies(config);
1905
- cache.setCachedLintResults(result, dep.files);
2090
+ await cache.setCachedLintResults(result, dep.files);
1906
2091
  return result;
1907
2092
  }
1908
2093
  function mapIssue({ doc: _,...tdo }) {
@@ -1915,7 +2100,7 @@ async function runLint(cfg) {
1915
2100
  async function processFiles(files, configInfo, cacheSettings) {
1916
2101
  const fileCount = Array.isArray(files) ? files.length : void 0;
1917
2102
  const status = runResult();
1918
- const cache = createCache(cacheSettings);
2103
+ const cache = await createCache(cacheSettings);
1919
2104
  const failFast = cfg.options.failFast ?? configInfo.config.failFast ?? false;
1920
2105
  function* prefetchFiles(files$1) {
1921
2106
  const iter = prefetchIterable(pipe(files$1, opMap$1((filename) => prefetch(filename, configInfo, cache))), BATCH_SIZE);
@@ -1975,7 +2160,7 @@ async function runLint(cfg) {
1975
2160
  }
1976
2161
  status.errors += result.configErrors;
1977
2162
  }
1978
- cache.reconcile();
2163
+ await cache.reconcile();
1979
2164
  return status;
1980
2165
  }
1981
2166
  function calcDependencies(config) {
@@ -2288,22 +2473,18 @@ function extractUnknownWordsConfig(options) {
2288
2473
  const config = {};
2289
2474
  if (!options.report) return config;
2290
2475
  switch (options.report) {
2291
- case "all": {
2476
+ case "all":
2292
2477
  config.unknownWords = unknownWordsChoices.ReportAll;
2293
2478
  break;
2294
- }
2295
- case "simple": {
2479
+ case "simple":
2296
2480
  config.unknownWords = unknownWordsChoices.ReportSimple;
2297
2481
  break;
2298
- }
2299
- case "typos": {
2482
+ case "typos":
2300
2483
  config.unknownWords = unknownWordsChoices.ReportCommonTypos;
2301
2484
  break;
2302
- }
2303
- case "flagged": {
2485
+ case "flagged":
2304
2486
  config.unknownWords = unknownWordsChoices.ReportFlagged;
2305
2487
  break;
2306
- }
2307
2488
  }
2308
2489
  return config;
2309
2490
  }
@@ -2570,4 +2751,4 @@ function parseApplicationFeatureFlags(flags) {
2570
2751
 
2571
2752
  //#endregion
2572
2753
  export { ApplicationError, CheckFailed, DEFAULT_CACHE_LOCATION, IncludeExcludeFlag, ReportChoicesAll, checkText, console, createInit, getReporter, lint, listDictionaries, npmPackage, parseApplicationFeatureFlags, suggestions, trace };
2573
- //# sourceMappingURL=application-D-NwS6qb.js.map
2754
+ //# sourceMappingURL=application-BZlf5spr.js.map
@@ -112,5 +112,5 @@ declare function suggestions(words: string[], options: SuggestionOptions): Async
112
112
  declare function createInit(options: InitOptions): Promise<void>;
113
113
  declare function parseApplicationFeatureFlags(flags: string[] | undefined): FeatureFlags;
114
114
  //#endregion
115
- export { AppError, CheckTextResult, IncludeExcludeFlag, TraceResult, checkText, createInit, lint, listDictionaries, parseApplicationFeatureFlags, suggestions, trace };
116
- //# sourceMappingURL=application-DbOQYm56.d.ts.map
115
+ export { AppError, CheckTextResult, IncludeExcludeFlag, type TraceResult, checkText, createInit, lint, listDictionaries, parseApplicationFeatureFlags, suggestions, trace };
116
+ //# sourceMappingURL=application-D8WjsMdV.d.ts.map
@@ -1,3 +1,3 @@
1
1
  import "./options-ChaXtdFn.js";
2
- import { AppError, CheckTextResult, IncludeExcludeFlag, TraceResult, checkText, createInit, lint, listDictionaries, parseApplicationFeatureFlags, suggestions, trace } from "./application-DbOQYm56.js";
2
+ import { AppError, CheckTextResult, IncludeExcludeFlag, TraceResult, checkText, createInit, lint, listDictionaries, parseApplicationFeatureFlags, suggestions, trace } from "./application-D8WjsMdV.js";
3
3
  export { AppError, CheckTextResult, IncludeExcludeFlag, TraceResult, checkText, createInit, lint, listDictionaries, parseApplicationFeatureFlags, suggestions, trace };
@@ -1,3 +1,3 @@
1
- import { IncludeExcludeFlag, checkText, createInit, lint, listDictionaries, parseApplicationFeatureFlags, suggestions, trace } from "./application-D-NwS6qb.js";
1
+ import { IncludeExcludeFlag, checkText, createInit, lint, listDictionaries, parseApplicationFeatureFlags, suggestions, trace } from "./application-BZlf5spr.js";
2
2
 
3
3
  export { IncludeExcludeFlag, checkText, createInit, lint, listDictionaries, parseApplicationFeatureFlags, suggestions, trace };
@@ -1,5 +1,5 @@
1
1
  import { BaseOptions, LinterCliOptions, TraceOptions } from "./options-ChaXtdFn.js";
2
- import { AppError, CheckTextResult, IncludeExcludeFlag, TraceResult, checkText, createInit, lint, listDictionaries, parseApplicationFeatureFlags, suggestions, trace } from "./application-DbOQYm56.js";
2
+ import { AppError, CheckTextResult, IncludeExcludeFlag, TraceResult, checkText, createInit, lint, listDictionaries, parseApplicationFeatureFlags, suggestions, trace } from "./application-D8WjsMdV.js";
3
3
  import "chalk";
4
4
  import { CSpellReporter, CSpellSettings, ReporterConfiguration, RunResult } from "@cspell/cspell-types";
5
5
  import { WriteStream } from "node:tty";
@@ -51,5 +51,5 @@ interface ReporterOptions extends Pick<LinterCliOptions, "color" | "debug" | "is
51
51
  }
52
52
  declare function getReporter(options: ReporterOptions, config?: CSpellReporterConfiguration): FinalizedReporter;
53
53
  //#endregion
54
- export { AppError, BaseOptions, LinterCliOptions as CSpellApplicationOptions, CSpellReporterConfiguration, CSpellReporterModule, CheckTextResult, IncludeExcludeFlag, TraceOptions, TraceResult, checkText, createInit, getReporter as getDefaultReporter, lint, listDictionaries, parseApplicationFeatureFlags, suggestions, trace };
54
+ export { AppError, type BaseOptions, type LinterCliOptions as CSpellApplicationOptions, type CSpellReporterConfiguration, type CSpellReporterModule, CheckTextResult, IncludeExcludeFlag, type TraceOptions, TraceResult, checkText, createInit, getReporter as getDefaultReporter, lint, listDictionaries, parseApplicationFeatureFlags, suggestions, trace };
55
55
  //# sourceMappingURL=index.d.ts.map
package/dist/esm/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { IncludeExcludeFlag, checkText, createInit, getReporter, lint, listDictionaries, parseApplicationFeatureFlags, suggestions, trace } from "./application-D-NwS6qb.js";
1
+ import { IncludeExcludeFlag, checkText, createInit, getReporter, lint, listDictionaries, parseApplicationFeatureFlags, suggestions, trace } from "./application-BZlf5spr.js";
2
2
 
3
3
  export * from "@cspell/cspell-types"
4
4
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cspell",
3
- "version": "9.1.5",
3
+ "version": "9.2.1",
4
4
  "description": "A Spelling Checker for Code!",
5
5
  "funding": "https://github.com/streetsidesoftware/cspell?sponsor=1",
6
6
  "bin": {
@@ -83,22 +83,22 @@
83
83
  },
84
84
  "homepage": "https://cspell.org/",
85
85
  "dependencies": {
86
- "@cspell/cspell-json-reporter": "9.1.5",
87
- "@cspell/cspell-pipe": "9.1.5",
88
- "@cspell/cspell-types": "9.1.5",
89
- "@cspell/dynamic-import": "9.1.5",
90
- "@cspell/url": "9.1.5",
91
- "chalk": "^5.4.1",
86
+ "@cspell/cspell-json-reporter": "9.2.1",
87
+ "@cspell/cspell-pipe": "9.2.1",
88
+ "@cspell/cspell-types": "9.2.1",
89
+ "@cspell/dynamic-import": "9.2.1",
90
+ "@cspell/url": "9.2.1",
91
+ "chalk": "^5.6.0",
92
92
  "chalk-template": "^1.1.0",
93
93
  "commander": "^14.0.0",
94
- "cspell-config-lib": "9.1.5",
95
- "cspell-dictionary": "9.1.5",
96
- "cspell-gitignore": "9.1.5",
97
- "cspell-glob": "9.1.5",
98
- "cspell-io": "9.1.5",
99
- "cspell-lib": "9.1.5",
94
+ "cspell-config-lib": "9.2.1",
95
+ "cspell-dictionary": "9.2.1",
96
+ "cspell-gitignore": "9.2.1",
97
+ "cspell-glob": "9.2.1",
98
+ "cspell-io": "9.2.1",
99
+ "cspell-lib": "9.2.1",
100
100
  "fast-json-stable-stringify": "^2.1.0",
101
- "file-entry-cache": "^9.1.0",
101
+ "flatted": "^3.3.3",
102
102
  "semver": "^7.7.2",
103
103
  "tinyglobby": "^0.2.14"
104
104
  },
@@ -106,12 +106,11 @@
106
106
  "node": ">=20"
107
107
  },
108
108
  "devDependencies": {
109
- "@types/file-entry-cache": "^5.0.4",
110
109
  "@types/glob": "^8.1.0",
111
110
  "@types/micromatch": "^4.0.9",
112
111
  "@types/semver": "^7.7.0",
113
112
  "micromatch": "^4.0.8",
114
113
  "minimatch": "^9.0.5"
115
114
  },
116
- "gitHead": "6303813cb5da37e88b3ccab7ce5bcf09373f5cf2"
115
+ "gitHead": "3a165c2afd917f4a923c2316f3768eaf18aa3e4b"
117
116
  }