@tsslint/cli 1.3.5 → 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 +107 -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,19 +125,21 @@ 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
135
  let t = Date.now();
129
- lintSpinner.start();
136
+ lintSpinner.start(darkGray(`[1/${parsed.fileNames.length}] ${path.relative(process.cwd(), parsed.fileNames[0])}`));
137
+ await new Promise(resolve => setTimeout(resolve, 100));
130
138
  for (let i = 0; i < parsed.fileNames.length; i++) {
131
139
  const fileName = parsed.fileNames[i];
132
140
  if (Date.now() - t > 100) {
133
141
  t = Date.now();
134
- lintSpinner.message(`${gray}[${i + 1}/${parsed.fileNames.length}] ${path.relative(process.cwd(), fileName)}${reset}`);
142
+ lintSpinner.message(darkGray(`[${i + 1}/${parsed.fileNames.length}] ${path.relative(process.cwd(), fileName)}`));
135
143
  await new Promise(resolve => setTimeout(resolve, 0));
136
144
  }
137
145
  const fileMtime = fs.statSync(fileName).mtimeMs;
@@ -151,6 +159,7 @@ const reset = '\x1b[0m';
151
159
  else {
152
160
  lintCache[fileName] = fileCache = [fileMtime, {}, [], [], {}];
153
161
  }
162
+ let diagnostics;
154
163
  if (process.argv.includes('--fix')) {
155
164
  let retry = 3;
156
165
  let shouldRetry = true;
@@ -164,7 +173,7 @@ const reset = '\x1b[0m';
164
173
  fileCache[2].length = 0;
165
174
  fileCache[3].length = 0;
166
175
  }
167
- const diagnostics = linter.lint(fileName, fileCache);
176
+ diagnostics = linter.lint(fileName, fileCache);
168
177
  const fixes = linter.getCodeFixes(fileName, 0, Number.MAX_VALUE, diagnostics, fileCache);
169
178
  const textChanges = core.combineCodeFixes(fileName, fixes);
170
179
  if (textChanges.length) {
@@ -180,9 +189,16 @@ const reset = '\x1b[0m';
180
189
  ts.sys.writeFile(fileName, newSnapshot.getText(0, newSnapshot.getLength()));
181
190
  fileCache[0] = fs.statSync(fileName).mtimeMs;
182
191
  }
192
+ if (shouldRetry) {
193
+ diagnostics = linter.lint(fileName, fileCache);
194
+ }
183
195
  }
184
196
  else {
185
- 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);
186
202
  for (const diagnostic of diagnostics) {
187
203
  if (diagnostic.category === ts.DiagnosticCategory.Suggestion) {
188
204
  continue;
@@ -192,73 +208,93 @@ const reset = '\x1b[0m';
192
208
  getCanonicalFileName: ts.sys.useCaseSensitiveFileNames ? x => x : x => x.toLowerCase(),
193
209
  getNewLine: () => ts.sys.newLine,
194
210
  });
195
- output = output.replace(`TS${diagnostic.code}`, `TSSLint(${diagnostic.code})`);
196
- if (diagnostic.category === ts.DiagnosticCategory.Error) {
197
- errors++;
198
- clack.log.error(output);
199
- }
200
- else if (diagnostic.category === ts.DiagnosticCategory.Warning) {
201
- warnings++;
202
- 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;
203
225
  }
204
226
  else {
205
- 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
+ }
206
238
  }
207
239
  }
208
- if (diagnostics.length) {
209
- hasFix ||= linter.hasCodeFixes(fileName);
210
- hasError ||= diagnostics.some(diagnostic => diagnostic.category === ts.DiagnosticCategory.Error);
211
- }
212
- else {
213
- passed++;
214
- }
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));
215
251
  }
216
252
  }
217
253
  if (cached) {
218
- 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.)`));
219
255
  }
220
256
  else {
221
- lintSpinner.stop(`${gray}Checked ${parsed.fileNames.length} files.${reset}`);
222
- }
223
- if (hasFix) {
224
- clack.log.message(`${gray}Use --fix to apply fixes.${reset}`);
257
+ lintSpinner.stop(darkGray(`Processed ${parsed.fileNames.length} files.`));
225
258
  }
226
259
  const data = [
227
- [passed, 'passed', green],
228
- [errors, 'errors', red],
229
- [warnings, 'warnings', yellow],
260
+ [passed, 'passed', lightGreen],
261
+ [errors, 'errors', lightRed],
262
+ [warnings, 'warnings', lightYellow],
263
+ [excluded, 'excluded', darkGray],
230
264
  ];
231
- const summary = data
265
+ let summary = data
232
266
  .filter(([count]) => count)
233
- .map(([count, label, color]) => `${color}${count} ${label}${reset}`)
234
- .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
+ }
235
275
  clack.outro(summary);
236
276
  cache.saveCache(configFile, lintCache, ts.sys.createHash);
237
277
  }
238
- async function getTsconfigPath(tsconfig) {
239
- if (!tsconfig) {
240
- tsconfig = ts.findConfigFile(process.cwd(), ts.sys.fileExists);
241
- let shortTsconfig = tsconfig ? path.relative(process.cwd(), tsconfig) : undefined;
242
- if (!shortTsconfig?.startsWith('.')) {
243
- shortTsconfig = `./${shortTsconfig}`;
244
- }
245
- tsconfig = await clack.text({
246
- message: 'Select the tsconfig project. (Use --project or --projects to skip this prompt.)',
247
- 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.',
248
- defaultValue: shortTsconfig,
249
- validate(value) {
250
- value ||= shortTsconfig;
251
- try {
252
- require.resolve(value, { paths: [process.cwd()] });
253
- }
254
- catch {
255
- return `File not found!`;
256
- }
257
- },
258
- });
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}`;
259
283
  }
260
- tsconfig = require.resolve(tsconfig, { paths: [process.cwd()] });
261
- 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
+ });
262
298
  }
263
299
  function parseCommonLine(tsconfig) {
264
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.5",
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.5",
20
- "@tsslint/core": "1.3.5",
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": "6fd4e516735cdf1205a3fa0df91933de72f62476"
26
+ "gitHead": "d153aa87c92803b4c20fef1f5cf2799f1a599099"
27
27
  }