Skip to content

Commit

Permalink
fix(cli): don't cache resolved diagnostics
Browse files Browse the repository at this point in the history
  • Loading branch information
johnsoncodehk committed Dec 16, 2024
1 parent 7cdb4a3 commit bcbea1b
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 86 deletions.
9 changes: 4 additions & 5 deletions packages/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -397,16 +397,15 @@ class Project {
if (fileCache[0] !== fileMtime) {
fileCache[0] = fileMtime;
fileCache[1] = {};
fileCache[2].length = 0;
fileCache[3].length = 0;
fileCache[4] = {};
fileCache[2] = {};
fileCache[3] = {};
}
else {
cached++;
}
}
else {
project.cache[fileName] = fileCache = [fileMtime, {}, [], [], {}];
project.cache[fileName] = fileCache = [fileMtime, {}, {}, {}];
}

let diagnostics!: ts.DiagnosticWithLocation[];
Expand Down Expand Up @@ -445,7 +444,7 @@ class Project {
log(output);
}
}
} else if (!(await linterWorker.hasRules(fileName, fileCache[4]))) {
} else if (!(await linterWorker.hasRules(fileName, fileCache[3]))) {
excluded++;
} else {
passed++;
Expand Down
10 changes: 4 additions & 6 deletions packages/cli/lib/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,13 +225,12 @@ function lintAndFix(fileName: string, fileCache: core.FileLintCache) {
if (Object.values(fileCache[1]).some(fixes => fixes > 0)) {
// Reset the cache if there are any fixes applied.
fileCache[1] = {};
fileCache[2].length = 0;
fileCache[3].length = 0;
fileCache[2] = {};
}
diagnostics = linter.lint(fileName, fileCache);

let fixes = linter
.getCodeFixes(fileName, 0, Number.MAX_VALUE, diagnostics, fileCache[4])
.getCodeFixes(fileName, 0, Number.MAX_VALUE, diagnostics, fileCache[3])
.filter(fix => fix.fixId === 'tsslint');

if (language) {
Expand All @@ -256,8 +255,7 @@ function lintAndFix(fileName: string, fileCache: core.FileLintCache) {
ts.sys.writeFile(fileName, newSnapshot.getText(0, newSnapshot.getLength()));
fileCache[0] = fs.statSync(fileName).mtimeMs;
fileCache[1] = {};
fileCache[2].length = 0;
fileCache[3].length = 0;
fileCache[2] = {};
}

if (shouldRetry) {
Expand Down Expand Up @@ -353,6 +351,6 @@ function hasCodeFixes(fileName: string) {
return linter.hasCodeFixes(fileName);
}

function hasRules(fileName: string, minimatchCache: core.FileLintCache[4]) {
function hasRules(fileName: string, minimatchCache: core.FileLintCache[3]) {
return [Object.keys(linter.getRules(fileName, minimatchCache)).length > 0, minimatchCache] as const;
}
110 changes: 35 additions & 75 deletions packages/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ import minimatch = require('minimatch');
export type FileLintCache = [
mtime: number,
ruleFixes: Record<string, number>,
result: ts.DiagnosticWithLocation[],
resolvedResult: ts.DiagnosticWithLocation[],
result: Record<string, ts.DiagnosticWithLocation[]>,
minimatchResult: Record<string, boolean>,
];

Expand Down Expand Up @@ -68,17 +67,15 @@ export function createLinter(

return {
lint(fileName: string, cache?: FileLintCache): ts.DiagnosticWithLocation[] {
let cacheableDiagnostics: ts.DiagnosticWithLocation[] = [];
let uncacheableDiagnostics: ts.DiagnosticWithLocation[] = [];
let diagnostics: ts.DiagnosticWithLocation[] = [];
let currentRuleId: string;
let currentIssues = 0;
let currentFixes = 0;
let currentRefactors = 0;
let currentRuleLanguageServiceUsage = 0;
let sourceFile: ts.SourceFile | undefined;
let hasUncacheResult = false;

const rules = getFileRules(fileName, cache?.[4]);
const rules = getFileRules(fileName, cache?.[3]);
const rulesContext: RuleContext = {
...ctx,
languageService,
Expand All @@ -92,13 +89,7 @@ export function createLinter(
const token = ctx.languageServiceHost.getCancellationToken?.();
const fixes = getFileFixes(fileName);
const refactors = getFileRefactors(fileName);
const cachedRules = new Map<string, number>();

if (cache) {
for (const ruleId in cache[1]) {
cachedRules.set(ruleId, cache[1][ruleId]);
}
}
const configs = getFileConfigs(fileName, cache?.[3]);

fixes.clear();
refactors.length = 0;
Expand All @@ -107,62 +98,16 @@ export function createLinter(
return this.lint(fileName, cache);
}

const configs = getFileConfigs(fileName, cache?.[4]);

if (cache) {
for (const [ruleId, fixes] of cachedRules) {
cache[1][ruleId] = fixes;
}
}

let diagnostics: ts.DiagnosticWithLocation[];

if (hasUncacheResult) {
diagnostics = [
...(cacheableDiagnostics.length
? cacheableDiagnostics
: (cache?.[2] ?? []).map(data => ({
...data,
file: rulesContext.sourceFile,
relatedInformation: data.relatedInformation?.map(info => ({
...info,
file: info.file ? getSourceFile(info.file.fileName) : undefined,
})),
}))
),
...uncacheableDiagnostics,
];
for (const { plugins } of configs) {
for (const { resolveDiagnostics } of plugins) {
if (resolveDiagnostics) {
diagnostics = resolveDiagnostics(rulesContext.sourceFile, diagnostics);
}
for (const { plugins } of configs) {
for (const { resolveDiagnostics } of plugins) {
if (resolveDiagnostics) {
diagnostics = resolveDiagnostics(rulesContext.sourceFile, diagnostics);
}
}
if (cache) {
cache[3] = diagnostics.map(data => ({
...data,
file: undefined as any,
relatedInformation: data.relatedInformation?.map(info => ({
...info,
file: info.file ? { fileName: info.file.fileName } as any : undefined,
})),
}));
}
}
else {
diagnostics = (cache?.[3] ?? []).map(data => ({
...data,
file: rulesContext.sourceFile,
relatedInformation: data.relatedInformation?.map(info => ({
...info,
file: info.file ? getSourceFile(info.file.fileName) : undefined,
})),
}));
}

// Remove fixes and refactors that removed by resolveDiagnostics
const diagnosticSet = new Set(diagnostics);

for (const diagnostic of [...fixes.keys()]) {
if (!diagnosticSet.has(diagnostic)) {
fixes.delete(diagnostic);
Expand Down Expand Up @@ -190,12 +135,23 @@ export function createLinter(
currentFixes = 0;
currentRefactors = 0;

if (cachedRules.has(currentRuleId)) {
continue;
if (cache) {
const ruleCache = cache[2][currentRuleId];
if (ruleCache) {
diagnostics.push(
...ruleCache.map(data => ({
...data,
file: rulesContext.sourceFile,
relatedInformation: data.relatedInformation?.map(info => ({
...info,
file: info.file ? getSourceFile(info.file.fileName) : undefined,
})),
}))
);
continue;
}
}

hasUncacheResult = true;

try {
rule(rulesContext);
} catch (err) {
Expand All @@ -209,8 +165,11 @@ export function createLinter(
}
}

if (cache && currentRuleLanguageServiceUsage === languageServiceUsage) {
cachedRules.set(currentRuleId, currentFixes);
if (cache) {
if (currentRuleLanguageServiceUsage === languageServiceUsage) {
cache[1][currentRuleId] = currentFixes;
cache[2][currentRuleId] ??= [];
}
}
}
return true;
Expand Down Expand Up @@ -242,7 +201,8 @@ export function createLinter(
const cacheable = currentRuleLanguageServiceUsage === languageServiceUsage;

if (cache && cacheable) {
cache[2].push({
cache[2][currentRuleId] ??= [];
cache[2][currentRuleId].push({
...error,
file: undefined as any,
relatedInformation: error.relatedInformation?.map(info => ({
Expand All @@ -261,7 +221,7 @@ export function createLinter(
}

fixes.set(error, []);
(cacheable ? cacheableDiagnostics : uncacheableDiagnostics).push(error);
diagnostics.push(error);
currentIssues++;

return {
Expand Down Expand Up @@ -307,7 +267,7 @@ export function createLinter(
start: number,
end: number,
diagnostics?: ts.Diagnostic[],
minimatchCache?: FileLintCache[4]
minimatchCache?: FileLintCache[3]
) {

const configs = getFileConfigs(fileName, minimatchCache);
Expand Down Expand Up @@ -409,7 +369,7 @@ export function createLinter(
throw new Error('No source file');
}

function getFileRules(fileName: string, minimatchCache: undefined | FileLintCache[4]) {
function getFileRules(fileName: string, minimatchCache: undefined | FileLintCache[3]) {
let result = fileRules.get(fileName);
if (!result) {
result = {};
Expand All @@ -432,7 +392,7 @@ export function createLinter(
return result;
}

function getFileConfigs(fileName: string, minimatchCache: undefined | FileLintCache[4]) {
function getFileConfigs(fileName: string, minimatchCache: undefined | FileLintCache[3]) {
let result = fileConfigs.get(fileName);
if (!result) {
result = configs.filter(({ include, exclude }) => {
Expand Down

0 comments on commit bcbea1b

Please sign in to comment.