cspell 10.3.5 → 10.4.0-alpha.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 +105 -77
- package/dist/esm/app.d.ts +1 -1
- package/dist/esm/app.js +50 -13
- package/dist/esm/{application-094uTsvC.d.ts → application-CFfMlhE_.d.ts} +11 -3
- package/dist/esm/{application-CdcDwTFc.js → application-DRa52DKq.js} +263 -131
- package/dist/esm/application.d.ts +1 -1
- package/dist/esm/application.js +1 -1
- package/dist/esm/index.d.ts +15 -6
- package/dist/esm/index.js +1 -1
- package/dist/esm/{options-DlXe327y.d.ts → options-D5lC3IZu.d.ts} +18 -1
- package/package.json +65 -65
|
@@ -24,7 +24,7 @@ import { dynamicImport } from "@cspell/dynamic-import";
|
|
|
24
24
|
import crypto from "node:crypto";
|
|
25
25
|
import streamConsumers from "node:stream/consumers";
|
|
26
26
|
import { getStat, readFileText, toURL } from "cspell-io";
|
|
27
|
-
import { glob } from "tinyglobby";
|
|
27
|
+
import { glob, isDynamicPattern } from "tinyglobby";
|
|
28
28
|
import * as readline from "node:readline";
|
|
29
29
|
import { parse, stringify } from "flatted";
|
|
30
30
|
//#region src/console.ts
|
|
@@ -119,6 +119,107 @@ function toApplicationError(e, message) {
|
|
|
119
119
|
return new ApplicationError(message ?? err.message, void 0, err);
|
|
120
120
|
}
|
|
121
121
|
//#endregion
|
|
122
|
+
//#region src/formatIssue.ts
|
|
123
|
+
function formatIssue(io, templateStr, issue, maxIssueTextWidth) {
|
|
124
|
+
function clean(t) {
|
|
125
|
+
return t.replace(/\s+/, " ");
|
|
126
|
+
}
|
|
127
|
+
const { uri = "", filename, row, col, text, context = issue.line, offset } = issue;
|
|
128
|
+
const textLen = issue.length ?? text.length;
|
|
129
|
+
const contextLeft = clean(context.text.slice(0, offset - context.offset));
|
|
130
|
+
const contextRight = clean(context.text.slice(offset + textLen - context.offset));
|
|
131
|
+
const contextFull = clean(context.text);
|
|
132
|
+
const padContext = " ".repeat(Math.max(maxIssueTextWidth - text.length, 0));
|
|
133
|
+
const rowText = row.toString();
|
|
134
|
+
const colText = col.toString();
|
|
135
|
+
const padRowCol = " ".repeat(Math.max(1, 8 - (rowText.length + colText.length)));
|
|
136
|
+
const suggestions = formatSuggestions(io, issue);
|
|
137
|
+
const msg = issue.message || (issue.isFlagged ? "Forbidden word" : "Unknown word");
|
|
138
|
+
const messageColored = issue.isFlagged ? `{yellow ${msg}}` : msg;
|
|
139
|
+
const substitutions = {
|
|
140
|
+
$col: colText,
|
|
141
|
+
$contextFull: contextFull,
|
|
142
|
+
$contextLeft: contextLeft,
|
|
143
|
+
$contextRight: contextRight,
|
|
144
|
+
$filename: filename,
|
|
145
|
+
$padContext: padContext,
|
|
146
|
+
$padRowCol: padRowCol,
|
|
147
|
+
$row: rowText,
|
|
148
|
+
$suggestions: suggestions,
|
|
149
|
+
$text: text,
|
|
150
|
+
$uri: uri,
|
|
151
|
+
$quickFix: formatQuickFix(io, issue),
|
|
152
|
+
$message: msg,
|
|
153
|
+
$messageColored: messageColored
|
|
154
|
+
};
|
|
155
|
+
const t = templateStr.replaceAll("$messageColored", messageColored);
|
|
156
|
+
return substitute(makeTemplate(io.chalk)(t), substitutions).trimEnd();
|
|
157
|
+
}
|
|
158
|
+
function formatSuggestions(io, issue) {
|
|
159
|
+
if (issue.suggestionsEx) return issue.suggestionsEx.map((sug) => sug.isPreferred ? io.chalk.italic(io.chalk.bold(sug.wordAdjustedToMatchCase || sug.word)) + "*" : sug.wordAdjustedToMatchCase || sug.word).join(", ");
|
|
160
|
+
if (issue.suggestions) return issue.suggestions.join(", ");
|
|
161
|
+
return "";
|
|
162
|
+
}
|
|
163
|
+
function formatQuickFix(io, issue) {
|
|
164
|
+
if (!issue.suggestionsEx?.length) return "";
|
|
165
|
+
const preferred = issue.suggestionsEx.filter((sug) => sug.isPreferred).map((sug) => sug.wordAdjustedToMatchCase || sug.word);
|
|
166
|
+
if (!preferred.length) return "";
|
|
167
|
+
return `fix: (${preferred.map((w) => io.chalk.italic(io.chalk.yellow(w))).join(", ")})`;
|
|
168
|
+
}
|
|
169
|
+
function substitute(text, substitutions) {
|
|
170
|
+
const subs = [];
|
|
171
|
+
for (const [match, replaceWith] of Object.entries(substitutions)) {
|
|
172
|
+
const len = match.length;
|
|
173
|
+
for (let i = text.indexOf(match); i >= 0; i = text.indexOf(match, i)) {
|
|
174
|
+
const end = i + len;
|
|
175
|
+
const reg = /\b/y;
|
|
176
|
+
reg.lastIndex = end;
|
|
177
|
+
if (reg.test(text)) subs.push([
|
|
178
|
+
i,
|
|
179
|
+
end,
|
|
180
|
+
replaceWith
|
|
181
|
+
]);
|
|
182
|
+
i = end;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
subs.sort((a, b) => a[0] - b[0]);
|
|
186
|
+
let i = 0;
|
|
187
|
+
function sub(r) {
|
|
188
|
+
const [a, b, t] = r;
|
|
189
|
+
const prefix = text.slice(i, a);
|
|
190
|
+
i = b;
|
|
191
|
+
return prefix + t;
|
|
192
|
+
}
|
|
193
|
+
return subs.map(sub).join("") + text.slice(i);
|
|
194
|
+
}
|
|
195
|
+
function checkTemplate(template) {
|
|
196
|
+
const chalk = new Chalk();
|
|
197
|
+
const chalkTemplate = makeTemplate(chalk);
|
|
198
|
+
const substitutions = {
|
|
199
|
+
$col: "<col>",
|
|
200
|
+
$contextFull: "<contextFull>",
|
|
201
|
+
$contextLeft: "<contextLeft>",
|
|
202
|
+
$contextRight: "<contextRight>",
|
|
203
|
+
$filename: "<filename>",
|
|
204
|
+
$padContext: "<padContext>",
|
|
205
|
+
$padRowCol: "<padRowCol>",
|
|
206
|
+
$row: "<row>",
|
|
207
|
+
$suggestions: "<suggestions>",
|
|
208
|
+
$text: "<text>",
|
|
209
|
+
$uri: "<uri>",
|
|
210
|
+
$quickFix: "<quickFix>",
|
|
211
|
+
$message: "<message>",
|
|
212
|
+
$messageColored: "<messageColored>"
|
|
213
|
+
};
|
|
214
|
+
try {
|
|
215
|
+
const problems = [...substitute(chalkTemplate(template), substitutions).matchAll(/\$[a-z]+/gi)].map((m) => m[0]);
|
|
216
|
+
if (problems.length) throw new Error(`Unresolved template variable${problems.length > 1 ? "s" : ""}: ${problems.map((v) => `'${v}'`).join(", ")}`);
|
|
217
|
+
return true;
|
|
218
|
+
} catch (e) {
|
|
219
|
+
return new ApplicationError(e instanceof Error ? e.message : `${e}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
//#endregion
|
|
122
223
|
//#region src/util/perfMeasurements.ts
|
|
123
224
|
function getPerfMeasurements() {
|
|
124
225
|
const measurements = performance.getEntriesByType("measure");
|
|
@@ -563,6 +664,9 @@ function getReporter(options, config) {
|
|
|
563
664
|
filesCached: 0,
|
|
564
665
|
accumulatedTimeMs: 0,
|
|
565
666
|
startTime: performance.now(),
|
|
667
|
+
firstFileStartTime: 0,
|
|
668
|
+
lastFileEndTime: 0,
|
|
669
|
+
betweenFilesTimeMs: 0,
|
|
566
670
|
perf: Object.create(null)
|
|
567
671
|
};
|
|
568
672
|
const noColor = options.color === false;
|
|
@@ -637,13 +741,19 @@ function getReporter(options, config) {
|
|
|
637
741
|
errorCollection.forEach((error) => consoleError(error));
|
|
638
742
|
}
|
|
639
743
|
if (options.showPerfSummary) {
|
|
640
|
-
const
|
|
744
|
+
const now = performance.now();
|
|
745
|
+
const elapsedTotal = now - perfStats.startTime;
|
|
746
|
+
const setupTime = (perfStats.firstFileStartTime || now) - perfStats.startTime;
|
|
747
|
+
const otherTime = elapsedTotal - setupTime - perfStats.accumulatedTimeMs - perfStats.betweenFilesTimeMs;
|
|
641
748
|
consoleError("-------------------------------------------");
|
|
642
749
|
consoleError("Performance Summary:");
|
|
643
750
|
consoleError(` Files Processed : ${perfStats.filesProcessed.toString().padStart(11)}`);
|
|
644
751
|
consoleError(` Files Skipped : ${perfStats.filesSkipped.toString().padStart(11)}`);
|
|
645
752
|
consoleError(` Files Cached : ${perfStats.filesCached.toString().padStart(11)}`);
|
|
753
|
+
consoleError(` Setup Time : ${setupTime.toFixed(2).padStart(9)}ms`);
|
|
646
754
|
consoleError(` Processing Time : ${perfStats.accumulatedTimeMs.toFixed(2).padStart(9)}ms`);
|
|
755
|
+
consoleError(` Between Files : ${perfStats.betweenFilesTimeMs.toFixed(2).padStart(9)}ms`);
|
|
756
|
+
consoleError(` Other Time : ${otherTime.toFixed(2).padStart(9)}ms`);
|
|
647
757
|
consoleError(` Total Time : ${elapsedTotal.toFixed(2).padStart(9)}ms`);
|
|
648
758
|
const tableStats = {
|
|
649
759
|
title: chalk.bold("Perf Stats:"),
|
|
@@ -755,7 +865,15 @@ function getReporter(options, config) {
|
|
|
755
865
|
}
|
|
756
866
|
function progress(p) {
|
|
757
867
|
if (!silent && showProgress) reportProgress(stderr, p, rootURL, options);
|
|
758
|
-
if (p.type === "
|
|
868
|
+
if (p.type === "ProgressFileBegin") {
|
|
869
|
+
const now = performance.now();
|
|
870
|
+
perfStats.firstFileStartTime ||= now;
|
|
871
|
+
if (perfStats.lastFileEndTime) perfStats.betweenFilesTimeMs += now - perfStats.lastFileEndTime;
|
|
872
|
+
}
|
|
873
|
+
if (p.type === "ProgressFileComplete") {
|
|
874
|
+
perfStats.lastFileEndTime = performance.now();
|
|
875
|
+
collectPerfStats(p);
|
|
876
|
+
}
|
|
759
877
|
}
|
|
760
878
|
return {
|
|
761
879
|
issue: relativeIssue(silent || !issues ? nullEmitter : genIssueEmitter(stdio, stderr, issueTemplate, uniqueIssues, issuesCollection)),
|
|
@@ -764,7 +882,7 @@ function getReporter(options, config) {
|
|
|
764
882
|
debug: emitters.Debug,
|
|
765
883
|
progress,
|
|
766
884
|
result: !silent && summary ? resultEmitter : nullEmitter,
|
|
767
|
-
features:
|
|
885
|
+
features: { issueType: true }
|
|
768
886
|
};
|
|
769
887
|
}
|
|
770
888
|
function extractNotableBySelfTimeInGroup(measurements) {
|
|
@@ -788,109 +906,10 @@ function extractNotableBySelfTimeInGroup(measurements) {
|
|
|
788
906
|
if (highest) notable.add(highest);
|
|
789
907
|
return notable;
|
|
790
908
|
}
|
|
791
|
-
function formatIssue(io, templateStr, issue, maxIssueTextWidth) {
|
|
792
|
-
function clean(t) {
|
|
793
|
-
return t.replace(/\s+/, " ");
|
|
794
|
-
}
|
|
795
|
-
const { uri = "", filename, row, col, text, context = issue.line, offset } = issue;
|
|
796
|
-
const textLen = issue.length ?? text.length;
|
|
797
|
-
const contextLeft = clean(context.text.slice(0, offset - context.offset));
|
|
798
|
-
const contextRight = clean(context.text.slice(offset + textLen - context.offset));
|
|
799
|
-
const contextFull = clean(context.text);
|
|
800
|
-
const padContext = " ".repeat(Math.max(maxIssueTextWidth - text.length, 0));
|
|
801
|
-
const rowText = row.toString();
|
|
802
|
-
const colText = col.toString();
|
|
803
|
-
const padRowCol = " ".repeat(Math.max(1, 8 - (rowText.length + colText.length)));
|
|
804
|
-
const suggestions = formatSuggestions(io, issue);
|
|
805
|
-
const msg = issue.message || (issue.isFlagged ? "Forbidden word" : "Unknown word");
|
|
806
|
-
const messageColored = issue.isFlagged ? `{yellow ${msg}}` : msg;
|
|
807
|
-
const substitutions = {
|
|
808
|
-
$col: colText,
|
|
809
|
-
$contextFull: contextFull,
|
|
810
|
-
$contextLeft: contextLeft,
|
|
811
|
-
$contextRight: contextRight,
|
|
812
|
-
$filename: filename,
|
|
813
|
-
$padContext: padContext,
|
|
814
|
-
$padRowCol: padRowCol,
|
|
815
|
-
$row: rowText,
|
|
816
|
-
$suggestions: suggestions,
|
|
817
|
-
$text: text,
|
|
818
|
-
$uri: uri,
|
|
819
|
-
$quickFix: formatQuickFix(io, issue),
|
|
820
|
-
$message: msg,
|
|
821
|
-
$messageColored: messageColored
|
|
822
|
-
};
|
|
823
|
-
const t = templateStr.replaceAll("$messageColored", messageColored);
|
|
824
|
-
return substitute(makeTemplate(io.chalk)(t), substitutions).trimEnd();
|
|
825
|
-
}
|
|
826
|
-
function formatSuggestions(io, issue) {
|
|
827
|
-
if (issue.suggestionsEx) return issue.suggestionsEx.map((sug) => sug.isPreferred ? io.chalk.italic(io.chalk.bold(sug.wordAdjustedToMatchCase || sug.word)) + "*" : sug.wordAdjustedToMatchCase || sug.word).join(", ");
|
|
828
|
-
if (issue.suggestions) return issue.suggestions.join(", ");
|
|
829
|
-
return "";
|
|
830
|
-
}
|
|
831
|
-
function formatQuickFix(io, issue) {
|
|
832
|
-
if (!issue.suggestionsEx?.length) return "";
|
|
833
|
-
const preferred = issue.suggestionsEx.filter((sug) => sug.isPreferred).map((sug) => sug.wordAdjustedToMatchCase || sug.word);
|
|
834
|
-
if (!preferred.length) return "";
|
|
835
|
-
return `fix: (${preferred.map((w) => io.chalk.italic(io.chalk.yellow(w))).join(", ")})`;
|
|
836
|
-
}
|
|
837
|
-
function substitute(text, substitutions) {
|
|
838
|
-
const subs = [];
|
|
839
|
-
for (const [match, replaceWith] of Object.entries(substitutions)) {
|
|
840
|
-
const len = match.length;
|
|
841
|
-
for (let i = text.indexOf(match); i >= 0; i = text.indexOf(match, i)) {
|
|
842
|
-
const end = i + len;
|
|
843
|
-
const reg = /\b/y;
|
|
844
|
-
reg.lastIndex = end;
|
|
845
|
-
if (reg.test(text)) subs.push([
|
|
846
|
-
i,
|
|
847
|
-
end,
|
|
848
|
-
replaceWith
|
|
849
|
-
]);
|
|
850
|
-
i = end;
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
subs.sort((a, b) => a[0] - b[0]);
|
|
854
|
-
let i = 0;
|
|
855
|
-
function sub(r) {
|
|
856
|
-
const [a, b, t] = r;
|
|
857
|
-
const prefix = text.slice(i, a);
|
|
858
|
-
i = b;
|
|
859
|
-
return prefix + t;
|
|
860
|
-
}
|
|
861
|
-
return subs.map(sub).join("") + text.slice(i);
|
|
862
|
-
}
|
|
863
909
|
function assertCheckTemplate(template) {
|
|
864
910
|
const r = checkTemplate(template);
|
|
865
911
|
if (r instanceof Error) throw r;
|
|
866
912
|
}
|
|
867
|
-
function checkTemplate(template) {
|
|
868
|
-
const chalk = new Chalk();
|
|
869
|
-
const chalkTemplate = makeTemplate(chalk);
|
|
870
|
-
const substitutions = {
|
|
871
|
-
$col: "<col>",
|
|
872
|
-
$contextFull: "<contextFull>",
|
|
873
|
-
$contextLeft: "<contextLeft>",
|
|
874
|
-
$contextRight: "<contextRight>",
|
|
875
|
-
$filename: "<filename>",
|
|
876
|
-
$padContext: "<padContext>",
|
|
877
|
-
$padRowCol: "<padRowCol>",
|
|
878
|
-
$row: "<row>",
|
|
879
|
-
$suggestions: "<suggestions>",
|
|
880
|
-
$text: "<text>",
|
|
881
|
-
$uri: "<uri>",
|
|
882
|
-
$quickFix: "<quickFix>",
|
|
883
|
-
$message: "<message>",
|
|
884
|
-
$messageColored: "<messageColored>"
|
|
885
|
-
};
|
|
886
|
-
try {
|
|
887
|
-
const problems = [...substitute(chalkTemplate(template), substitutions).matchAll(/\$[a-z]+/gi)].map((m) => m[0]);
|
|
888
|
-
if (problems.length) throw new Error(`Unresolved template variable${problems.length > 1 ? "s" : ""}: ${problems.map((v) => `'${v}'`).join(", ")}`);
|
|
889
|
-
return true;
|
|
890
|
-
} catch (e) {
|
|
891
|
-
return new ApplicationError(e instanceof Error ? e.message : `${e}`);
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
913
|
//#endregion
|
|
895
914
|
//#region src/config/adjustConfig.ts
|
|
896
915
|
async function fileExists(url) {
|
|
@@ -1183,7 +1202,9 @@ const environmentKeys = {
|
|
|
1183
1202
|
CSPELL_ENABLE_DICTIONARY_LOG_FIELDS: "CSPELL_ENABLE_DICTIONARY_LOG_FIELDS",
|
|
1184
1203
|
CSPELL_GLOB_ROOT: "CSPELL_GLOB_ROOT",
|
|
1185
1204
|
CSPELL_CONFIG_PATH: "CSPELL_CONFIG_PATH",
|
|
1186
|
-
CSPELL_DEFAULT_CONFIG_PATH: "CSPELL_DEFAULT_CONFIG_PATH"
|
|
1205
|
+
CSPELL_DEFAULT_CONFIG_PATH: "CSPELL_DEFAULT_CONFIG_PATH",
|
|
1206
|
+
CSPELL_FOLLOW_SYMLINKS: "CSPELL_FOLLOW_SYMLINKS",
|
|
1207
|
+
CSPELL_GLOB_SYMLINKS: "CSPELL_GLOB_SYMLINKS"
|
|
1187
1208
|
};
|
|
1188
1209
|
function setEnvironmentVariable(key, value) {
|
|
1189
1210
|
process.env[key] = value;
|
|
@@ -1213,7 +1234,7 @@ try {
|
|
|
1213
1234
|
const pkgDir = _dirname;
|
|
1214
1235
|
const npmPackage = {
|
|
1215
1236
|
name: "cspell",
|
|
1216
|
-
version: "10.
|
|
1237
|
+
version: "10.4.0-alpha.1",
|
|
1217
1238
|
engines: { node: ">=22.18.0" }
|
|
1218
1239
|
};
|
|
1219
1240
|
//#endregion
|
|
@@ -1351,7 +1372,7 @@ var LintReporter = class {
|
|
|
1351
1372
|
});
|
|
1352
1373
|
}
|
|
1353
1374
|
emitProgressComplete(filename, fileNum, fileCount, result) {
|
|
1354
|
-
const numIssues = result.issues.filter((issue) => filterFeatureIssues({}, issue, result.reportIssueOptions)).length;
|
|
1375
|
+
const numIssues = result.issues.filter((issue) => filterFeatureIssues({ issueType: true }, issue, result.reportIssueOptions)).length;
|
|
1355
1376
|
for (const reporter of this.#reporters) {
|
|
1356
1377
|
const progress = clean({
|
|
1357
1378
|
type: "ProgressFileComplete",
|
|
@@ -1448,7 +1469,7 @@ async function globP(pattern, options) {
|
|
|
1448
1469
|
dot,
|
|
1449
1470
|
ignore,
|
|
1450
1471
|
absolute: true,
|
|
1451
|
-
followSymbolicLinks: false,
|
|
1472
|
+
followSymbolicLinks: options?.followSymlinks ?? false,
|
|
1452
1473
|
expandDirectories: false
|
|
1453
1474
|
});
|
|
1454
1475
|
const compare = new Intl.Collator("en").compare;
|
|
@@ -1992,18 +2013,20 @@ var DiskCache = class {
|
|
|
1992
2013
|
cspellVersion;
|
|
1993
2014
|
useUniversalCache;
|
|
1994
2015
|
fileEntryCache;
|
|
2016
|
+
optionsKey;
|
|
1995
2017
|
cacheDir;
|
|
1996
2018
|
dependencyCache = /* @__PURE__ */ new Map();
|
|
1997
2019
|
dependencyCacheTree = {};
|
|
1998
2020
|
objectCollection = new ShallowObjectCollection();
|
|
1999
2021
|
ocCacheFileResult = new ShallowObjectCollection();
|
|
2000
2022
|
version;
|
|
2001
|
-
constructor(cacheFileLocation, useCheckSum, cspellVersion, useUniversalCache, fileEntryCache) {
|
|
2023
|
+
constructor(cacheFileLocation, useCheckSum, cspellVersion, useUniversalCache, fileEntryCache, optionsKey) {
|
|
2002
2024
|
this.cacheFileLocation = cacheFileLocation;
|
|
2003
2025
|
this.useCheckSum = useCheckSum;
|
|
2004
2026
|
this.cspellVersion = cspellVersion;
|
|
2005
2027
|
this.useUniversalCache = useUniversalCache;
|
|
2006
2028
|
this.fileEntryCache = fileEntryCache;
|
|
2029
|
+
this.optionsKey = optionsKey;
|
|
2007
2030
|
this.cacheDir = fileURLToPath(new URL("./", cacheFileLocation));
|
|
2008
2031
|
this.version = calcVersion(cspellVersion);
|
|
2009
2032
|
}
|
|
@@ -2014,7 +2037,8 @@ var DiskCache = class {
|
|
|
2014
2037
|
const data = meta?.data;
|
|
2015
2038
|
const result = data?.r;
|
|
2016
2039
|
const versionMatches = this.version === data?.v;
|
|
2017
|
-
|
|
2040
|
+
const optionsMatch = this.optionsKey === data?.o;
|
|
2041
|
+
if (fileDescriptor.notFound || fileDescriptor.changed || !meta || !result || !versionMatches || !optionsMatch || !await this.checkDependencies(data.d)) return;
|
|
2018
2042
|
const dd = { ...data };
|
|
2019
2043
|
if (dd.d) dd.d = setTreeEntry(this.dependencyCacheTree, dd.d);
|
|
2020
2044
|
dd.r = dd.r && this.normalizeResult(dd.r);
|
|
@@ -2036,7 +2060,8 @@ var DiskCache = class {
|
|
|
2036
2060
|
meta.data = this.objectCollection.get({
|
|
2037
2061
|
v: this.version,
|
|
2038
2062
|
r: this.normalizeResult(result),
|
|
2039
|
-
d: await this.calcDependencyHashes(dependsUponFiles)
|
|
2063
|
+
d: await this.calcDependencyHashes(dependsUponFiles),
|
|
2064
|
+
...this.optionsKey ? { o: this.optionsKey } : {}
|
|
2040
2065
|
});
|
|
2041
2066
|
}
|
|
2042
2067
|
async reconcile() {
|
|
@@ -2138,8 +2163,8 @@ async function getDependencyForUrl(remoteUrl) {
|
|
|
2138
2163
|
};
|
|
2139
2164
|
}
|
|
2140
2165
|
}
|
|
2141
|
-
async function createDiskCache(cacheFileLocation, useCheckSum, cspellVersion, useUniversalCache) {
|
|
2142
|
-
return new DiskCache(cacheFileLocation, useCheckSum, cspellVersion, useUniversalCache, await createFromFile(cacheFileLocation, useCheckSum, useUniversalCache));
|
|
2166
|
+
async function createDiskCache(cacheFileLocation, useCheckSum, cspellVersion, useUniversalCache, optionsKey) {
|
|
2167
|
+
return new DiskCache(cacheFileLocation, useCheckSum, cspellVersion, useUniversalCache, await createFromFile(cacheFileLocation, useCheckSum, useUniversalCache), optionsKey);
|
|
2143
2168
|
}
|
|
2144
2169
|
function getTreeEntry(tree, keys) {
|
|
2145
2170
|
let r = tree;
|
|
@@ -2208,7 +2233,7 @@ async function createCache(options) {
|
|
|
2208
2233
|
const useChecksum = cacheStrategy === "content";
|
|
2209
2234
|
const version = normalizeVersion(options.version);
|
|
2210
2235
|
const useUniversal = options.cacheFormat === "universal";
|
|
2211
|
-
const cache = useCache ? await createDiskCache(location, useChecksum, version, useUniversal) : new DummyCache();
|
|
2236
|
+
const cache = useCache ? await createDiskCache(location, useChecksum, version, useUniversal, options.optionsKey) : new DummyCache();
|
|
2212
2237
|
if (reset) await cache.reset();
|
|
2213
2238
|
return cache;
|
|
2214
2239
|
}
|
|
@@ -2220,6 +2245,8 @@ async function calcCacheSettings(config, cacheOptions, root) {
|
|
|
2220
2245
|
const cacheFormat = cacheOptions.cacheFormat ?? cs.cacheFormat ?? "universal";
|
|
2221
2246
|
const optionals = {};
|
|
2222
2247
|
if (cacheOptions.cacheReset) optionals.reset = true;
|
|
2248
|
+
const optionsKey = calcOptionsKey(cacheOptions);
|
|
2249
|
+
if (optionsKey) optionals.optionsKey = optionsKey;
|
|
2223
2250
|
return {
|
|
2224
2251
|
...optionals,
|
|
2225
2252
|
useCache,
|
|
@@ -2229,6 +2256,17 @@ async function calcCacheSettings(config, cacheOptions, root) {
|
|
|
2229
2256
|
cacheFormat
|
|
2230
2257
|
};
|
|
2231
2258
|
}
|
|
2259
|
+
function calcOptionsKey(cacheOptions) {
|
|
2260
|
+
const { languageId, locale, report, showSuggestions, validateDirectives } = cacheOptions;
|
|
2261
|
+
const set = Object.entries({
|
|
2262
|
+
languageId: languageId || void 0,
|
|
2263
|
+
locale: locale || void 0,
|
|
2264
|
+
report: report || void 0,
|
|
2265
|
+
showSuggestions,
|
|
2266
|
+
validateDirectives
|
|
2267
|
+
}).filter(([, value]) => value !== void 0);
|
|
2268
|
+
return set.length ? JSON.stringify(Object.fromEntries(set)) : void 0;
|
|
2269
|
+
}
|
|
2232
2270
|
async function resolveCacheLocation(cacheLocation) {
|
|
2233
2271
|
try {
|
|
2234
2272
|
if ((await stat(cacheLocation)).isFile()) return cacheLocation;
|
|
@@ -2288,6 +2326,48 @@ async function readConfigHandleError(filename) {
|
|
|
2288
2326
|
}
|
|
2289
2327
|
}
|
|
2290
2328
|
//#endregion
|
|
2329
|
+
//#region src/util/symlinks.ts
|
|
2330
|
+
function createSymlinkChecker(root) {
|
|
2331
|
+
const rootPath = path$1.resolve(root);
|
|
2332
|
+
const cache = /* @__PURE__ */ new Map();
|
|
2333
|
+
function isSymlink(filename) {
|
|
2334
|
+
let found = cache.get(filename);
|
|
2335
|
+
if (!found) {
|
|
2336
|
+
found = promises.lstat(filename).then((s) => s.isSymbolicLink(), () => false);
|
|
2337
|
+
cache.set(filename, found);
|
|
2338
|
+
}
|
|
2339
|
+
return found;
|
|
2340
|
+
}
|
|
2341
|
+
async function isReachedThroughSymlink(filename) {
|
|
2342
|
+
if (filename === "stdin" || isStdinUrl(filename)) return false;
|
|
2343
|
+
const absFilename = path$1.resolve(rootPath, filename);
|
|
2344
|
+
const rel = path$1.relative(rootPath, absFilename);
|
|
2345
|
+
if (!rel) return false;
|
|
2346
|
+
if (rel === ".." || rel.startsWith(".." + path$1.sep) || path$1.isAbsolute(rel)) return isSymlink(absFilename);
|
|
2347
|
+
let current = rootPath;
|
|
2348
|
+
for (const segment of rel.split(path$1.sep)) {
|
|
2349
|
+
current = path$1.join(current, segment);
|
|
2350
|
+
if (await isSymlink(current)) return true;
|
|
2351
|
+
}
|
|
2352
|
+
return false;
|
|
2353
|
+
}
|
|
2354
|
+
async function isGlobReachedThroughSymlink(pattern) {
|
|
2355
|
+
const segments = pattern.split("/");
|
|
2356
|
+
const fixed = [];
|
|
2357
|
+
for (const segment of segments) {
|
|
2358
|
+
if (isDynamicPattern(segment)) break;
|
|
2359
|
+
fixed.push(segment);
|
|
2360
|
+
}
|
|
2361
|
+
const base = fixed.join("/");
|
|
2362
|
+
if (!base) return false;
|
|
2363
|
+
return isReachedThroughSymlink(path$1.resolve(rootPath, base));
|
|
2364
|
+
}
|
|
2365
|
+
return {
|
|
2366
|
+
isReachedThroughSymlink,
|
|
2367
|
+
isGlobReachedThroughSymlink
|
|
2368
|
+
};
|
|
2369
|
+
}
|
|
2370
|
+
//#endregion
|
|
2291
2371
|
//#region src/util/timer.ts
|
|
2292
2372
|
function getTimeMeasurer() {
|
|
2293
2373
|
const timer = createPerfTimer("timer");
|
|
@@ -2687,13 +2767,30 @@ function prefetch(fileToProcess, cfg) {
|
|
|
2687
2767
|
const reportIssueOptions = extractReporterIssueOptions(cfg.config);
|
|
2688
2768
|
async function fetch() {
|
|
2689
2769
|
const getElapsedTimeMs = getTimeMeasurer();
|
|
2770
|
+
if (!cfg.followSymlinks && await cfg.symlinks.isReachedThroughSymlink(filename)) {
|
|
2771
|
+
const skipReason = "referenced by a symbolic link, use --follow-symlinks to check it";
|
|
2772
|
+
if (cfg.forceCheck) return {
|
|
2773
|
+
skip: true,
|
|
2774
|
+
skipReason,
|
|
2775
|
+
error: new LinterError(`File ${skipReason}: "${filename}"`)
|
|
2776
|
+
};
|
|
2777
|
+
return {
|
|
2778
|
+
skip: true,
|
|
2779
|
+
skipReason: cfg.verbose ? skipReason : void 0
|
|
2780
|
+
};
|
|
2781
|
+
}
|
|
2690
2782
|
const cachedResult = await cfg.cache.getCachedLintResults(filename);
|
|
2691
2783
|
if (cachedResult) return { fileResult: {
|
|
2692
2784
|
...cachedResult,
|
|
2693
2785
|
elapsedTimeMs: getElapsedTimeMs()
|
|
2694
2786
|
} };
|
|
2695
2787
|
const uri = filenameToUri(filename, cfg.root).href;
|
|
2696
|
-
const
|
|
2788
|
+
const { languageId, locale } = cfg;
|
|
2789
|
+
const checkResult = await shouldCheckDocument({
|
|
2790
|
+
uri,
|
|
2791
|
+
languageId,
|
|
2792
|
+
locale
|
|
2793
|
+
}, { forceCheck: cfg.forceCheck }, cfg.config);
|
|
2697
2794
|
if (!checkResult.shouldCheck) return {
|
|
2698
2795
|
skip: true,
|
|
2699
2796
|
skipReason: checkResult.reason || "Ignored by configuration."
|
|
@@ -2725,6 +2822,11 @@ async function processFiles(files, options) {
|
|
|
2725
2822
|
root: options.cfg.root,
|
|
2726
2823
|
maxFileSize: options.cfg.maxFileSize,
|
|
2727
2824
|
forceCheck: !!options.cfg.options.forceCheck,
|
|
2825
|
+
symlinks: options.symlinks ?? createSymlinkChecker(options.cfg.root),
|
|
2826
|
+
followSymlinks: !!options.followSymlinks,
|
|
2827
|
+
verbose: options.verboseLevel > 0,
|
|
2828
|
+
languageId: options.cfg.options.languageId || void 0,
|
|
2829
|
+
locale: options.cfg.locale || void 0,
|
|
2728
2830
|
config: options.configInfo.config,
|
|
2729
2831
|
cache
|
|
2730
2832
|
};
|
|
@@ -2760,17 +2862,24 @@ async function processFiles(files, options) {
|
|
|
2760
2862
|
if (fetchResult instanceof Error) throw fetchResult;
|
|
2761
2863
|
const fileNum = sequence + 1;
|
|
2762
2864
|
reporter.emitProgressBegin(filename, fileNum, pf.sequenceSize ?? sequence);
|
|
2763
|
-
if (fetchResult?.skip)
|
|
2764
|
-
|
|
2765
|
-
sequence,
|
|
2766
|
-
sequenceSize,
|
|
2767
|
-
result: {
|
|
2865
|
+
if (fetchResult?.skip) {
|
|
2866
|
+
const result = {
|
|
2768
2867
|
...emptyResult,
|
|
2769
2868
|
fileInfo: { filename },
|
|
2770
2869
|
elapsedTimeMs: getElapsedTimeMs(),
|
|
2771
2870
|
skippedReason: fetchResult.skipReason
|
|
2871
|
+
};
|
|
2872
|
+
if (fetchResult.error) {
|
|
2873
|
+
new ReportItemCollector(result).error("Linter:", fetchResult.error);
|
|
2874
|
+
result.errors = 1;
|
|
2772
2875
|
}
|
|
2773
|
-
|
|
2876
|
+
return {
|
|
2877
|
+
filename,
|
|
2878
|
+
sequence,
|
|
2879
|
+
sequenceSize,
|
|
2880
|
+
result
|
|
2881
|
+
};
|
|
2882
|
+
}
|
|
2774
2883
|
return {
|
|
2775
2884
|
filename,
|
|
2776
2885
|
sequence,
|
|
@@ -2826,7 +2935,7 @@ function runResult(init = {}) {
|
|
|
2826
2935
|
};
|
|
2827
2936
|
}
|
|
2828
2937
|
//#endregion
|
|
2829
|
-
//#region \0@oxc-project+runtime@0.
|
|
2938
|
+
//#region \0@oxc-project+runtime@0.151.0/helpers/esm/usingCtx.js
|
|
2830
2939
|
function _usingCtx() {
|
|
2831
2940
|
var r = "function" == typeof SuppressedError ? SuppressedError : function(r, e) {
|
|
2832
2941
|
var n = Error();
|
|
@@ -2935,7 +3044,8 @@ async function runLint(cfg) {
|
|
|
2935
3044
|
...cfg.options,
|
|
2936
3045
|
version
|
|
2937
3046
|
}, root);
|
|
2938
|
-
const
|
|
3047
|
+
const symlinks = createSymlinkChecker(root);
|
|
3048
|
+
const filesToCheck = await determineFilesToCheck(configInfo, cfg, reporter, globInfo, symlinks);
|
|
2939
3049
|
const processFilesOptions = {
|
|
2940
3050
|
chalk,
|
|
2941
3051
|
configInfo,
|
|
@@ -2945,7 +3055,9 @@ async function runLint(cfg) {
|
|
|
2945
3055
|
configErrors,
|
|
2946
3056
|
userSettings: configInfo.config,
|
|
2947
3057
|
lintReporter: reporter,
|
|
2948
|
-
cacheSettings
|
|
3058
|
+
cacheSettings,
|
|
3059
|
+
symlinks,
|
|
3060
|
+
followSymlinks: filesToCheck.followSymlinks
|
|
2949
3061
|
};
|
|
2950
3062
|
const result = await processFiles(filesToCheck.files, processFilesOptions);
|
|
2951
3063
|
if (configErrorCount && cfg.options.exitCode !== false) result.errors ||= configErrorCount;
|
|
@@ -3026,10 +3138,11 @@ function filesToProcess(files) {
|
|
|
3026
3138
|
sequenceSize
|
|
3027
3139
|
}));
|
|
3028
3140
|
}
|
|
3029
|
-
async function determineFilesToCheck(configInfo, cfg, reporter, globInfo) {
|
|
3141
|
+
async function determineFilesToCheck(configInfo, cfg, reporter, globInfo, symlinks) {
|
|
3030
3142
|
const result = {
|
|
3031
3143
|
files: [],
|
|
3032
|
-
numFiles: 0
|
|
3144
|
+
numFiles: 0,
|
|
3145
|
+
followSymlinks: false
|
|
3033
3146
|
};
|
|
3034
3147
|
function countFiles(fnKeep) {
|
|
3035
3148
|
if (!fnKeep) return () => {
|
|
@@ -3047,6 +3160,13 @@ async function determineFilesToCheck(configInfo, cfg, reporter, globInfo) {
|
|
|
3047
3160
|
async function determineFilesToCheckFromCliFiles() {
|
|
3048
3161
|
const { fileLists } = cfg;
|
|
3049
3162
|
const hasFileLists = !!fileLists.length;
|
|
3163
|
+
const followSymlinks = cfg.options.followSymlinks ?? truthy(getEnvironmentVariable("CSPELL_FOLLOW_SYMLINKS"));
|
|
3164
|
+
result.followSymlinks = followSymlinks;
|
|
3165
|
+
const keepSymlinks = (fn) => followSymlinks ? fn : async (file) => await symlinks.isReachedThroughSymlink(file) || fn(file);
|
|
3166
|
+
if (!followSymlinks) for (const fileList of fileLists) {
|
|
3167
|
+
if (fileList === "stdin") continue;
|
|
3168
|
+
if (await symlinks.isReachedThroughSymlink(path$1.resolve(fileList))) throw new ApplicationError(`Error reading file list from: "${fileList}". It is referenced by a symbolic link, use --follow-symlinks to read it.`);
|
|
3169
|
+
}
|
|
3050
3170
|
const { gitIgnore, allGlobs, excludeGlobs, normalizedExcludes } = globInfo;
|
|
3051
3171
|
const { root } = cfg;
|
|
3052
3172
|
const globsToExcludeRaw = [...configInfo.config.ignorePaths || [], ...excludeGlobs];
|
|
@@ -3066,8 +3186,8 @@ async function determineFilesToCheck(configInfo, cfg, reporter, globInfo) {
|
|
|
3066
3186
|
if (enableGlobDot !== void 0) globOptions.dot = enableGlobDot;
|
|
3067
3187
|
const includeFilterCountSkipped = countFiles(cfg.options.forceCheck && !cfg.fileGlobs.length ? () => true : createIncludeFileFilterFn(allGlobs, root, enableGlobDot));
|
|
3068
3188
|
const rawCliFiles = cfg.files?.map((file) => resolveFilename(file, root)).filter(includeFilterCountSkipped);
|
|
3069
|
-
const cliFiles = cfg.options.mustFindFiles ? rawCliFiles : rawCliFiles && pipeAsync(rawCliFiles, opFilterAsync(isFile));
|
|
3070
|
-
const foundFiles = hasFileLists ? concatAsyncIterables(cliFiles, await useFileLists(fileLists, includeFilterCountSkipped)) : cliFiles || [];
|
|
3189
|
+
const cliFiles = cfg.options.mustFindFiles ? rawCliFiles : rawCliFiles && pipeAsync(rawCliFiles, opFilterAsync(keepSymlinks(isFile)));
|
|
3190
|
+
const foundFiles = hasFileLists ? concatAsyncIterables(cliFiles, await useFileLists(fileLists, includeFilterCountSkipped, keepSymlinks(isNotDir))) : cliFiles || [];
|
|
3071
3191
|
const opFilterExcludedFiles = opFilter(filterOutExcludedFilesFn(globMatcher));
|
|
3072
3192
|
const filtered = !cfg.options.forceCheck && gitIgnore ? await gitIgnore.filterOutIgnored(foundFiles) : foundFiles;
|
|
3073
3193
|
return isAsyncIterable(filtered) ? pipeAsync(filtered, opFilterExcludedFiles, filesToProcessAsync) : filesToProcess(pipe(filtered, opFilterExcludedFiles));
|
|
@@ -3090,8 +3210,19 @@ async function determineFilesToCheck(configInfo, cfg, reporter, globInfo) {
|
|
|
3090
3210
|
};
|
|
3091
3211
|
const enableGlobDot = cfg.enableGlobDot ?? configInfo.config.enableGlobDot;
|
|
3092
3212
|
if (enableGlobDot !== void 0) globOptions.dot = enableGlobDot;
|
|
3213
|
+
const globSymlinks = cfg.options.globSymlinks ?? truthy(getEnvironmentVariable("CSPELL_GLOB_SYMLINKS"));
|
|
3214
|
+
globOptions.followSymlinks = globSymlinks;
|
|
3215
|
+
result.followSymlinks = globSymlinks;
|
|
3093
3216
|
const opFilterExcludedFiles = opFilter(filterOutExcludedFilesFn(globMatcher));
|
|
3094
|
-
const
|
|
3217
|
+
const globsToSearch = [];
|
|
3218
|
+
for (const glob of fileGlobs) {
|
|
3219
|
+
if (!globSymlinks && await symlinks.isGlobReachedThroughSymlink(glob)) {
|
|
3220
|
+
if (calcVerboseLevel(cfg.options) > 0) reporter.info(`Glob not searched: "${glob}" goes through a symbolic link.`, MessageTypes$1.Info);
|
|
3221
|
+
continue;
|
|
3222
|
+
}
|
|
3223
|
+
globsToSearch.push(glob);
|
|
3224
|
+
}
|
|
3225
|
+
const foundFiles = await findFiles(globsToSearch, globOptions);
|
|
3095
3226
|
const filtered = gitIgnore ? await gitIgnore.filterOutIgnored(foundFiles) : foundFiles;
|
|
3096
3227
|
return isAsyncIterable(filtered) ? pipeAsync(filtered, opFilterExcludedFiles, filesToProcessAsync, opFilter(countFiles())) : filesToProcess(pipe(filtered, opFilterExcludedFiles)).filter(countFiles());
|
|
3097
3228
|
}
|
|
@@ -3158,9 +3289,9 @@ async function generateGitIgnore(roots) {
|
|
|
3158
3289
|
}
|
|
3159
3290
|
return new GitIgnore(root?.map((p) => path$1.resolve(p)));
|
|
3160
3291
|
}
|
|
3161
|
-
async function useFileLists(fileListFiles, filterFiles) {
|
|
3292
|
+
async function useFileLists(fileListFiles, filterFiles, filterNotDir) {
|
|
3162
3293
|
const files = readFileListFiles(fileListFiles);
|
|
3163
|
-
return pipeAsync(files, opFilter(filterFiles), opFilterAsync(
|
|
3294
|
+
return pipeAsync(files, opFilter(filterFiles), opFilterAsync(filterNotDir));
|
|
3164
3295
|
}
|
|
3165
3296
|
function createIncludeFileFilterFn(includeGlobPatterns, root, dot) {
|
|
3166
3297
|
if (!includeGlobPatterns?.length) return () => true;
|
|
@@ -3227,6 +3358,7 @@ var LintRequest = class {
|
|
|
3227
3358
|
}];
|
|
3228
3359
|
this.cspellSettingsFromCliOptions = {
|
|
3229
3360
|
...noConfigSearch !== void 0 ? { noConfigSearch } : {},
|
|
3361
|
+
...options.validateDirectives !== void 0 ? { validateDirectives: options.validateDirectives } : {},
|
|
3230
3362
|
...extractUnknownWordsConfig(options),
|
|
3231
3363
|
languageSettings
|
|
3232
3364
|
};
|
|
@@ -3534,4 +3666,4 @@ function parseApplicationFeatureFlags(flags) {
|
|
|
3534
3666
|
//#endregion
|
|
3535
3667
|
export { ApplicationError as C, width as S, console as T, padLeft as _, parseApplicationFeatureFlags as a, pruneAnsiTextEnd as b, listDictionaries as c, validateUnitSize as d, unindent as f, tableToLines as g, getReporter as h, lint as i, ReportChoicesAll as l, npmPackage as m, checkText as n, suggestions as o, DEFAULT_CACHE_LOCATION as p, createInit as r, trace as s, IncludeExcludeFlag as t, cvtLinterCliCommandOptionsToLinterCliOptions as u, padWidth as v, CheckFailed as w, pruneAnsiTextStart as x, ansiWidth as y };
|
|
3536
3668
|
|
|
3537
|
-
//# sourceMappingURL=application-
|
|
3669
|
+
//# sourceMappingURL=application-DRa52DKq.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as checkText, c as parseApplicationFeatureFlags, d as listDictionaries, i as TraceResult, l as suggestions, n as CheckTextResult, o as createInit, r as IncludeExcludeFlag, s as lint, t as AppError, u as trace } from "./application-
|
|
1
|
+
import { a as checkText, c as parseApplicationFeatureFlags, d as listDictionaries, i as TraceResult, l as suggestions, n as CheckTextResult, o as createInit, r as IncludeExcludeFlag, s as lint, t as AppError, u as trace } from "./application-CFfMlhE_.js";
|
|
2
2
|
export { AppError, CheckTextResult, IncludeExcludeFlag, type TraceResult, checkText, createInit, lint, listDictionaries, parseApplicationFeatureFlags, suggestions, trace };
|
package/dist/esm/application.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as parseApplicationFeatureFlags, c as listDictionaries, i as lint, n as checkText, o as suggestions, r as createInit, s as trace, t as IncludeExcludeFlag } from "./application-
|
|
1
|
+
import { a as parseApplicationFeatureFlags, c as listDictionaries, i as lint, n as checkText, o as suggestions, r as createInit, s as trace, t as IncludeExcludeFlag } from "./application-DRa52DKq.js";
|
|
2
2
|
export { IncludeExcludeFlag, checkText, createInit, lint, listDictionaries, parseApplicationFeatureFlags, suggestions, trace };
|