tinylint 0.1.0
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 +123 -0
- package/chunks/index-CanivEwi.js +1211 -0
- package/chunks/index-CanivEwi.js.map +1 -0
- package/engine.d.ts +6 -0
- package/engine.d.ts.map +1 -0
- package/index.d.ts +4 -0
- package/index.d.ts.map +1 -0
- package/index.js +2 -0
- package/index.js.map +1 -0
- package/monaco.d.ts +68 -0
- package/monaco.d.ts.map +1 -0
- package/monaco.js +343 -0
- package/monaco.js.map +1 -0
- package/package.json +29 -0
- package/types.d.ts +147 -0
- package/types.d.ts.map +1 -0
- package/utils.d.ts +10 -0
- package/utils.d.ts.map +1 -0
|
@@ -0,0 +1,1211 @@
|
|
|
1
|
+
var RuleScope;
|
|
2
|
+
(function (RuleScope) {
|
|
3
|
+
RuleScope[RuleScope["File"] = 1] = "File";
|
|
4
|
+
RuleScope[RuleScope["Project"] = 2] = "Project";
|
|
5
|
+
})(RuleScope || (RuleScope = {}));
|
|
6
|
+
var RuleTrigger;
|
|
7
|
+
(function (RuleTrigger) {
|
|
8
|
+
RuleTrigger[RuleTrigger["Immediate"] = 1] = "Immediate";
|
|
9
|
+
RuleTrigger[RuleTrigger["Debounced"] = 2] = "Debounced";
|
|
10
|
+
RuleTrigger[RuleTrigger["Idle"] = 3] = "Idle";
|
|
11
|
+
})(RuleTrigger || (RuleTrigger = {}));
|
|
12
|
+
var LintPhase;
|
|
13
|
+
(function (LintPhase) {
|
|
14
|
+
LintPhase[LintPhase["Immediate"] = 1] = "Immediate";
|
|
15
|
+
LintPhase[LintPhase["Debounced"] = 2] = "Debounced";
|
|
16
|
+
LintPhase[LintPhase["Idle"] = 3] = "Idle";
|
|
17
|
+
LintPhase[LintPhase["All"] = 4] = "All";
|
|
18
|
+
})(LintPhase || (LintPhase = {}));
|
|
19
|
+
var DiagnosticSeverity;
|
|
20
|
+
(function (DiagnosticSeverity) {
|
|
21
|
+
DiagnosticSeverity[DiagnosticSeverity["Suggestion"] = 1] = "Suggestion";
|
|
22
|
+
DiagnosticSeverity[DiagnosticSeverity["Warning"] = 2] = "Warning";
|
|
23
|
+
DiagnosticSeverity[DiagnosticSeverity["Error"] = 3] = "Error";
|
|
24
|
+
})(DiagnosticSeverity || (DiagnosticSeverity = {}));
|
|
25
|
+
class RuleMeta {
|
|
26
|
+
constructor(ruleName, options) {
|
|
27
|
+
this.ruleName = ruleName;
|
|
28
|
+
this.defaultSeverity = options?.defaultSeverity ?? DiagnosticSeverity.Warning;
|
|
29
|
+
this.requiresTypeInfo = options?.requiresTypeInfo ?? true;
|
|
30
|
+
this.scope = options?.scope ?? RuleScope.File;
|
|
31
|
+
this.trigger = options?.trigger ?? RuleTrigger.Debounced;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function normalizePath(fileName, useCaseSensitive) {
|
|
36
|
+
let normalized = fileName;
|
|
37
|
+
const count = normalized.length;
|
|
38
|
+
for (let index = 0; index < count; index++) {
|
|
39
|
+
if (normalized.charCodeAt(index) === 92) {
|
|
40
|
+
normalized = replaceBackslashes(normalized);
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const prefixLength = getPrefixLength(normalized);
|
|
45
|
+
const prefix = prefixLength === 0 ? "" : normalized.slice(0, prefixLength);
|
|
46
|
+
const parts = [];
|
|
47
|
+
let segmentStart = prefixLength;
|
|
48
|
+
const segmentCount = normalized.length;
|
|
49
|
+
for (let index = prefixLength; index <= segmentCount; index++) {
|
|
50
|
+
if (index === segmentCount || normalized.charCodeAt(index) === 47) {
|
|
51
|
+
if (index > segmentStart) {
|
|
52
|
+
const segment = normalized.slice(segmentStart, index);
|
|
53
|
+
if (segment === ".") {
|
|
54
|
+
segmentStart = index + 1;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (segment === "..") {
|
|
58
|
+
if (parts.length > 0 && parts[parts.length - 1] !== "..") {
|
|
59
|
+
parts.length -= 1;
|
|
60
|
+
}
|
|
61
|
+
else if (prefixLength === 0) {
|
|
62
|
+
parts.push(segment);
|
|
63
|
+
}
|
|
64
|
+
segmentStart = index + 1;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
parts.push(segment);
|
|
68
|
+
}
|
|
69
|
+
segmentStart = index + 1;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
let result = prefix;
|
|
73
|
+
const partCount = parts.length;
|
|
74
|
+
for (let index = 0; index < partCount; index++) {
|
|
75
|
+
if (result.length > 0 && result.charCodeAt(result.length - 1) !== 47) {
|
|
76
|
+
result += "/";
|
|
77
|
+
}
|
|
78
|
+
result += parts[index];
|
|
79
|
+
}
|
|
80
|
+
if (result.length === 0) {
|
|
81
|
+
result = ".";
|
|
82
|
+
}
|
|
83
|
+
return useCaseSensitive ? result : result.toLowerCase();
|
|
84
|
+
}
|
|
85
|
+
function joinPath(basePath, relativePath, useCaseSensitive) {
|
|
86
|
+
if (relativePath.length === 0) {
|
|
87
|
+
return normalizePath(basePath, useCaseSensitive);
|
|
88
|
+
}
|
|
89
|
+
if (isAbsolutePath(relativePath)) {
|
|
90
|
+
return normalizePath(relativePath, useCaseSensitive);
|
|
91
|
+
}
|
|
92
|
+
if (basePath.length === 0 || basePath === ".") {
|
|
93
|
+
return normalizePath(relativePath, useCaseSensitive);
|
|
94
|
+
}
|
|
95
|
+
return normalizePath(basePath + "/" + relativePath, useCaseSensitive);
|
|
96
|
+
}
|
|
97
|
+
function getDirectoryPath(fileName, useCaseSensitive) {
|
|
98
|
+
const normalized = normalizePath(fileName, useCaseSensitive);
|
|
99
|
+
for (let index = normalized.length - 1; index >= 0; index--) {
|
|
100
|
+
if (normalized.charCodeAt(index) === 47) {
|
|
101
|
+
if (index === 0) {
|
|
102
|
+
return "/";
|
|
103
|
+
}
|
|
104
|
+
return normalized.slice(0, index);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return ".";
|
|
108
|
+
}
|
|
109
|
+
function isRelativePath(value) {
|
|
110
|
+
if (value.length === 0) {
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
const code = value.charCodeAt(0);
|
|
114
|
+
return code === 46 || code === 47;
|
|
115
|
+
}
|
|
116
|
+
function getScriptKindFromFileName(tsApi, fileName) {
|
|
117
|
+
const length = fileName.length;
|
|
118
|
+
if (length >= 4) {
|
|
119
|
+
const tail4 = fileName.slice(length - 4).toLowerCase();
|
|
120
|
+
if (tail4 === ".tsx") {
|
|
121
|
+
return tsApi.ScriptKind.TSX;
|
|
122
|
+
}
|
|
123
|
+
if (tail4 === ".jsx") {
|
|
124
|
+
return tsApi.ScriptKind.JSX;
|
|
125
|
+
}
|
|
126
|
+
if (tail4 === ".mts") {
|
|
127
|
+
return tsApi.ScriptKind.TS;
|
|
128
|
+
}
|
|
129
|
+
if (tail4 === ".cts") {
|
|
130
|
+
return tsApi.ScriptKind.TS;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (length >= 3) {
|
|
134
|
+
const tail3 = fileName.slice(length - 3).toLowerCase();
|
|
135
|
+
if (tail3 === ".ts") {
|
|
136
|
+
return tsApi.ScriptKind.TS;
|
|
137
|
+
}
|
|
138
|
+
if (tail3 === ".js") {
|
|
139
|
+
return tsApi.ScriptKind.JS;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (length >= 5 && fileName.slice(length - 5).toLowerCase() === ".json") {
|
|
143
|
+
return tsApi.ScriptKind.JSON;
|
|
144
|
+
}
|
|
145
|
+
return tsApi.ScriptKind.Unknown;
|
|
146
|
+
}
|
|
147
|
+
function getExtensionForFileName(tsApi, fileName) {
|
|
148
|
+
const lower = fileName.toLowerCase();
|
|
149
|
+
if (lower.endsWith(".tsx")) {
|
|
150
|
+
return tsApi.Extension.Tsx;
|
|
151
|
+
}
|
|
152
|
+
if (lower.endsWith(".jsx")) {
|
|
153
|
+
return tsApi.Extension.Jsx;
|
|
154
|
+
}
|
|
155
|
+
if (lower.endsWith(".d.ts")) {
|
|
156
|
+
return tsApi.Extension.Dts;
|
|
157
|
+
}
|
|
158
|
+
if (lower.endsWith(".cts")) {
|
|
159
|
+
return tsApi.Extension.Cts;
|
|
160
|
+
}
|
|
161
|
+
if (lower.endsWith(".mts")) {
|
|
162
|
+
return tsApi.Extension.Mts;
|
|
163
|
+
}
|
|
164
|
+
return tsApi.Extension.Ts;
|
|
165
|
+
}
|
|
166
|
+
function useCaseSensitiveFileNames(tsApi, override) {
|
|
167
|
+
if (typeof override === "boolean") {
|
|
168
|
+
return override;
|
|
169
|
+
}
|
|
170
|
+
const sys = tsApi.sys;
|
|
171
|
+
if (sys !== undefined && typeof sys.useCaseSensitiveFileNames === "boolean") {
|
|
172
|
+
return sys.useCaseSensitiveFileNames;
|
|
173
|
+
}
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
function replaceBackslashes(value) {
|
|
177
|
+
let result = "";
|
|
178
|
+
const count = value.length;
|
|
179
|
+
for (let index = 0; index < count; index++) {
|
|
180
|
+
const code = value.charCodeAt(index);
|
|
181
|
+
result += code === 92 ? "/" : value.charAt(index);
|
|
182
|
+
}
|
|
183
|
+
return result;
|
|
184
|
+
}
|
|
185
|
+
function getPrefixLength(value) {
|
|
186
|
+
if (value.length === 0) {
|
|
187
|
+
return 0;
|
|
188
|
+
}
|
|
189
|
+
if (value.charCodeAt(0) === 47) {
|
|
190
|
+
return 1;
|
|
191
|
+
}
|
|
192
|
+
if (value.length > 1 && value.charCodeAt(1) === 58) {
|
|
193
|
+
if (value.length > 2 && value.charCodeAt(2) === 47) {
|
|
194
|
+
return 3;
|
|
195
|
+
}
|
|
196
|
+
return 2;
|
|
197
|
+
}
|
|
198
|
+
return 0;
|
|
199
|
+
}
|
|
200
|
+
function isAbsolutePath(value) {
|
|
201
|
+
if (value.length === 0) {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
if (value.charCodeAt(0) === 47) {
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
return value.length > 1 && value.charCodeAt(1) === 58;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const EMPTY_DIAGNOSTICS = [];
|
|
211
|
+
const EMPTY_SOURCE_FILES = [];
|
|
212
|
+
function defineRule(rule) {
|
|
213
|
+
return rule;
|
|
214
|
+
}
|
|
215
|
+
function defineConfig(config) {
|
|
216
|
+
return config;
|
|
217
|
+
}
|
|
218
|
+
function lintWithProgram(options) {
|
|
219
|
+
const phase = normalizePhase(options.phase);
|
|
220
|
+
const compiledRules = compileRules(options.config);
|
|
221
|
+
const diagnostics = runProgramLint(options.typescript, options.program, compiledRules, phase, options.fileNames, options.changedFiles, options.currentFile, useCaseSensitiveFileNames(options.typescript, undefined));
|
|
222
|
+
return buildLintResult(diagnostics, phase, options.projectVersion);
|
|
223
|
+
}
|
|
224
|
+
function createLinter(options) {
|
|
225
|
+
if ("programProvider" in options) {
|
|
226
|
+
return new ProviderProgramLinter(options);
|
|
227
|
+
}
|
|
228
|
+
return new ManagedProgramLinter(options);
|
|
229
|
+
}
|
|
230
|
+
class ProviderProgramLinter {
|
|
231
|
+
constructor(options) {
|
|
232
|
+
this.aggregateCache = Object.create(null);
|
|
233
|
+
this.fileCache = Object.create(null);
|
|
234
|
+
this.projectCache = Object.create(null);
|
|
235
|
+
this.disposed = false;
|
|
236
|
+
this.compiledRules = compileRules(options.config);
|
|
237
|
+
this.getChangedFiles = options.getChangedFiles;
|
|
238
|
+
this.getCurrentFile = options.getCurrentFile;
|
|
239
|
+
this.getPhase = options.getPhase;
|
|
240
|
+
this.getProjectVersion = options.getProjectVersion;
|
|
241
|
+
this.programProvider = options.programProvider;
|
|
242
|
+
this.typescript = options.typescript;
|
|
243
|
+
this.useCaseSensitive = useCaseSensitiveFileNames(options.typescript, undefined);
|
|
244
|
+
}
|
|
245
|
+
dispose() {
|
|
246
|
+
this.disposed = true;
|
|
247
|
+
this.lastProgramSignature = undefined;
|
|
248
|
+
clearRecord(this.aggregateCache);
|
|
249
|
+
clearRecord(this.fileCache);
|
|
250
|
+
clearRecord(this.projectCache);
|
|
251
|
+
}
|
|
252
|
+
getProgram() {
|
|
253
|
+
if (this.disposed) {
|
|
254
|
+
return undefined;
|
|
255
|
+
}
|
|
256
|
+
return this.programProvider();
|
|
257
|
+
}
|
|
258
|
+
lint(request) {
|
|
259
|
+
const phase = normalizePhase(request?.phase ?? this.getPhase?.());
|
|
260
|
+
const projectVersion = this.getProjectVersion?.();
|
|
261
|
+
if (this.disposed) {
|
|
262
|
+
return buildLintResult(EMPTY_DIAGNOSTICS, phase, projectVersion);
|
|
263
|
+
}
|
|
264
|
+
const program = this.programProvider();
|
|
265
|
+
if (program === undefined) {
|
|
266
|
+
return buildLintResult(EMPTY_DIAGNOSTICS, phase, projectVersion);
|
|
267
|
+
}
|
|
268
|
+
const currentFile = request?.currentFile ?? this.getCurrentFile?.();
|
|
269
|
+
const changedFiles = request?.changedFiles ?? this.getChangedFiles?.();
|
|
270
|
+
const hasExplicitTargets = hasTargetRequest(request?.fileNames, currentFile, changedFiles, phase);
|
|
271
|
+
const aggregateKey = phase;
|
|
272
|
+
if (hasExplicitTargets) {
|
|
273
|
+
const targetFiles = resolveExplicitTargetFiles(program, request?.fileNames, currentFile, changedFiles, phase, this.useCaseSensitive);
|
|
274
|
+
const diagnostics = runFileSet(this.typescript, program, this.compiledRules, phase, targetFiles, false, this.fileCache);
|
|
275
|
+
return buildLintResult(diagnostics, phase, projectVersion);
|
|
276
|
+
}
|
|
277
|
+
if (hasExplicitTargets === false && projectVersion !== undefined) {
|
|
278
|
+
const aggregate = this.aggregateCache[aggregateKey];
|
|
279
|
+
if (aggregate !== undefined && aggregate.signature === projectVersion) {
|
|
280
|
+
return {
|
|
281
|
+
diagnostics: aggregate.diagnostics,
|
|
282
|
+
phase,
|
|
283
|
+
projectVersion,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
const sourceFiles = collectSourceFiles(program, this.useCaseSensitive);
|
|
288
|
+
const programSignature = createSourceFileSetSignature(sourceFiles, this.useCaseSensitive);
|
|
289
|
+
if (this.lastProgramSignature !== undefined && this.lastProgramSignature !== programSignature) {
|
|
290
|
+
this.clearCaches();
|
|
291
|
+
}
|
|
292
|
+
this.lastProgramSignature = programSignature;
|
|
293
|
+
const changedSet = createFileSet(changedFiles, this.useCaseSensitive);
|
|
294
|
+
const fileRulePlan = createFileRulePlan(this.compiledRules, phase);
|
|
295
|
+
const diagnostics = [];
|
|
296
|
+
const fileCount = sourceFiles.length;
|
|
297
|
+
for (let index = 0; index < fileCount; index++) {
|
|
298
|
+
const file = sourceFiles[index];
|
|
299
|
+
const cacheKey = createFileCacheKey(phase, file.fileName);
|
|
300
|
+
let fileDiagnostics = this.fileCache[cacheKey];
|
|
301
|
+
if (fileDiagnostics === undefined || changedSet === undefined || changedSet[normalizePath(file.fileName, this.useCaseSensitive)] === 1) {
|
|
302
|
+
const nextDiagnostics = [];
|
|
303
|
+
runFileRules(this.typescript, program, fileRulePlan, file, nextDiagnostics);
|
|
304
|
+
fileDiagnostics = nextDiagnostics;
|
|
305
|
+
this.fileCache[cacheKey] = fileDiagnostics;
|
|
306
|
+
}
|
|
307
|
+
pushDiagnostics(diagnostics, fileDiagnostics);
|
|
308
|
+
}
|
|
309
|
+
if (phase === LintPhase.All || phase === LintPhase.Idle) {
|
|
310
|
+
const projectKey = createProjectCacheKey(phase);
|
|
311
|
+
let projectDiagnostics = this.projectCache[projectKey];
|
|
312
|
+
if (projectDiagnostics === undefined || changedSet !== undefined) {
|
|
313
|
+
projectDiagnostics = runProjectRules(this.typescript, program, this.compiledRules, phase);
|
|
314
|
+
this.projectCache[projectKey] = projectDiagnostics;
|
|
315
|
+
}
|
|
316
|
+
pushDiagnostics(diagnostics, projectDiagnostics);
|
|
317
|
+
}
|
|
318
|
+
const readonlyDiagnostics = diagnostics;
|
|
319
|
+
if (projectVersion !== undefined) {
|
|
320
|
+
this.aggregateCache[aggregateKey] = {
|
|
321
|
+
diagnostics: readonlyDiagnostics,
|
|
322
|
+
signature: projectVersion,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
return buildLintResult(readonlyDiagnostics, phase, projectVersion);
|
|
326
|
+
}
|
|
327
|
+
clearCaches() {
|
|
328
|
+
clearRecord(this.aggregateCache);
|
|
329
|
+
clearRecord(this.fileCache);
|
|
330
|
+
clearRecord(this.projectCache);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
class ManagedProgramLinter {
|
|
334
|
+
constructor(options) {
|
|
335
|
+
this.aggregateCache = Object.create(null);
|
|
336
|
+
this.disposed = false;
|
|
337
|
+
this.fileCache = Object.create(null);
|
|
338
|
+
this.files = Object.create(null);
|
|
339
|
+
this.libContents = Object.create(null);
|
|
340
|
+
this.libSnapshots = Object.create(null);
|
|
341
|
+
this.projectVersion = 1;
|
|
342
|
+
this.projectRuleCache = Object.create(null);
|
|
343
|
+
this.compilerOptions = options.compilerOptions ?? {};
|
|
344
|
+
this.compiledRules = compileRules(options.config);
|
|
345
|
+
this.typescript = options.typescript;
|
|
346
|
+
this.useCaseSensitive = true;
|
|
347
|
+
this.currentDirectory = "/";
|
|
348
|
+
this.defaultLibFileName = "lib.d.ts";
|
|
349
|
+
this.languageService = this.createLanguageService();
|
|
350
|
+
this.resetProject(options);
|
|
351
|
+
}
|
|
352
|
+
dispose() {
|
|
353
|
+
if (this.disposed === false) {
|
|
354
|
+
this.disposed = true;
|
|
355
|
+
this.languageService.dispose();
|
|
356
|
+
this.clearState();
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
getProgram() {
|
|
360
|
+
if (this.disposed) {
|
|
361
|
+
return undefined;
|
|
362
|
+
}
|
|
363
|
+
return this.languageService.getProgram();
|
|
364
|
+
}
|
|
365
|
+
lint(request) {
|
|
366
|
+
const phase = normalizePhase(request?.phase);
|
|
367
|
+
const projectVersion = this.projectVersion;
|
|
368
|
+
if (this.disposed) {
|
|
369
|
+
return buildLintResult(EMPTY_DIAGNOSTICS, phase, projectVersion);
|
|
370
|
+
}
|
|
371
|
+
const program = this.languageService.getProgram();
|
|
372
|
+
if (program === undefined) {
|
|
373
|
+
return buildLintResult(EMPTY_DIAGNOSTICS, phase, projectVersion);
|
|
374
|
+
}
|
|
375
|
+
const aggregateKey = phase;
|
|
376
|
+
const hasExplicitTargets = hasTargetRequest(request?.fileNames, request?.currentFile, request?.changedFiles, phase);
|
|
377
|
+
if (hasExplicitTargets === false) {
|
|
378
|
+
const aggregate = this.aggregateCache[aggregateKey];
|
|
379
|
+
if (aggregate !== undefined && aggregate.signature === projectVersion) {
|
|
380
|
+
return {
|
|
381
|
+
diagnostics: aggregate.diagnostics,
|
|
382
|
+
phase,
|
|
383
|
+
projectVersion,
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
const fileRulePlan = createFileRulePlan(this.compiledRules, phase);
|
|
388
|
+
if (hasExplicitTargets) {
|
|
389
|
+
const targetFiles = resolveExplicitTargetFiles(program, request?.fileNames, request?.currentFile, request?.changedFiles, phase, this.useCaseSensitive);
|
|
390
|
+
const diagnostics = this.runManagedFileSet(program, phase, targetFiles, fileRulePlan);
|
|
391
|
+
return buildLintResult(diagnostics, phase, projectVersion);
|
|
392
|
+
}
|
|
393
|
+
const sourceFiles = collectSourceFiles(program, this.useCaseSensitive);
|
|
394
|
+
const diagnostics = [];
|
|
395
|
+
const fileCount = sourceFiles.length;
|
|
396
|
+
for (let index = 0; index < fileCount; index++) {
|
|
397
|
+
const file = sourceFiles[index];
|
|
398
|
+
const fileVersion = this.getManagedFileVersion(file.fileName);
|
|
399
|
+
const cacheKey = createFileCacheKey(phase, file.fileName);
|
|
400
|
+
let cached = this.fileCache[cacheKey];
|
|
401
|
+
if (cached === undefined || cached.version !== fileVersion) {
|
|
402
|
+
const fileDiagnostics = this.runManagedFile(program, phase, file, fileRulePlan);
|
|
403
|
+
cached = {
|
|
404
|
+
diagnostics: fileDiagnostics,
|
|
405
|
+
version: fileVersion,
|
|
406
|
+
};
|
|
407
|
+
this.fileCache[cacheKey] = cached;
|
|
408
|
+
}
|
|
409
|
+
pushDiagnostics(diagnostics, cached.diagnostics);
|
|
410
|
+
}
|
|
411
|
+
if (phase === LintPhase.All || phase === LintPhase.Idle) {
|
|
412
|
+
const projectKey = createProjectCacheKey(phase);
|
|
413
|
+
let projectCache = this.projectRuleCache[projectKey];
|
|
414
|
+
if (projectCache === undefined || projectCache.signature !== projectVersion) {
|
|
415
|
+
projectCache = {
|
|
416
|
+
diagnostics: runProjectRules(this.typescript, program, this.compiledRules, phase),
|
|
417
|
+
signature: projectVersion,
|
|
418
|
+
};
|
|
419
|
+
this.projectRuleCache[projectKey] = projectCache;
|
|
420
|
+
}
|
|
421
|
+
pushDiagnostics(diagnostics, projectCache.diagnostics);
|
|
422
|
+
}
|
|
423
|
+
const readonlyDiagnostics = diagnostics;
|
|
424
|
+
this.aggregateCache[aggregateKey] = {
|
|
425
|
+
diagnostics: readonlyDiagnostics,
|
|
426
|
+
signature: projectVersion,
|
|
427
|
+
};
|
|
428
|
+
return buildLintResult(readonlyDiagnostics, phase, projectVersion);
|
|
429
|
+
}
|
|
430
|
+
resetProject(options) {
|
|
431
|
+
this.clearState();
|
|
432
|
+
this.useCaseSensitive = useCaseSensitiveFileNames(this.typescript, options.useCaseSensitiveFileNames);
|
|
433
|
+
this.compilerOptions = options.compilerOptions ?? {};
|
|
434
|
+
this.currentDirectory = normalizePath(options.currentDirectory ?? "/", this.useCaseSensitive);
|
|
435
|
+
this.defaultLibFileName = normalizePath(options.defaultLibFileName ?? getDefaultLibFileName(this.typescript, this.compilerOptions), this.useCaseSensitive);
|
|
436
|
+
if (options.libFiles !== undefined) {
|
|
437
|
+
for (const fileName in options.libFiles) {
|
|
438
|
+
if (Object.prototype.hasOwnProperty.call(options.libFiles, fileName)) {
|
|
439
|
+
const normalized = normalizePath(fileName, this.useCaseSensitive);
|
|
440
|
+
this.libContents[normalized] = options.libFiles[fileName];
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
for (const fileName in options.files) {
|
|
445
|
+
if (Object.prototype.hasOwnProperty.call(options.files, fileName)) {
|
|
446
|
+
this.setManagedFile(fileName, options.files[fileName], false);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
this.projectVersion += 1;
|
|
450
|
+
this.languageService.dispose();
|
|
451
|
+
this.languageService = this.createLanguageService();
|
|
452
|
+
}
|
|
453
|
+
removeFile(fileName) {
|
|
454
|
+
const normalized = normalizePath(fileName, this.useCaseSensitive);
|
|
455
|
+
if (this.files[normalized] === undefined) {
|
|
456
|
+
return false;
|
|
457
|
+
}
|
|
458
|
+
delete this.files[normalized];
|
|
459
|
+
delete this.libContents[normalized];
|
|
460
|
+
delete this.libSnapshots[normalized];
|
|
461
|
+
deleteFileCacheEntries(this.fileCache, normalized);
|
|
462
|
+
this.fileNameList = undefined;
|
|
463
|
+
this.projectVersion += 1;
|
|
464
|
+
this.invalidateProjectCaches();
|
|
465
|
+
return true;
|
|
466
|
+
}
|
|
467
|
+
updateFile(fileName, content, kind) {
|
|
468
|
+
return this.setManagedFile(fileName, kind === undefined ? content : { content, kind }, true);
|
|
469
|
+
}
|
|
470
|
+
directoryExists(directoryName) {
|
|
471
|
+
const normalized = normalizePath(directoryName, this.useCaseSensitive);
|
|
472
|
+
const names = this.getScriptFileNames();
|
|
473
|
+
const count = names.length;
|
|
474
|
+
for (let index = 0; index < count; index++) {
|
|
475
|
+
if (isInDirectory(names[index], normalized)) {
|
|
476
|
+
return true;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
for (const fileName in this.libContents) {
|
|
480
|
+
if (this.libContents[fileName] !== undefined && isInDirectory(fileName, normalized)) {
|
|
481
|
+
return true;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
fileExists(fileName) {
|
|
487
|
+
const normalized = normalizePath(fileName, this.useCaseSensitive);
|
|
488
|
+
if (this.files[normalized] !== undefined) {
|
|
489
|
+
return true;
|
|
490
|
+
}
|
|
491
|
+
if (this.libContents[normalized] !== undefined) {
|
|
492
|
+
return true;
|
|
493
|
+
}
|
|
494
|
+
const sys = this.typescript.sys;
|
|
495
|
+
if (sys === undefined || sys.fileExists === undefined) {
|
|
496
|
+
return false;
|
|
497
|
+
}
|
|
498
|
+
return sys.fileExists(fileName);
|
|
499
|
+
}
|
|
500
|
+
getManagedFileVersion(fileName) {
|
|
501
|
+
const normalized = normalizePath(fileName, this.useCaseSensitive);
|
|
502
|
+
const file = this.files[normalized];
|
|
503
|
+
if (file === undefined) {
|
|
504
|
+
return 0;
|
|
505
|
+
}
|
|
506
|
+
return file.version;
|
|
507
|
+
}
|
|
508
|
+
getScriptFileNames() {
|
|
509
|
+
if (this.fileNameList !== undefined) {
|
|
510
|
+
return this.fileNameList;
|
|
511
|
+
}
|
|
512
|
+
const names = [];
|
|
513
|
+
for (const fileName in this.files) {
|
|
514
|
+
if (this.files[fileName] !== undefined) {
|
|
515
|
+
names.push(fileName);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
this.fileNameList = names;
|
|
519
|
+
return names;
|
|
520
|
+
}
|
|
521
|
+
getScriptKind(fileName) {
|
|
522
|
+
const normalized = normalizePath(fileName, this.useCaseSensitive);
|
|
523
|
+
const file = this.files[normalized];
|
|
524
|
+
if (file !== undefined) {
|
|
525
|
+
return file.kind;
|
|
526
|
+
}
|
|
527
|
+
return getScriptKindFromFileName(this.typescript, normalized);
|
|
528
|
+
}
|
|
529
|
+
getScriptSnapshot(fileName) {
|
|
530
|
+
const normalized = normalizePath(fileName, this.useCaseSensitive);
|
|
531
|
+
const file = this.files[normalized];
|
|
532
|
+
if (file !== undefined) {
|
|
533
|
+
if (file.snapshot === undefined) {
|
|
534
|
+
file.snapshot = this.typescript.ScriptSnapshot.fromString(file.content);
|
|
535
|
+
}
|
|
536
|
+
return file.snapshot;
|
|
537
|
+
}
|
|
538
|
+
const libText = this.readLibraryFile(normalized, fileName);
|
|
539
|
+
if (libText === undefined) {
|
|
540
|
+
return undefined;
|
|
541
|
+
}
|
|
542
|
+
let snapshot = this.libSnapshots[normalized];
|
|
543
|
+
if (snapshot === undefined) {
|
|
544
|
+
snapshot = this.typescript.ScriptSnapshot.fromString(libText);
|
|
545
|
+
this.libSnapshots[normalized] = snapshot;
|
|
546
|
+
}
|
|
547
|
+
return snapshot;
|
|
548
|
+
}
|
|
549
|
+
getScriptVersion(fileName) {
|
|
550
|
+
const normalized = normalizePath(fileName, this.useCaseSensitive);
|
|
551
|
+
const file = this.files[normalized];
|
|
552
|
+
if (file !== undefined) {
|
|
553
|
+
return String(file.version);
|
|
554
|
+
}
|
|
555
|
+
return "0";
|
|
556
|
+
}
|
|
557
|
+
readDirectory(rootDir, extensions) {
|
|
558
|
+
const normalizedRoot = normalizePath(rootDir, this.useCaseSensitive);
|
|
559
|
+
const result = [];
|
|
560
|
+
const files = this.getScriptFileNames();
|
|
561
|
+
const count = files.length;
|
|
562
|
+
for (let index = 0; index < count; index++) {
|
|
563
|
+
const fileName = files[index];
|
|
564
|
+
if (isInDirectory(fileName, normalizedRoot) && matchesExtension(fileName, extensions)) {
|
|
565
|
+
result.push(fileName);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
return result;
|
|
569
|
+
}
|
|
570
|
+
readFile(fileName) {
|
|
571
|
+
const normalized = normalizePath(fileName, this.useCaseSensitive);
|
|
572
|
+
const file = this.files[normalized];
|
|
573
|
+
if (file !== undefined) {
|
|
574
|
+
return file.content;
|
|
575
|
+
}
|
|
576
|
+
return this.readLibraryFile(normalized, fileName);
|
|
577
|
+
}
|
|
578
|
+
readLibraryFile(normalizedFileName, originalFileName) {
|
|
579
|
+
const fromMemory = this.libContents[normalizedFileName];
|
|
580
|
+
if (fromMemory !== undefined) {
|
|
581
|
+
return fromMemory;
|
|
582
|
+
}
|
|
583
|
+
const sys = this.typescript.sys;
|
|
584
|
+
if (sys !== undefined && sys.readFile !== undefined) {
|
|
585
|
+
const text = sys.readFile(originalFileName);
|
|
586
|
+
if (text !== undefined) {
|
|
587
|
+
this.libContents[normalizedFileName] = text;
|
|
588
|
+
return text;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
return undefined;
|
|
592
|
+
}
|
|
593
|
+
resolveModuleNames(moduleNames, containingFile) {
|
|
594
|
+
const resolved = [];
|
|
595
|
+
const count = moduleNames.length;
|
|
596
|
+
for (let index = 0; index < count; index++) {
|
|
597
|
+
const moduleName = moduleNames[index];
|
|
598
|
+
const local = this.resolveSingleModule(moduleName, containingFile);
|
|
599
|
+
if (local !== undefined) {
|
|
600
|
+
resolved.push(local);
|
|
601
|
+
}
|
|
602
|
+
else {
|
|
603
|
+
resolved.push(undefined);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
return resolved;
|
|
607
|
+
}
|
|
608
|
+
resolveSingleModule(moduleName, containingFile) {
|
|
609
|
+
if (isRelativePath(moduleName)) {
|
|
610
|
+
const basePath = getDirectoryPath(containingFile, this.useCaseSensitive);
|
|
611
|
+
const resolvedFileName = resolveKnownFile(this.typescript, this.files, this.libContents, joinPath(basePath, moduleName, this.useCaseSensitive), this.useCaseSensitive);
|
|
612
|
+
if (resolvedFileName !== undefined) {
|
|
613
|
+
return {
|
|
614
|
+
extension: getExtensionForFileName(this.typescript, resolvedFileName),
|
|
615
|
+
isExternalLibraryImport: this.files[resolvedFileName] === undefined,
|
|
616
|
+
resolvedFileName,
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
const sys = this.typescript.sys;
|
|
621
|
+
if (sys !== undefined && this.typescript.resolveModuleName !== undefined) {
|
|
622
|
+
const resolved = this.typescript.resolveModuleName(moduleName, containingFile, this.compilerOptions, sys);
|
|
623
|
+
if (resolved.resolvedModule !== undefined) {
|
|
624
|
+
return resolved.resolvedModule;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
return undefined;
|
|
628
|
+
}
|
|
629
|
+
runManagedFile(program, phase, file, fileRulePlan) {
|
|
630
|
+
const diagnostics = [];
|
|
631
|
+
runFileRules(this.typescript, program, fileRulePlan, file, diagnostics);
|
|
632
|
+
const readonlyDiagnostics = diagnostics;
|
|
633
|
+
this.fileCache[createFileCacheKey(phase, file.fileName)] = {
|
|
634
|
+
diagnostics: readonlyDiagnostics,
|
|
635
|
+
version: this.getManagedFileVersion(file.fileName),
|
|
636
|
+
};
|
|
637
|
+
return readonlyDiagnostics;
|
|
638
|
+
}
|
|
639
|
+
runManagedFileSet(program, phase, files, fileRulePlan) {
|
|
640
|
+
const diagnostics = [];
|
|
641
|
+
const count = files.length;
|
|
642
|
+
for (let index = 0; index < count; index++) {
|
|
643
|
+
const file = files[index];
|
|
644
|
+
const fileVersion = this.getManagedFileVersion(file.fileName);
|
|
645
|
+
const cacheKey = createFileCacheKey(phase, file.fileName);
|
|
646
|
+
let cached = this.fileCache[cacheKey];
|
|
647
|
+
if (cached === undefined || cached.version !== fileVersion) {
|
|
648
|
+
const fileDiagnostics = this.runManagedFile(program, phase, file, fileRulePlan);
|
|
649
|
+
cached = {
|
|
650
|
+
diagnostics: fileDiagnostics,
|
|
651
|
+
version: fileVersion,
|
|
652
|
+
};
|
|
653
|
+
this.fileCache[cacheKey] = cached;
|
|
654
|
+
}
|
|
655
|
+
pushDiagnostics(diagnostics, cached.diagnostics);
|
|
656
|
+
}
|
|
657
|
+
if (phase === LintPhase.All || phase === LintPhase.Idle) {
|
|
658
|
+
pushDiagnostics(diagnostics, runProjectRules(this.typescript, program, this.compiledRules, phase));
|
|
659
|
+
}
|
|
660
|
+
return diagnostics;
|
|
661
|
+
}
|
|
662
|
+
setManagedFile(fileName, input, bumpProjectVersion) {
|
|
663
|
+
const normalized = normalizePath(fileName, this.useCaseSensitive);
|
|
664
|
+
const nextContent = typeof input === "string" ? input : input.content;
|
|
665
|
+
const nextKind = typeof input === "string"
|
|
666
|
+
? getScriptKindFromFileName(this.typescript, normalized)
|
|
667
|
+
: (input.kind ?? getScriptKindFromFileName(this.typescript, normalized));
|
|
668
|
+
let file = this.files[normalized];
|
|
669
|
+
if (file === undefined) {
|
|
670
|
+
this.files[normalized] = {
|
|
671
|
+
content: nextContent,
|
|
672
|
+
fileName: normalized,
|
|
673
|
+
kind: nextKind,
|
|
674
|
+
snapshot: undefined,
|
|
675
|
+
version: 1,
|
|
676
|
+
};
|
|
677
|
+
this.fileNameList = undefined;
|
|
678
|
+
if (bumpProjectVersion) {
|
|
679
|
+
this.projectVersion += 1;
|
|
680
|
+
this.invalidateProjectCaches();
|
|
681
|
+
}
|
|
682
|
+
return true;
|
|
683
|
+
}
|
|
684
|
+
if (file.content === nextContent && file.kind === nextKind) {
|
|
685
|
+
return false;
|
|
686
|
+
}
|
|
687
|
+
file.content = nextContent;
|
|
688
|
+
file.kind = nextKind;
|
|
689
|
+
file.snapshot = undefined;
|
|
690
|
+
file.version += 1;
|
|
691
|
+
if (bumpProjectVersion) {
|
|
692
|
+
this.projectVersion += 1;
|
|
693
|
+
this.invalidateProjectCaches();
|
|
694
|
+
}
|
|
695
|
+
return true;
|
|
696
|
+
}
|
|
697
|
+
clearState() {
|
|
698
|
+
clearRecord(this.aggregateCache);
|
|
699
|
+
clearRecord(this.fileCache);
|
|
700
|
+
clearRecord(this.files);
|
|
701
|
+
clearRecord(this.libContents);
|
|
702
|
+
clearRecord(this.libSnapshots);
|
|
703
|
+
clearRecord(this.projectRuleCache);
|
|
704
|
+
this.fileNameList = undefined;
|
|
705
|
+
}
|
|
706
|
+
createLanguageService() {
|
|
707
|
+
const host = {
|
|
708
|
+
directoryExists: (directoryName) => this.directoryExists(directoryName),
|
|
709
|
+
fileExists: (fileName) => this.fileExists(fileName),
|
|
710
|
+
getCompilationSettings: () => this.compilerOptions,
|
|
711
|
+
getCurrentDirectory: () => this.currentDirectory,
|
|
712
|
+
getDefaultLibFileName: () => this.defaultLibFileName,
|
|
713
|
+
getProjectVersion: () => String(this.projectVersion),
|
|
714
|
+
getScriptFileNames: () => this.getScriptFileNames(),
|
|
715
|
+
getScriptKind: (fileName) => this.getScriptKind(fileName),
|
|
716
|
+
getScriptSnapshot: (fileName) => this.getScriptSnapshot(fileName),
|
|
717
|
+
getScriptVersion: (fileName) => this.getScriptVersion(fileName),
|
|
718
|
+
readDirectory: (rootDir, extensions) => this.readDirectory(rootDir, extensions),
|
|
719
|
+
readFile: (fileName) => this.readFile(fileName),
|
|
720
|
+
resolveModuleNames: (moduleNames, containingFile) => this.resolveModuleNames(moduleNames, containingFile),
|
|
721
|
+
useCaseSensitiveFileNames: () => this.useCaseSensitive,
|
|
722
|
+
};
|
|
723
|
+
return this.typescript.createLanguageService(host);
|
|
724
|
+
}
|
|
725
|
+
invalidateProjectCaches() {
|
|
726
|
+
clearRecord(this.aggregateCache);
|
|
727
|
+
clearRecord(this.projectRuleCache);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
function compileRules(config) {
|
|
731
|
+
const result = [];
|
|
732
|
+
const rules = config.rules;
|
|
733
|
+
for (const ruleName in rules) {
|
|
734
|
+
if (Object.prototype.hasOwnProperty.call(rules, ruleName) === false) {
|
|
735
|
+
continue;
|
|
736
|
+
}
|
|
737
|
+
const value = rules[ruleName];
|
|
738
|
+
if (value === undefined || value === false) {
|
|
739
|
+
continue;
|
|
740
|
+
}
|
|
741
|
+
let definition;
|
|
742
|
+
let options;
|
|
743
|
+
if (Array.isArray(value)) {
|
|
744
|
+
definition = value[0];
|
|
745
|
+
options = value[1];
|
|
746
|
+
}
|
|
747
|
+
else {
|
|
748
|
+
definition = value;
|
|
749
|
+
options = undefined;
|
|
750
|
+
}
|
|
751
|
+
const meta = definition.meta;
|
|
752
|
+
result.push({
|
|
753
|
+
defaultSeverity: meta.defaultSeverity,
|
|
754
|
+
definition,
|
|
755
|
+
name: meta.ruleName.length === 0 ? ruleName : meta.ruleName,
|
|
756
|
+
options,
|
|
757
|
+
requiresTypeInfo: meta.requiresTypeInfo,
|
|
758
|
+
scope: meta.scope,
|
|
759
|
+
trigger: meta.trigger,
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
return result;
|
|
763
|
+
}
|
|
764
|
+
function createDiagnosticBuilder(diagnostic) {
|
|
765
|
+
return {
|
|
766
|
+
asError() {
|
|
767
|
+
diagnostic.severity = DiagnosticSeverity.Error;
|
|
768
|
+
return this;
|
|
769
|
+
},
|
|
770
|
+
asSuggestion() {
|
|
771
|
+
diagnostic.severity = DiagnosticSeverity.Suggestion;
|
|
772
|
+
return this;
|
|
773
|
+
},
|
|
774
|
+
asWarning() {
|
|
775
|
+
diagnostic.severity = DiagnosticSeverity.Warning;
|
|
776
|
+
return this;
|
|
777
|
+
},
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
function buildLintResult(diagnostics, phase, projectVersion) {
|
|
781
|
+
if (projectVersion === undefined) {
|
|
782
|
+
return {
|
|
783
|
+
diagnostics,
|
|
784
|
+
phase,
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
return {
|
|
788
|
+
diagnostics,
|
|
789
|
+
phase,
|
|
790
|
+
projectVersion,
|
|
791
|
+
};
|
|
792
|
+
}
|
|
793
|
+
function createFileCacheKey(phase, fileName) {
|
|
794
|
+
return phase + "|" + fileName;
|
|
795
|
+
}
|
|
796
|
+
function createFileReporter(file, rule, diagnostics) {
|
|
797
|
+
function report(nodeOrStart, lengthOrMessage, messageText) {
|
|
798
|
+
let start = 0;
|
|
799
|
+
let length = 0;
|
|
800
|
+
let message = "";
|
|
801
|
+
if (typeof nodeOrStart === "number") {
|
|
802
|
+
start = nodeOrStart;
|
|
803
|
+
length = lengthOrMessage;
|
|
804
|
+
message = messageText ?? "";
|
|
805
|
+
}
|
|
806
|
+
else {
|
|
807
|
+
start = nodeOrStart.getStart(file, false);
|
|
808
|
+
length = nodeOrStart.getEnd() - start;
|
|
809
|
+
message = lengthOrMessage;
|
|
810
|
+
}
|
|
811
|
+
const diagnostic = {
|
|
812
|
+
fileName: file.fileName,
|
|
813
|
+
length,
|
|
814
|
+
message,
|
|
815
|
+
phase: rule.trigger,
|
|
816
|
+
ruleName: rule.name,
|
|
817
|
+
severity: rule.defaultSeverity,
|
|
818
|
+
start,
|
|
819
|
+
};
|
|
820
|
+
diagnostics.push(diagnostic);
|
|
821
|
+
return createDiagnosticBuilder(diagnostic);
|
|
822
|
+
}
|
|
823
|
+
return report;
|
|
824
|
+
}
|
|
825
|
+
function createProjectCacheKey(phase) {
|
|
826
|
+
return "project|" + phase;
|
|
827
|
+
}
|
|
828
|
+
function createFileRulePlan(rules, phase) {
|
|
829
|
+
const activeRules = [];
|
|
830
|
+
let requiresChecker = false;
|
|
831
|
+
const ruleCount = rules.length;
|
|
832
|
+
for (let index = 0; index < ruleCount; index++) {
|
|
833
|
+
const rule = rules[index];
|
|
834
|
+
if (rule.scope === RuleScope.File && matchesPhase(rule.trigger, phase) && rule.definition.create) {
|
|
835
|
+
activeRules.push(rule);
|
|
836
|
+
requiresChecker = requiresChecker || rule.requiresTypeInfo;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
if (activeRules.length === 0) {
|
|
840
|
+
return undefined;
|
|
841
|
+
}
|
|
842
|
+
return {
|
|
843
|
+
requiresChecker,
|
|
844
|
+
rules: activeRules,
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
function createSourceFileSetSignature(files, useCaseSensitive) {
|
|
848
|
+
const count = files.length;
|
|
849
|
+
if (count === 0) {
|
|
850
|
+
return "";
|
|
851
|
+
}
|
|
852
|
+
let result = normalizePath(files[0].fileName, useCaseSensitive);
|
|
853
|
+
if (count === 1) {
|
|
854
|
+
return result;
|
|
855
|
+
}
|
|
856
|
+
for (let index = 1; index < count; index++) {
|
|
857
|
+
result += "\n" + normalizePath(files[index].fileName, useCaseSensitive);
|
|
858
|
+
}
|
|
859
|
+
return result;
|
|
860
|
+
}
|
|
861
|
+
function createProjectReporter(rule, diagnostics) {
|
|
862
|
+
function report(file, start, length, message) {
|
|
863
|
+
const diagnostic = {
|
|
864
|
+
fileName: typeof file === "string" ? file : file.fileName,
|
|
865
|
+
length,
|
|
866
|
+
message,
|
|
867
|
+
phase: rule.trigger,
|
|
868
|
+
ruleName: rule.name,
|
|
869
|
+
severity: rule.defaultSeverity,
|
|
870
|
+
start,
|
|
871
|
+
};
|
|
872
|
+
diagnostics.push(diagnostic);
|
|
873
|
+
return createDiagnosticBuilder(diagnostic);
|
|
874
|
+
}
|
|
875
|
+
return report;
|
|
876
|
+
}
|
|
877
|
+
function createFileSet(fileNames, useCaseSensitive) {
|
|
878
|
+
if (fileNames === undefined || fileNames.length === 0) {
|
|
879
|
+
return undefined;
|
|
880
|
+
}
|
|
881
|
+
const result = Object.create(null);
|
|
882
|
+
const count = fileNames.length;
|
|
883
|
+
for (let index = 0; index < count; index++) {
|
|
884
|
+
result[normalizePath(fileNames[index], useCaseSensitive)] = 1;
|
|
885
|
+
}
|
|
886
|
+
return result;
|
|
887
|
+
}
|
|
888
|
+
function collectSourceFiles(program, useCaseSensitive) {
|
|
889
|
+
const files = program.getSourceFiles();
|
|
890
|
+
const lintable = [];
|
|
891
|
+
const count = files.length;
|
|
892
|
+
for (let index = 0; index < count; index++) {
|
|
893
|
+
const file = files[index];
|
|
894
|
+
if (file.isDeclarationFile === false) {
|
|
895
|
+
lintable.push(file);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
return lintable;
|
|
899
|
+
}
|
|
900
|
+
function getDefaultLibFileName(tsApi, compilerOptions) {
|
|
901
|
+
if (compilerOptions.noLib === true) {
|
|
902
|
+
return "lib.d.ts";
|
|
903
|
+
}
|
|
904
|
+
if (tsApi.getDefaultLibFilePath !== undefined) {
|
|
905
|
+
try {
|
|
906
|
+
return tsApi.getDefaultLibFilePath(compilerOptions);
|
|
907
|
+
}
|
|
908
|
+
catch {
|
|
909
|
+
return "lib.d.ts";
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
return "lib.d.ts";
|
|
913
|
+
}
|
|
914
|
+
function hasTargetRequest(fileNames, currentFile, changedFiles, phase) {
|
|
915
|
+
if (fileNames !== undefined && fileNames.length > 0) {
|
|
916
|
+
return true;
|
|
917
|
+
}
|
|
918
|
+
if (phase === LintPhase.All || phase === LintPhase.Idle) {
|
|
919
|
+
return false;
|
|
920
|
+
}
|
|
921
|
+
if (currentFile !== undefined && currentFile.length > 0) {
|
|
922
|
+
return true;
|
|
923
|
+
}
|
|
924
|
+
return changedFiles !== undefined && changedFiles.length > 0;
|
|
925
|
+
}
|
|
926
|
+
function isInDirectory(fileName, directoryName) {
|
|
927
|
+
if (directoryName === "." || directoryName.length === 0) {
|
|
928
|
+
return true;
|
|
929
|
+
}
|
|
930
|
+
if (fileName === directoryName) {
|
|
931
|
+
return true;
|
|
932
|
+
}
|
|
933
|
+
if (fileName.length <= directoryName.length) {
|
|
934
|
+
return false;
|
|
935
|
+
}
|
|
936
|
+
return fileName.slice(0, directoryName.length) === directoryName && fileName.charCodeAt(directoryName.length) === 47;
|
|
937
|
+
}
|
|
938
|
+
function matchesExtension(fileName, extensions) {
|
|
939
|
+
if (extensions === undefined || extensions.length === 0) {
|
|
940
|
+
return true;
|
|
941
|
+
}
|
|
942
|
+
const count = extensions.length;
|
|
943
|
+
for (let index = 0; index < count; index++) {
|
|
944
|
+
if (fileName.endsWith(extensions[index])) {
|
|
945
|
+
return true;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
return false;
|
|
949
|
+
}
|
|
950
|
+
function matchesPhase(trigger, phase) {
|
|
951
|
+
const phaseTrigger = toRuleTrigger(phase);
|
|
952
|
+
return phase === LintPhase.All || phaseTrigger === trigger;
|
|
953
|
+
}
|
|
954
|
+
function normalizePhase(phase) {
|
|
955
|
+
return phase ?? LintPhase.All;
|
|
956
|
+
}
|
|
957
|
+
function toRuleTrigger(phase) {
|
|
958
|
+
if (phase === LintPhase.All) {
|
|
959
|
+
return undefined;
|
|
960
|
+
}
|
|
961
|
+
return phase;
|
|
962
|
+
}
|
|
963
|
+
function pushDiagnostics(target, source) {
|
|
964
|
+
if (source === undefined || source.length === 0) {
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
const count = source.length;
|
|
968
|
+
for (let index = 0; index < count; index++) {
|
|
969
|
+
target.push(source[index]);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
function resolveKnownFile(tsApi, files, libContents, basePath, useCaseSensitive) {
|
|
973
|
+
const candidates = [
|
|
974
|
+
basePath,
|
|
975
|
+
basePath + ".ts",
|
|
976
|
+
basePath + ".tsx",
|
|
977
|
+
basePath + ".d.ts",
|
|
978
|
+
basePath + ".cts",
|
|
979
|
+
basePath + ".mts",
|
|
980
|
+
basePath + "/index.ts",
|
|
981
|
+
basePath + "/index.tsx",
|
|
982
|
+
basePath + "/index.d.ts",
|
|
983
|
+
];
|
|
984
|
+
const count = candidates.length;
|
|
985
|
+
for (let index = 0; index < count; index++) {
|
|
986
|
+
const candidate = normalizePath(candidates[index], useCaseSensitive);
|
|
987
|
+
if (files[candidate] !== undefined || libContents[candidate] !== undefined) {
|
|
988
|
+
return candidate;
|
|
989
|
+
}
|
|
990
|
+
const sys = tsApi.sys;
|
|
991
|
+
if (sys !== undefined && sys.fileExists !== undefined && sys.fileExists(candidate)) {
|
|
992
|
+
return candidate;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
return undefined;
|
|
996
|
+
}
|
|
997
|
+
function resolveExplicitTargetFiles(program, fileNames, currentFile, changedFiles, phase, useCaseSensitive) {
|
|
998
|
+
if (fileNames !== undefined && fileNames.length > 0) {
|
|
999
|
+
return resolveRequestedProgramFiles(program, fileNames, useCaseSensitive);
|
|
1000
|
+
}
|
|
1001
|
+
if (phase !== LintPhase.All && phase !== LintPhase.Idle) {
|
|
1002
|
+
if (currentFile !== undefined && currentFile.length > 0) {
|
|
1003
|
+
return resolveRequestedProgramFile(program, currentFile, useCaseSensitive);
|
|
1004
|
+
}
|
|
1005
|
+
if (changedFiles !== undefined && changedFiles.length > 0) {
|
|
1006
|
+
return resolveRequestedProgramFiles(program, changedFiles, useCaseSensitive);
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
return EMPTY_SOURCE_FILES;
|
|
1010
|
+
}
|
|
1011
|
+
function resolveRequestedProgramFile(program, fileName, useCaseSensitive) {
|
|
1012
|
+
const exactFile = program.getSourceFile(fileName);
|
|
1013
|
+
if (exactFile !== undefined && exactFile.isDeclarationFile === false) {
|
|
1014
|
+
return [exactFile];
|
|
1015
|
+
}
|
|
1016
|
+
const normalized = normalizePath(fileName, useCaseSensitive);
|
|
1017
|
+
const files = program.getSourceFiles();
|
|
1018
|
+
const count = files.length;
|
|
1019
|
+
for (let index = 0; index < count; index++) {
|
|
1020
|
+
const file = files[index];
|
|
1021
|
+
if (file.isDeclarationFile === false && normalizePath(file.fileName, useCaseSensitive) === normalized) {
|
|
1022
|
+
return [file];
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
return EMPTY_SOURCE_FILES;
|
|
1026
|
+
}
|
|
1027
|
+
function resolveRequestedProgramFiles(program, fileNames, useCaseSensitive) {
|
|
1028
|
+
if (fileNames.length === 1) {
|
|
1029
|
+
return resolveRequestedProgramFile(program, fileNames[0], useCaseSensitive);
|
|
1030
|
+
}
|
|
1031
|
+
const requested = createFileSet(fileNames, useCaseSensitive);
|
|
1032
|
+
if (requested === undefined) {
|
|
1033
|
+
return EMPTY_SOURCE_FILES;
|
|
1034
|
+
}
|
|
1035
|
+
const result = [];
|
|
1036
|
+
const files = program.getSourceFiles();
|
|
1037
|
+
const count = files.length;
|
|
1038
|
+
for (let index = 0; index < count; index++) {
|
|
1039
|
+
const file = files[index];
|
|
1040
|
+
if (file.isDeclarationFile === false && requested[normalizePath(file.fileName, useCaseSensitive)] === 1) {
|
|
1041
|
+
result.push(file);
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
return result;
|
|
1045
|
+
}
|
|
1046
|
+
function runFileRules(tsApi, program, fileRulePlan, file, diagnostics) {
|
|
1047
|
+
if (fileRulePlan === undefined) {
|
|
1048
|
+
return;
|
|
1049
|
+
}
|
|
1050
|
+
const activeRules = fileRulePlan.rules;
|
|
1051
|
+
const checker = fileRulePlan.requiresChecker ? program.getTypeChecker() : undefined;
|
|
1052
|
+
const anyKindVisitors = [];
|
|
1053
|
+
const buckets = [];
|
|
1054
|
+
const activeRuleCount = activeRules.length;
|
|
1055
|
+
for (let index = 0; index < activeRuleCount; index++) {
|
|
1056
|
+
const rule = activeRules[index];
|
|
1057
|
+
const report = createFileReporter(file, rule, diagnostics);
|
|
1058
|
+
const context = {
|
|
1059
|
+
checker: rule.requiresTypeInfo ? checker : undefined,
|
|
1060
|
+
file,
|
|
1061
|
+
options: rule.options,
|
|
1062
|
+
phase: rule.trigger,
|
|
1063
|
+
program,
|
|
1064
|
+
report,
|
|
1065
|
+
sourceText: file.text,
|
|
1066
|
+
typescript: tsApi,
|
|
1067
|
+
};
|
|
1068
|
+
const visitor = rule.definition.create(context);
|
|
1069
|
+
if (visitor !== undefined) {
|
|
1070
|
+
const state = { rule, visitor };
|
|
1071
|
+
const nodeKinds = rule.definition.nodeKinds;
|
|
1072
|
+
if (nodeKinds === undefined || nodeKinds.length === 0) {
|
|
1073
|
+
anyKindVisitors.push(state);
|
|
1074
|
+
}
|
|
1075
|
+
else {
|
|
1076
|
+
const nodeKindCount = nodeKinds.length;
|
|
1077
|
+
for (let kindIndex = 0; kindIndex < nodeKindCount; kindIndex++) {
|
|
1078
|
+
const kind = nodeKinds[kindIndex];
|
|
1079
|
+
let bucket = buckets[kind];
|
|
1080
|
+
if (bucket === undefined) {
|
|
1081
|
+
bucket = [];
|
|
1082
|
+
buckets[kind] = bucket;
|
|
1083
|
+
}
|
|
1084
|
+
bucket.push(state);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
function visit(node) {
|
|
1090
|
+
dispatchVisitors(node, true, anyKindVisitors, buckets);
|
|
1091
|
+
tsApi.forEachChild(node, visit);
|
|
1092
|
+
dispatchVisitors(node, false, anyKindVisitors, buckets);
|
|
1093
|
+
}
|
|
1094
|
+
visit(file);
|
|
1095
|
+
const anyKindVisitorCount = anyKindVisitors.length;
|
|
1096
|
+
for (let index = 0; index < anyKindVisitorCount; index++) {
|
|
1097
|
+
anyKindVisitors[index].visitor.finish?.();
|
|
1098
|
+
}
|
|
1099
|
+
const bucketCount = buckets.length;
|
|
1100
|
+
for (let index = 0; index < bucketCount; index++) {
|
|
1101
|
+
const bucket = buckets[index];
|
|
1102
|
+
if (bucket !== undefined) {
|
|
1103
|
+
const visitorCount = bucket.length;
|
|
1104
|
+
for (let bucketIndex = 0; bucketIndex < visitorCount; bucketIndex++) {
|
|
1105
|
+
bucket[bucketIndex].visitor.finish?.();
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
function runFileSet(tsApi, program, rules, phase, files, includeProjectRules, fileCache) {
|
|
1111
|
+
const diagnostics = [];
|
|
1112
|
+
const fileRulePlan = createFileRulePlan(rules, phase);
|
|
1113
|
+
const count = files.length;
|
|
1114
|
+
for (let index = 0; index < count; index++) {
|
|
1115
|
+
const file = files[index];
|
|
1116
|
+
const fileDiagnostics = [];
|
|
1117
|
+
runFileRules(tsApi, program, fileRulePlan, file, fileDiagnostics);
|
|
1118
|
+
const readonlyFileDiagnostics = fileDiagnostics;
|
|
1119
|
+
fileCache[createFileCacheKey(phase, file.fileName)] = readonlyFileDiagnostics;
|
|
1120
|
+
pushDiagnostics(diagnostics, readonlyFileDiagnostics);
|
|
1121
|
+
}
|
|
1122
|
+
return diagnostics;
|
|
1123
|
+
}
|
|
1124
|
+
function runProgramLint(tsApi, program, rules, phase, fileNames, changedFiles, currentFile, useCaseSensitive, includeProjectRules) {
|
|
1125
|
+
const explicitTargetFiles = resolveExplicitTargetFiles(program, fileNames, currentFile, changedFiles, phase, useCaseSensitive);
|
|
1126
|
+
const targetFiles = explicitTargetFiles.length > 0 || hasTargetRequest(fileNames, currentFile, changedFiles, phase)
|
|
1127
|
+
? explicitTargetFiles
|
|
1128
|
+
: collectSourceFiles(program);
|
|
1129
|
+
const diagnostics = [];
|
|
1130
|
+
const fileRulePlan = createFileRulePlan(rules, phase);
|
|
1131
|
+
const count = targetFiles.length;
|
|
1132
|
+
for (let index = 0; index < count; index++) {
|
|
1133
|
+
runFileRules(tsApi, program, fileRulePlan, targetFiles[index], diagnostics);
|
|
1134
|
+
}
|
|
1135
|
+
return diagnostics;
|
|
1136
|
+
}
|
|
1137
|
+
function runProjectRules(tsApi, program, rules, phase) {
|
|
1138
|
+
const diagnostics = [];
|
|
1139
|
+
let requiresChecker = false;
|
|
1140
|
+
let count = 0;
|
|
1141
|
+
const ruleCount = rules.length;
|
|
1142
|
+
for (let index = 0; index < ruleCount; index++) {
|
|
1143
|
+
const rule = rules[index];
|
|
1144
|
+
if (rule.scope === RuleScope.Project && matchesPhase(rule.trigger, phase) && rule.definition.createProject) {
|
|
1145
|
+
requiresChecker = requiresChecker || rule.requiresTypeInfo;
|
|
1146
|
+
count += 1;
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
if (count === 0) {
|
|
1150
|
+
return EMPTY_DIAGNOSTICS;
|
|
1151
|
+
}
|
|
1152
|
+
const checker = requiresChecker ? program.getTypeChecker() : undefined;
|
|
1153
|
+
for (let index = 0; index < ruleCount; index++) {
|
|
1154
|
+
const rule = rules[index];
|
|
1155
|
+
if (rule.scope === RuleScope.Project && matchesPhase(rule.trigger, phase) && rule.definition.createProject) {
|
|
1156
|
+
rule.definition.createProject({
|
|
1157
|
+
checker: rule.requiresTypeInfo ? checker : undefined,
|
|
1158
|
+
options: rule.options,
|
|
1159
|
+
phase: rule.trigger,
|
|
1160
|
+
program,
|
|
1161
|
+
report: createProjectReporter(rule, diagnostics),
|
|
1162
|
+
typescript: tsApi,
|
|
1163
|
+
});
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
return diagnostics;
|
|
1167
|
+
}
|
|
1168
|
+
function dispatchVisitors(node, entering, anyKindVisitors, buckets) {
|
|
1169
|
+
const anyKindVisitorCount = anyKindVisitors.length;
|
|
1170
|
+
for (let index = 0; index < anyKindVisitorCount; index++) {
|
|
1171
|
+
const visitor = anyKindVisitors[index].visitor;
|
|
1172
|
+
if (entering) {
|
|
1173
|
+
visitor.enter?.(node);
|
|
1174
|
+
}
|
|
1175
|
+
else {
|
|
1176
|
+
visitor.exit?.(node);
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
const bucket = buckets[node.kind];
|
|
1180
|
+
if (bucket === undefined) {
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1183
|
+
const count = bucket.length;
|
|
1184
|
+
for (let index = 0; index < count; index++) {
|
|
1185
|
+
const visitor = bucket[index].visitor;
|
|
1186
|
+
if (entering) {
|
|
1187
|
+
visitor.enter?.(node);
|
|
1188
|
+
}
|
|
1189
|
+
else {
|
|
1190
|
+
visitor.exit?.(node);
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
function clearRecord(record) {
|
|
1195
|
+
for (const key in record) {
|
|
1196
|
+
if (Object.prototype.hasOwnProperty.call(record, key)) {
|
|
1197
|
+
delete record[key];
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
function deleteFileCacheEntries(cache, fileName) {
|
|
1202
|
+
const suffix = "|" + fileName;
|
|
1203
|
+
for (const key in cache) {
|
|
1204
|
+
if (Object.prototype.hasOwnProperty.call(cache, key) && key.endsWith(suffix)) {
|
|
1205
|
+
delete cache[key];
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
export { DiagnosticSeverity as D, LintPhase as L, RuleMeta as R, RuleScope as a, RuleTrigger as b, createLinter as c, defineConfig as d, defineRule as e, getScriptKindFromFileName as g, lintWithProgram as l, normalizePath as n };
|
|
1211
|
+
//# sourceMappingURL=index-CanivEwi.js.map
|