@tsslint/core 1.5.3 → 1.5.4
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/index.d.ts +2 -2
- package/index.js +506 -493
- package/package.json +3 -3
package/index.d.ts
CHANGED
|
@@ -23,8 +23,8 @@ export declare function createLinter(ctx: ProjectContext, rootDir: string, confi
|
|
|
23
23
|
getRefactorEdits(fileName: string, actionName: string): ts.FileTextChanges[] | undefined;
|
|
24
24
|
getRules: (fileName: string, minimatchCache: undefined | FileLintCache[2]) => Record<string, Rule>;
|
|
25
25
|
getConfigs: (fileName: string, minimatchCache: undefined | FileLintCache[2]) => {
|
|
26
|
-
include: string[];
|
|
27
|
-
exclude: string[];
|
|
26
|
+
include: string[] | undefined;
|
|
27
|
+
exclude: string[] | undefined;
|
|
28
28
|
rules: Rules;
|
|
29
29
|
formatting: FormattingProcess[] | undefined;
|
|
30
30
|
plugins: import("@tsslint/types").PluginInstance[];
|
package/index.js
CHANGED
|
@@ -1,17 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function (o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) {
|
|
4
|
+
k2 = k;
|
|
5
|
+
}
|
|
6
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
7
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
8
|
+
desc = { enumerable: true, get: function () { return m[k]; } };
|
|
9
|
+
}
|
|
10
|
+
Object.defineProperty(o, k2, desc);
|
|
11
|
+
}) : (function (o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) {
|
|
13
|
+
k2 = k;
|
|
14
|
+
}
|
|
15
|
+
o[k2] = m[k];
|
|
12
16
|
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
|
|
17
|
+
var __exportStar = (this && this.__exportStar) || function (m, exports) {
|
|
18
|
+
for (var p in m) {
|
|
19
|
+
if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) {
|
|
20
|
+
__createBinding(exports, m, p);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
15
23
|
};
|
|
16
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
25
|
exports.createLinter = createLinter;
|
|
@@ -24,493 +32,498 @@ const ErrorStackParser = require("error-stack-parser");
|
|
|
24
32
|
const path = require("path");
|
|
25
33
|
const minimatch = require("minimatch");
|
|
26
34
|
function createLinter(ctx, rootDir, config, mode, syntaxOnlyLanguageService) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
35
|
+
const ts = ctx.typescript;
|
|
36
|
+
const fileRules = new Map();
|
|
37
|
+
const fileFmtProcesses = new Map();
|
|
38
|
+
const fileConfigs = new Map();
|
|
39
|
+
const lintResults = new Map();
|
|
40
|
+
const configs = (Array.isArray(config) ? config : [config])
|
|
41
|
+
.map(config => ({
|
|
42
|
+
include: config.include,
|
|
43
|
+
exclude: config.exclude,
|
|
44
|
+
rules: config.rules ?? {},
|
|
45
|
+
formatting: config.formatting,
|
|
46
|
+
plugins: (config.plugins ?? []).map(plugin => plugin(ctx)),
|
|
47
|
+
}));
|
|
48
|
+
const normalizedPath = new Map();
|
|
49
|
+
const rule2Mode = new Map();
|
|
50
|
+
const getNonBoundSourceFile = syntaxOnlyLanguageService?.getNonBoundSourceFile;
|
|
51
|
+
let shouldEnableTypeAware = false;
|
|
52
|
+
return {
|
|
53
|
+
format(sourceFile, minimatchCache) {
|
|
54
|
+
const preprocess = getFileFmtProcesses(sourceFile.fileName, minimatchCache);
|
|
55
|
+
const changes = [];
|
|
56
|
+
const tmpChanges = [];
|
|
57
|
+
const fmtCtx = {
|
|
58
|
+
typescript: ts,
|
|
59
|
+
sourceFile,
|
|
60
|
+
insert(pos, text) {
|
|
61
|
+
tmpChanges.push({ span: { start: pos, length: 0 }, newText: text });
|
|
62
|
+
},
|
|
63
|
+
remove(start, end) {
|
|
64
|
+
tmpChanges.push({ span: { start, length: end - start }, newText: '' });
|
|
65
|
+
},
|
|
66
|
+
replace(start, end, text) {
|
|
67
|
+
tmpChanges.push({ span: { start, length: end - start }, newText: text });
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
for (const process of preprocess) {
|
|
71
|
+
process(fmtCtx);
|
|
72
|
+
if (tmpChanges.every(a => {
|
|
73
|
+
const aStart = a.span.start;
|
|
74
|
+
const aEnd = aStart + a.span.length;
|
|
75
|
+
for (const b of changes) {
|
|
76
|
+
const bStart = b.span.start;
|
|
77
|
+
const bEnd = bStart + b.span.length;
|
|
78
|
+
if ((bStart >= aEnd && bStart > aStart)
|
|
79
|
+
|| (bEnd <= aStart && bEnd < aEnd)) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
return true;
|
|
85
|
+
})) {
|
|
86
|
+
changes.push(...tmpChanges);
|
|
87
|
+
}
|
|
88
|
+
tmpChanges.length = 0;
|
|
89
|
+
}
|
|
90
|
+
return changes;
|
|
91
|
+
},
|
|
92
|
+
lint(fileName, cache) {
|
|
93
|
+
const configs = getFileConfigs(fileName, cache?.[2]);
|
|
94
|
+
if (!configs.length) {
|
|
95
|
+
lintResults.set(fileName, [rulesContext.sourceFile, new Map(), []]);
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let currentRuleId;
|
|
100
|
+
let shouldRetry = false;
|
|
101
|
+
const rules = getFileRules(fileName, cache?.[2]);
|
|
102
|
+
const typeAwareMode = !getNonBoundSourceFile
|
|
103
|
+
|| shouldEnableTypeAware && !Object.keys(rules).some(ruleId => !rule2Mode.has(ruleId));
|
|
104
|
+
const rulesContext = typeAwareMode
|
|
105
|
+
? {
|
|
106
|
+
...ctx,
|
|
107
|
+
sourceFile: ctx.languageService.getProgram().getSourceFile(fileName),
|
|
108
|
+
reportError,
|
|
109
|
+
reportWarning,
|
|
110
|
+
reportSuggestion,
|
|
111
|
+
}
|
|
112
|
+
: {
|
|
113
|
+
...ctx,
|
|
114
|
+
languageService: syntaxOnlyLanguageService,
|
|
115
|
+
sourceFile: getNonBoundSourceFile(fileName),
|
|
116
|
+
reportError,
|
|
117
|
+
reportWarning,
|
|
118
|
+
reportSuggestion,
|
|
119
|
+
};
|
|
120
|
+
const token = ctx.languageServiceHost.getCancellationToken?.();
|
|
121
|
+
lintResults.set(fileName, [rulesContext.sourceFile, new Map(), []]);
|
|
122
|
+
const lintResult = lintResults.get(fileName);
|
|
123
|
+
for (const [ruleId, rule] of Object.entries(rules)) {
|
|
124
|
+
if (token?.isCancellationRequested()) {
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
currentRuleId = ruleId;
|
|
128
|
+
const ruleCache = cache?.[1][currentRuleId];
|
|
129
|
+
if (ruleCache) {
|
|
130
|
+
let lintResult = lintResults.get(fileName);
|
|
131
|
+
if (!lintResult) {
|
|
132
|
+
lintResults.set(fileName, lintResult = [rulesContext.sourceFile, new Map(), []]);
|
|
133
|
+
}
|
|
134
|
+
for (const cacheDiagnostic of ruleCache[1]) {
|
|
135
|
+
lintResult[1].set({
|
|
136
|
+
...cacheDiagnostic,
|
|
137
|
+
file: rulesContext.sourceFile,
|
|
138
|
+
relatedInformation: cacheDiagnostic.relatedInformation?.map(info => ({
|
|
139
|
+
...info,
|
|
140
|
+
file: info.file ? syntaxOnlyLanguageService.getNonBoundSourceFile(info.file.fileName) : undefined,
|
|
141
|
+
})),
|
|
142
|
+
}, []);
|
|
143
|
+
}
|
|
144
|
+
if (!typeAwareMode) {
|
|
145
|
+
rule2Mode.set(currentRuleId, false);
|
|
146
|
+
}
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
try {
|
|
150
|
+
rule(rulesContext);
|
|
151
|
+
if (!typeAwareMode) {
|
|
152
|
+
rule2Mode.set(currentRuleId, false);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
if (!typeAwareMode) {
|
|
157
|
+
// console.log(`Rule "${currentRuleId}" is type aware.`);
|
|
158
|
+
rule2Mode.set(currentRuleId, true);
|
|
159
|
+
shouldRetry = true;
|
|
160
|
+
}
|
|
161
|
+
else if (err instanceof Error) {
|
|
162
|
+
report(ts.DiagnosticCategory.Error, err.stack ?? err.message, 0, 0, 0, err);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
report(ts.DiagnosticCategory.Error, String(err), 0, 0, false);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (cache && !rule2Mode.get(currentRuleId)) {
|
|
169
|
+
cache[1][currentRuleId] ??= [false, []];
|
|
170
|
+
for (const [_, fixes] of lintResult[1]) {
|
|
171
|
+
if (fixes.length) {
|
|
172
|
+
cache[1][currentRuleId][0] = true;
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (shouldRetry) {
|
|
179
|
+
// Retry
|
|
180
|
+
shouldEnableTypeAware = true;
|
|
181
|
+
return this.lint(fileName, cache);
|
|
182
|
+
}
|
|
183
|
+
let diagnostics = [...lintResult[1].keys()];
|
|
184
|
+
try {
|
|
185
|
+
for (const { plugins } of configs) {
|
|
186
|
+
for (const { resolveDiagnostics } of plugins) {
|
|
187
|
+
if (resolveDiagnostics) {
|
|
188
|
+
diagnostics = resolveDiagnostics(rulesContext.sourceFile, diagnostics);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
if (!typeAwareMode) {
|
|
195
|
+
// Retry
|
|
196
|
+
shouldEnableTypeAware = true;
|
|
197
|
+
return this.lint(fileName, cache);
|
|
198
|
+
}
|
|
199
|
+
throw error;
|
|
200
|
+
}
|
|
201
|
+
// Remove fixes and refactors that removed by resolveDiagnostics
|
|
202
|
+
const diagnosticSet = new Set(diagnostics);
|
|
203
|
+
for (const diagnostic of [...lintResult[1].keys()]) {
|
|
204
|
+
if (!diagnosticSet.has(diagnostic)) {
|
|
205
|
+
lintResult[1].delete(diagnostic);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
lintResult[2] = lintResult[2].filter(refactor => diagnosticSet.has(refactor.diagnostic));
|
|
209
|
+
return diagnostics;
|
|
210
|
+
function reportError(message, start, end, stackOffset) {
|
|
211
|
+
return report(ts.DiagnosticCategory.Error, message, start, end, stackOffset);
|
|
212
|
+
}
|
|
213
|
+
function reportWarning(message, start, end, stackOffset) {
|
|
214
|
+
return report(ts.DiagnosticCategory.Warning, message, start, end, stackOffset);
|
|
215
|
+
}
|
|
216
|
+
function reportSuggestion(message, start, end, stackOffset) {
|
|
217
|
+
return report(ts.DiagnosticCategory.Suggestion, message, start, end, stackOffset);
|
|
218
|
+
}
|
|
219
|
+
function report(category, message, start, end, stackOffset = 2, err) {
|
|
220
|
+
const error = {
|
|
221
|
+
category,
|
|
222
|
+
code: currentRuleId,
|
|
223
|
+
messageText: message,
|
|
224
|
+
file: rulesContext.sourceFile,
|
|
225
|
+
start,
|
|
226
|
+
length: end - start,
|
|
227
|
+
source: 'tsslint',
|
|
228
|
+
relatedInformation: [],
|
|
229
|
+
};
|
|
230
|
+
if (cache && !rule2Mode.get(currentRuleId)) {
|
|
231
|
+
cache[1][currentRuleId] ??= [false, []];
|
|
232
|
+
cache[1][currentRuleId][1].push({
|
|
233
|
+
...error,
|
|
234
|
+
file: undefined,
|
|
235
|
+
relatedInformation: error.relatedInformation?.map(info => ({
|
|
236
|
+
...info,
|
|
237
|
+
file: info.file ? { fileName: info.file.fileName } : undefined,
|
|
238
|
+
})),
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
if (mode === 'typescript-plugin' && typeof stackOffset === 'number') {
|
|
242
|
+
err ??= new Error();
|
|
243
|
+
const relatedInfo = createRelatedInformation(ts, err, stackOffset);
|
|
244
|
+
if (relatedInfo) {
|
|
245
|
+
error.relatedInformation.push(relatedInfo);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
let lintResult = lintResults.get(fileName);
|
|
249
|
+
if (!lintResult) {
|
|
250
|
+
lintResults.set(fileName, lintResult = [rulesContext.sourceFile, new Map(), []]);
|
|
251
|
+
}
|
|
252
|
+
const diagnostic2Fixes = lintResult[1];
|
|
253
|
+
const refactors = lintResult[2];
|
|
254
|
+
diagnostic2Fixes.set(error, []);
|
|
255
|
+
const fixes = diagnostic2Fixes.get(error);
|
|
256
|
+
return {
|
|
257
|
+
withDeprecated() {
|
|
258
|
+
error.reportsDeprecated = true;
|
|
259
|
+
return this;
|
|
260
|
+
},
|
|
261
|
+
withUnnecessary() {
|
|
262
|
+
error.reportsUnnecessary = true;
|
|
263
|
+
return this;
|
|
264
|
+
},
|
|
265
|
+
withFix(title, getEdits) {
|
|
266
|
+
fixes.push(({ title, getEdits }));
|
|
267
|
+
return this;
|
|
268
|
+
},
|
|
269
|
+
withRefactor(title, getEdits) {
|
|
270
|
+
refactors.push(({
|
|
271
|
+
diagnostic: error,
|
|
272
|
+
title,
|
|
273
|
+
getEdits,
|
|
274
|
+
}));
|
|
275
|
+
return this;
|
|
276
|
+
},
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
hasCodeFixes(fileName) {
|
|
281
|
+
const lintResult = lintResults.get(fileName);
|
|
282
|
+
if (!lintResult) {
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
for (const [_, fixes] of lintResult[1]) {
|
|
286
|
+
if (fixes.length) {
|
|
287
|
+
return true;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return false;
|
|
291
|
+
},
|
|
292
|
+
getCodeFixes(fileName, start, end, diagnostics, minimatchCache) {
|
|
293
|
+
const lintResult = lintResults.get(fileName);
|
|
294
|
+
if (!lintResult) {
|
|
295
|
+
return [];
|
|
296
|
+
}
|
|
297
|
+
const sourceFile = lintResult[0];
|
|
298
|
+
const configs = getFileConfigs(fileName, minimatchCache);
|
|
299
|
+
const result = [];
|
|
300
|
+
for (const [diagnostic, actions] of lintResult[1]) {
|
|
301
|
+
if (diagnostics?.length && !diagnostics.includes(diagnostic)) {
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
const diagStart = diagnostic.start;
|
|
305
|
+
const diagEnd = diagStart + diagnostic.length;
|
|
306
|
+
if ((diagStart >= start && diagStart <= end) ||
|
|
307
|
+
(diagEnd >= start && diagEnd <= end) ||
|
|
308
|
+
(start >= diagStart && start <= diagEnd) ||
|
|
309
|
+
(end >= diagStart && end <= diagEnd)) {
|
|
310
|
+
let codeFixes = [];
|
|
311
|
+
for (const action of actions) {
|
|
312
|
+
codeFixes.push({
|
|
313
|
+
fixName: `tsslint:${diagnostic.code}`,
|
|
314
|
+
description: action.title,
|
|
315
|
+
changes: action.getEdits(),
|
|
316
|
+
fixId: 'tsslint',
|
|
317
|
+
fixAllDescription: 'Fix all TSSLint errors'
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
for (const { plugins } of configs) {
|
|
321
|
+
for (const { resolveCodeFixes } of plugins) {
|
|
322
|
+
if (resolveCodeFixes) {
|
|
323
|
+
codeFixes = resolveCodeFixes(sourceFile, diagnostic, codeFixes);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
result.push(...codeFixes);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return result;
|
|
331
|
+
},
|
|
332
|
+
getRefactors(fileName, start, end) {
|
|
333
|
+
const lintResult = lintResults.get(fileName);
|
|
334
|
+
if (!lintResult) {
|
|
335
|
+
return [];
|
|
336
|
+
}
|
|
337
|
+
const result = [];
|
|
338
|
+
for (let i = 0; i < lintResult[2].length; i++) {
|
|
339
|
+
const refactor = lintResult[2][i];
|
|
340
|
+
const diagStart = refactor.diagnostic.start;
|
|
341
|
+
const diagEnd = diagStart + refactor.diagnostic.length;
|
|
342
|
+
if ((diagStart >= start && diagStart <= end) ||
|
|
343
|
+
(diagEnd >= start && diagEnd <= end) ||
|
|
344
|
+
(start >= diagStart && start <= diagEnd) ||
|
|
345
|
+
(end >= diagStart && end <= diagEnd)) {
|
|
346
|
+
result.push({
|
|
347
|
+
name: `tsslint:${i}`,
|
|
348
|
+
description: refactor.title,
|
|
349
|
+
kind: 'quickfix',
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return result;
|
|
354
|
+
},
|
|
355
|
+
getRefactorEdits(fileName, actionName) {
|
|
356
|
+
if (actionName.startsWith('tsslint:')) {
|
|
357
|
+
const lintResult = lintResults.get(fileName);
|
|
358
|
+
if (!lintResult) {
|
|
359
|
+
return [];
|
|
360
|
+
}
|
|
361
|
+
const index = actionName.slice('tsslint:'.length);
|
|
362
|
+
const refactor = lintResult[2][Number(index)];
|
|
363
|
+
if (refactor) {
|
|
364
|
+
return refactor.getEdits();
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
},
|
|
368
|
+
getRules: getFileRules,
|
|
369
|
+
getConfigs: getFileConfigs,
|
|
370
|
+
};
|
|
371
|
+
function getFileFmtProcesses(fileName, minimatchCache) {
|
|
372
|
+
if (!fileFmtProcesses.has(fileName)) {
|
|
373
|
+
const allPreprocess = [];
|
|
374
|
+
const configs = getFileConfigs(fileName, minimatchCache);
|
|
375
|
+
for (const { formatting } of configs) {
|
|
376
|
+
if (formatting) {
|
|
377
|
+
allPreprocess.push(...formatting);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
fileFmtProcesses.set(fileName, allPreprocess);
|
|
381
|
+
}
|
|
382
|
+
return fileFmtProcesses.get(fileName);
|
|
383
|
+
}
|
|
384
|
+
function getFileRules(fileName, minimatchCache) {
|
|
385
|
+
let rules = fileRules.get(fileName);
|
|
386
|
+
if (!rules) {
|
|
387
|
+
rules = {};
|
|
388
|
+
const configs = getFileConfigs(fileName, minimatchCache);
|
|
389
|
+
for (const config of configs) {
|
|
390
|
+
collectRules(rules, config.rules, []);
|
|
391
|
+
}
|
|
392
|
+
for (const { plugins } of configs) {
|
|
393
|
+
for (const { resolveRules } of plugins) {
|
|
394
|
+
if (resolveRules) {
|
|
395
|
+
rules = resolveRules(fileName, rules);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
fileRules.set(fileName, rules);
|
|
400
|
+
}
|
|
401
|
+
return rules;
|
|
402
|
+
}
|
|
403
|
+
function collectRules(record, rules, paths) {
|
|
404
|
+
for (const [path, rule] of Object.entries(rules)) {
|
|
405
|
+
if (typeof rule === 'object') {
|
|
406
|
+
collectRules(record, rule, [...paths, path]);
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
record[[...paths, path].join('/')] = rule;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
function getFileConfigs(fileName, minimatchCache) {
|
|
413
|
+
let result = fileConfigs.get(fileName);
|
|
414
|
+
if (!result) {
|
|
415
|
+
result = configs.filter(({ include, exclude }) => {
|
|
416
|
+
if (exclude?.some(_minimatch)) {
|
|
417
|
+
return false;
|
|
418
|
+
}
|
|
419
|
+
if (include && !include.some(_minimatch)) {
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
return true;
|
|
423
|
+
});
|
|
424
|
+
fileConfigs.set(fileName, result);
|
|
425
|
+
function _minimatch(pattern) {
|
|
426
|
+
if (minimatchCache) {
|
|
427
|
+
if (pattern in minimatchCache) {
|
|
428
|
+
return minimatchCache[pattern];
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
let normalized = normalizedPath.get(pattern);
|
|
432
|
+
if (!normalized) {
|
|
433
|
+
normalized = ts.server.toNormalizedPath(path.resolve(rootDir, pattern));
|
|
434
|
+
normalizedPath.set(pattern, normalized);
|
|
435
|
+
}
|
|
436
|
+
const res = minimatch.minimatch(fileName, normalized);
|
|
437
|
+
if (minimatchCache) {
|
|
438
|
+
minimatchCache[pattern] = res;
|
|
439
|
+
}
|
|
440
|
+
return res;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
return result;
|
|
444
|
+
}
|
|
432
445
|
}
|
|
433
446
|
const fsFiles = new Map();
|
|
434
447
|
function createRelatedInformation(ts, err, stackOffset) {
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
448
|
+
const stacks = ErrorStackParser.parse(err);
|
|
449
|
+
if (stacks.length <= stackOffset) {
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
const stack = stacks[stackOffset];
|
|
453
|
+
if (stack.fileName && stack.lineNumber !== undefined && stack.columnNumber !== undefined) {
|
|
454
|
+
let fileName = stack.fileName.replace(/\\/g, '/');
|
|
455
|
+
if (fileName.startsWith('file://')) {
|
|
456
|
+
fileName = fileName.substring('file://'.length);
|
|
457
|
+
}
|
|
458
|
+
if (fileName.includes('http-url:')) {
|
|
459
|
+
fileName = fileName.split('http-url:')[1];
|
|
460
|
+
}
|
|
461
|
+
const mtime = ts.sys.getModifiedTime?.(fileName)?.getTime() ?? 0;
|
|
462
|
+
const lastMtime = fsFiles.get(fileName)?.[1];
|
|
463
|
+
if (mtime !== lastMtime) {
|
|
464
|
+
const text = ts.sys.readFile(fileName);
|
|
465
|
+
fsFiles.set(fileName, [
|
|
466
|
+
text !== undefined,
|
|
467
|
+
mtime,
|
|
468
|
+
ts.createSourceFile(fileName, text ?? '', ts.ScriptTarget.Latest, true)
|
|
469
|
+
]);
|
|
470
|
+
}
|
|
471
|
+
const [exist, _mtime, relatedFile] = fsFiles.get(fileName);
|
|
472
|
+
let pos = 0;
|
|
473
|
+
if (exist) {
|
|
474
|
+
try {
|
|
475
|
+
pos = relatedFile.getPositionOfLineAndCharacter(stack.lineNumber - 1, stack.columnNumber - 1) ?? 0;
|
|
476
|
+
}
|
|
477
|
+
catch { }
|
|
478
|
+
}
|
|
479
|
+
return {
|
|
480
|
+
category: ts.DiagnosticCategory.Message,
|
|
481
|
+
code: 0,
|
|
482
|
+
file: relatedFile,
|
|
483
|
+
start: pos,
|
|
484
|
+
length: 0,
|
|
485
|
+
messageText: 'at ' + (stack.functionName ?? '<anonymous>'),
|
|
486
|
+
};
|
|
487
|
+
}
|
|
475
488
|
}
|
|
476
489
|
function combineCodeFixes(fileName, fixes) {
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
490
|
+
const changes = fixes
|
|
491
|
+
.map(fix => fix.changes)
|
|
492
|
+
.flat()
|
|
493
|
+
.filter(change => change.fileName === fileName && change.textChanges.length)
|
|
494
|
+
.sort((a, b) => b.textChanges[0].span.start - a.textChanges[0].span.start);
|
|
495
|
+
let lastChangeAt = Number.MAX_VALUE;
|
|
496
|
+
let finalTextChanges = [];
|
|
497
|
+
for (const change of changes) {
|
|
498
|
+
const textChanges = [...change.textChanges].sort((a, b) => a.span.start - b.span.start);
|
|
499
|
+
const firstChange = textChanges[0];
|
|
500
|
+
const lastChange = textChanges[textChanges.length - 1];
|
|
501
|
+
if (lastChangeAt >= lastChange.span.start + lastChange.span.length) {
|
|
502
|
+
lastChangeAt = firstChange.span.start;
|
|
503
|
+
finalTextChanges = finalTextChanges.concat(textChanges);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
return finalTextChanges;
|
|
494
507
|
}
|
|
495
508
|
function applyTextChanges(baseSnapshot, textChanges) {
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
509
|
+
textChanges = [...textChanges].sort((a, b) => b.span.start - a.span.start);
|
|
510
|
+
let text = baseSnapshot.getText(0, baseSnapshot.getLength());
|
|
511
|
+
for (const change of textChanges) {
|
|
512
|
+
text = text.slice(0, change.span.start) + change.newText + text.slice(change.span.start + change.span.length);
|
|
513
|
+
}
|
|
514
|
+
return {
|
|
515
|
+
getText(start, end) {
|
|
516
|
+
return text.substring(start, end);
|
|
517
|
+
},
|
|
518
|
+
getLength() {
|
|
519
|
+
return text.length;
|
|
520
|
+
},
|
|
521
|
+
getChangeRange(oldSnapshot) {
|
|
522
|
+
if (oldSnapshot === baseSnapshot) {
|
|
523
|
+
// TODO
|
|
524
|
+
}
|
|
525
|
+
return undefined;
|
|
526
|
+
},
|
|
527
|
+
};
|
|
515
528
|
}
|
|
516
529
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tsslint/core",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"files": [
|
|
6
6
|
"**/*.js",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"directory": "packages/core"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@tsslint/types": "1.5.
|
|
15
|
+
"@tsslint/types": "1.5.4",
|
|
16
16
|
"error-stack-parser": "^2.1.4",
|
|
17
17
|
"esbuild": ">=0.17.0",
|
|
18
18
|
"minimatch": "^10.0.1"
|
|
@@ -23,5 +23,5 @@
|
|
|
23
23
|
"scripts": {
|
|
24
24
|
"postinstall": "node scripts/cleanCache.js"
|
|
25
25
|
},
|
|
26
|
-
"gitHead": "
|
|
26
|
+
"gitHead": "02cbc403c85b4224b5ccd732dc96f7a0991a6ae2"
|
|
27
27
|
}
|