@tsslint/cli 1.3.4 → 1.3.6

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.
Files changed (2) hide show
  1. package/index.js +112 -71
  2. package/package.json +4 -4
package/index.js CHANGED
@@ -6,12 +6,12 @@ const core = require("@tsslint/core");
6
6
  const cache = require("./lib/cache");
7
7
  const glob = require("glob");
8
8
  const fs = require("fs");
9
- const gray = '\x1b[90m';
10
- const purple = '\x1b[35m';
11
- const green = '\x1b[32m';
12
- const red = '\x1b[31m';
13
- const yellow = '\x1b[33m';
14
- const reset = '\x1b[0m';
9
+ const _reset = '\x1b[0m';
10
+ const purple = (s) => '\x1b[35m' + s + _reset;
11
+ const darkGray = (s) => '\x1b[90m' + s + _reset;
12
+ const lightRed = (s) => '\x1b[91m' + s + _reset;
13
+ const lightGreen = (s) => '\x1b[92m' + s + _reset;
14
+ const lightYellow = (s) => '\x1b[93m' + s + _reset;
15
15
  (async () => {
16
16
  let hasError = false;
17
17
  let projectVersion = 0;
@@ -54,8 +54,16 @@ const reset = '\x1b[0m';
54
54
  const languageService = ts.createLanguageService(languageServiceHost);
55
55
  if (process.argv.includes('--project')) {
56
56
  const projectIndex = process.argv.indexOf('--project');
57
- const tsconfig = process.argv[projectIndex + 1];
58
- await projectWorker(tsconfig);
57
+ let tsconfig = process.argv[projectIndex + 1];
58
+ if (tsconfig.startsWith('-') || !tsconfig) {
59
+ clack.log.error(lightRed(`Missing argument for --project.`));
60
+ }
61
+ else {
62
+ if (!tsconfig.startsWith('.')) {
63
+ tsconfig = `./${tsconfig}`;
64
+ }
65
+ await projectWorker(tsconfig);
66
+ }
59
67
  }
60
68
  else if (process.argv.includes('--projects')) {
61
69
  const projectsIndex = process.argv.indexOf('--projects');
@@ -74,20 +82,21 @@ const reset = '\x1b[0m';
74
82
  }
75
83
  }
76
84
  else {
77
- await projectWorker();
85
+ const tsconfig = await askTSConfig();
86
+ await projectWorker(tsconfig);
78
87
  }
79
88
  process.exit(hasError ? 1 : 0);
80
89
  async function projectWorker(tsconfigOption) {
81
- const tsconfig = await getTsconfigPath(tsconfigOption);
82
- clack.intro(`${purple}[project]${reset} ${path.relative(process.cwd(), tsconfig)}`);
90
+ const tsconfig = require.resolve(tsconfigOption, { paths: [process.cwd()] });
91
+ clack.intro(`${purple('[project]')} ${path.relative(process.cwd(), tsconfig)}`);
83
92
  parsed = parseCommonLine(tsconfig);
84
93
  if (!parsed.fileNames.length) {
85
- clack.outro(`${yellow}No input files found.${reset}`);
94
+ clack.outro(lightYellow('No included files.'));
86
95
  return;
87
96
  }
88
97
  const configFile = ts.findConfigFile(path.dirname(tsconfig), ts.sys.fileExists, 'tsslint.config.ts');
89
98
  if (!configFile) {
90
- clack.outro(`${yellow}No tsslint.config.ts found!${reset}`);
99
+ clack.outro(lightYellow('No tsslint.config.ts found.'));
91
100
  return;
92
101
  }
93
102
  if (!configs.has(configFile)) {
@@ -103,9 +112,6 @@ const reset = '\x1b[0m';
103
112
  if (!tsslintConfig) {
104
113
  return;
105
114
  }
106
- if (!parsed.fileNames) {
107
- throw new Error('No input files found in tsconfig!');
108
- }
109
115
  projectVersion++;
110
116
  typeRootsVersion++;
111
117
  const lintCache = process.argv.includes('--force')
@@ -119,16 +125,23 @@ const reset = '\x1b[0m';
119
125
  tsconfig: ts.server.toNormalizedPath(tsconfig),
120
126
  };
121
127
  const linter = core.createLinter(projectContext, tsslintConfig, 'cli', clack);
122
- const lintSpinner = clack.spinner();
128
+ let lintSpinner = clack.spinner();
123
129
  let hasFix = false;
130
+ let excluded = 0;
124
131
  let passed = 0;
125
132
  let errors = 0;
126
133
  let warnings = 0;
127
134
  let cached = 0;
128
- lintSpinner.start();
135
+ let t = Date.now();
136
+ lintSpinner.start(darkGray(`[1/${parsed.fileNames.length}] ${path.relative(process.cwd(), parsed.fileNames[0])}`));
137
+ await new Promise(resolve => setTimeout(resolve, 100));
129
138
  for (let i = 0; i < parsed.fileNames.length; i++) {
130
139
  const fileName = parsed.fileNames[i];
131
- lintSpinner.message(`${gray}[${i + 1}/${parsed.fileNames.length}] ${path.relative(process.cwd(), fileName)}${reset}`);
140
+ if (Date.now() - t > 100) {
141
+ t = Date.now();
142
+ lintSpinner.message(darkGray(`[${i + 1}/${parsed.fileNames.length}] ${path.relative(process.cwd(), fileName)}`));
143
+ await new Promise(resolve => setTimeout(resolve, 0));
144
+ }
132
145
  const fileMtime = fs.statSync(fileName).mtimeMs;
133
146
  let fileCache = lintCache[fileName];
134
147
  if (fileCache) {
@@ -146,6 +159,7 @@ const reset = '\x1b[0m';
146
159
  else {
147
160
  lintCache[fileName] = fileCache = [fileMtime, {}, [], [], {}];
148
161
  }
162
+ let diagnostics;
149
163
  if (process.argv.includes('--fix')) {
150
164
  let retry = 3;
151
165
  let shouldRetry = true;
@@ -159,7 +173,7 @@ const reset = '\x1b[0m';
159
173
  fileCache[2].length = 0;
160
174
  fileCache[3].length = 0;
161
175
  }
162
- const diagnostics = linter.lint(fileName, fileCache);
176
+ diagnostics = linter.lint(fileName, fileCache);
163
177
  const fixes = linter.getCodeFixes(fileName, 0, Number.MAX_VALUE, diagnostics, fileCache);
164
178
  const textChanges = core.combineCodeFixes(fileName, fixes);
165
179
  if (textChanges.length) {
@@ -175,9 +189,16 @@ const reset = '\x1b[0m';
175
189
  ts.sys.writeFile(fileName, newSnapshot.getText(0, newSnapshot.getLength()));
176
190
  fileCache[0] = fs.statSync(fileName).mtimeMs;
177
191
  }
192
+ if (shouldRetry) {
193
+ diagnostics = linter.lint(fileName, fileCache);
194
+ }
178
195
  }
179
196
  else {
180
- const diagnostics = linter.lint(fileName, fileCache);
197
+ diagnostics = linter.lint(fileName, fileCache);
198
+ }
199
+ if (diagnostics.length) {
200
+ hasFix ||= linter.hasCodeFixes(fileName);
201
+ hasError ||= diagnostics.some(diagnostic => diagnostic.category === ts.DiagnosticCategory.Error);
181
202
  for (const diagnostic of diagnostics) {
182
203
  if (diagnostic.category === ts.DiagnosticCategory.Suggestion) {
183
204
  continue;
@@ -187,73 +208,93 @@ const reset = '\x1b[0m';
187
208
  getCanonicalFileName: ts.sys.useCaseSensitiveFileNames ? x => x : x => x.toLowerCase(),
188
209
  getNewLine: () => ts.sys.newLine,
189
210
  });
190
- output = output.replace(`TS${diagnostic.code}`, `TSSLint(${diagnostic.code})`);
191
- if (diagnostic.category === ts.DiagnosticCategory.Error) {
192
- errors++;
193
- clack.log.error(output);
194
- }
195
- else if (diagnostic.category === ts.DiagnosticCategory.Warning) {
196
- warnings++;
197
- clack.log.warn(output);
211
+ output = output.replace(`TS${diagnostic.code}`, String(diagnostic.code));
212
+ if (lintSpinner) {
213
+ if (diagnostic.category === ts.DiagnosticCategory.Error) {
214
+ errors++;
215
+ lintSpinner.stop(output, 1);
216
+ }
217
+ else if (diagnostic.category === ts.DiagnosticCategory.Warning) {
218
+ warnings++;
219
+ lintSpinner.stop(output, 2);
220
+ }
221
+ else {
222
+ lintSpinner.stop(output);
223
+ }
224
+ lintSpinner = undefined;
198
225
  }
199
226
  else {
200
- clack.log.info(output);
227
+ if (diagnostic.category === ts.DiagnosticCategory.Error) {
228
+ errors++;
229
+ clack.log.error(output);
230
+ }
231
+ else if (diagnostic.category === ts.DiagnosticCategory.Warning) {
232
+ warnings++;
233
+ clack.log.warning(output);
234
+ }
235
+ else {
236
+ clack.log.info(output);
237
+ }
201
238
  }
202
239
  }
203
- if (diagnostics.length) {
204
- hasFix ||= linter.hasCodeFixes(fileName);
205
- hasError ||= diagnostics.some(diagnostic => diagnostic.category === ts.DiagnosticCategory.Error);
206
- }
207
- else {
208
- passed++;
209
- }
240
+ }
241
+ else if (!Object.keys(linter.getRules(fileName, fileCache)).length) {
242
+ excluded++;
243
+ }
244
+ else {
245
+ passed++;
246
+ }
247
+ if (!lintSpinner) {
248
+ lintSpinner = clack.spinner();
249
+ lintSpinner.start(darkGray(`[${i + 1}/${parsed.fileNames.length}] ${path.relative(process.cwd(), parsed.fileNames[i])}`));
250
+ await new Promise(resolve => setTimeout(resolve, 100));
210
251
  }
211
252
  }
212
253
  if (cached) {
213
- lintSpinner.stop(`${gray}Checked ${parsed.fileNames.length} files with cache.${reset} ${gray}(Use --force to ignore cache.)${reset}`);
254
+ lintSpinner.stop(darkGray(`Processed ${parsed.fileNames.length} files with cache. (Use --force to ignore cache.)`));
214
255
  }
215
256
  else {
216
- lintSpinner.stop(`${gray}Checked ${parsed.fileNames.length} files.${reset}`);
217
- }
218
- if (hasFix) {
219
- clack.log.message(`${gray}Use --fix to apply fixes.${reset}`);
257
+ lintSpinner.stop(darkGray(`Processed ${parsed.fileNames.length} files.`));
220
258
  }
221
259
  const data = [
222
- [passed, 'passed', green],
223
- [errors, 'errors', red],
224
- [warnings, 'warnings', yellow],
260
+ [passed, 'passed', lightGreen],
261
+ [errors, 'errors', lightRed],
262
+ [warnings, 'warnings', lightYellow],
263
+ [excluded, 'excluded', darkGray],
225
264
  ];
226
- const summary = data
265
+ let summary = data
227
266
  .filter(([count]) => count)
228
- .map(([count, label, color]) => `${color}${count} ${label}${reset}`)
229
- .join(` ${gray}|${reset} `);
267
+ .map(([count, label, color]) => color(`${count} ${label}`))
268
+ .join(darkGray(' | '));
269
+ if (hasFix) {
270
+ summary += darkGray(` (Use --fix to apply automatic fixes.)`);
271
+ }
272
+ else if (errors || warnings) {
273
+ summary += darkGray(` (No fixes available.)`);
274
+ }
230
275
  clack.outro(summary);
231
276
  cache.saveCache(configFile, lintCache, ts.sys.createHash);
232
277
  }
233
- async function getTsconfigPath(tsconfig) {
234
- if (!tsconfig) {
235
- tsconfig = ts.findConfigFile(process.cwd(), ts.sys.fileExists);
236
- let shortTsconfig = tsconfig ? path.relative(process.cwd(), tsconfig) : undefined;
237
- if (!shortTsconfig?.startsWith('.')) {
238
- shortTsconfig = `./${shortTsconfig}`;
239
- }
240
- tsconfig = await clack.text({
241
- message: 'Select the tsconfig project. (Use --project or --projects to skip this prompt.)',
242
- placeholder: shortTsconfig ? `${shortTsconfig} (${parseCommonLine(tsconfig).fileNames.length} files)` : 'No tsconfig.json/jsconfig.json found, please enter the path to the tsconfig.json/jsconfig.json file.',
243
- defaultValue: shortTsconfig,
244
- validate(value) {
245
- value ||= shortTsconfig;
246
- try {
247
- require.resolve(value, { paths: [process.cwd()] });
248
- }
249
- catch {
250
- return `File not found!`;
251
- }
252
- },
253
- });
278
+ async function askTSConfig() {
279
+ const presetConfig = ts.findConfigFile(process.cwd(), ts.sys.fileExists);
280
+ let shortTsconfig = presetConfig ? path.relative(process.cwd(), presetConfig) : undefined;
281
+ if (!shortTsconfig?.startsWith('.')) {
282
+ shortTsconfig = `./${shortTsconfig}`;
254
283
  }
255
- tsconfig = require.resolve(tsconfig, { paths: [process.cwd()] });
256
- return tsconfig;
284
+ return await clack.text({
285
+ message: 'Select the project. (Use --project or --projects to skip this prompt.)',
286
+ placeholder: shortTsconfig ? `${shortTsconfig} (${parseCommonLine(presetConfig).fileNames.length} files)` : 'No tsconfig.json/jsconfig.json found, please enter the path to the tsconfig.json/jsconfig.json file.',
287
+ defaultValue: shortTsconfig,
288
+ validate(value) {
289
+ value ||= shortTsconfig;
290
+ try {
291
+ require.resolve(value, { paths: [process.cwd()] });
292
+ }
293
+ catch {
294
+ return 'No such file.';
295
+ }
296
+ },
297
+ });
257
298
  }
258
299
  function parseCommonLine(tsconfig) {
259
300
  const jsonConfigFile = ts.readJsonConfigFile(tsconfig, ts.sys.readFile);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tsslint/cli",
3
- "version": "1.3.4",
3
+ "version": "1.3.6",
4
4
  "license": "MIT",
5
5
  "bin": {
6
6
  "tsslint": "./bin/tsslint.js"
@@ -16,12 +16,12 @@
16
16
  },
17
17
  "dependencies": {
18
18
  "@clack/prompts": "^0.8.2",
19
- "@tsslint/config": "1.3.4",
20
- "@tsslint/core": "1.3.4",
19
+ "@tsslint/config": "1.3.6",
20
+ "@tsslint/core": "1.3.6",
21
21
  "glob": "^10.4.1"
22
22
  },
23
23
  "peerDependencies": {
24
24
  "typescript": "*"
25
25
  },
26
- "gitHead": "695d85b225a333106ecdc476d096c88b1f77ecee"
26
+ "gitHead": "d153aa87c92803b4c20fef1f5cf2799f1a599099"
27
27
  }