tz-clean 2.1.0 → 2.3.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.
@@ -0,0 +1,19 @@
1
+ # Minified files
2
+ **/*.min.js
3
+ **/*.min.cjs
4
+ **/*.min.mjs
5
+ **/*.bundle.js
6
+
7
+ # Build output
8
+ dist/
9
+ build/
10
+ vendor/
11
+ libs/
12
+
13
+ # Package manager
14
+ node_modules/
15
+
16
+ # Lock files
17
+ package-lock.json
18
+ yarn.lock
19
+ pnpm-lock.yaml
package/eslint.config.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  import js from '@eslint/js';
2
2
  import jsdoc from 'eslint-plugin-jsdoc';
3
+ import noComments from 'eslint-plugin-no-comments';
3
4
  import perfectionist from 'eslint-plugin-perfectionist';
4
5
  import projectStructure from 'eslint-plugin-project-structure';
5
6
  import sonarjs from 'eslint-plugin-sonarjs';
@@ -25,6 +26,9 @@ export default [
25
26
  jsdoc.configs['flat/recommended'],
26
27
  perfectionist.configs['recommended-natural'],
27
28
  {
29
+ linterOptions: {
30
+ reportUnusedDisableDirectives: 'error',
31
+ },
28
32
  languageOptions: {
29
33
  ecmaVersion: 2022,
30
34
  globals: {
@@ -39,6 +43,7 @@ export default [
39
43
  sourceType: 'module',
40
44
  },
41
45
  plugins: {
46
+ 'no-comments': noComments,
42
47
  'project-structure': projectStructure,
43
48
  },
44
49
  rules: {
@@ -54,6 +59,8 @@ export default [
54
59
  'jsdoc/require-jsdoc': 'warn',
55
60
  'jsdoc/require-param': 'warn',
56
61
  'jsdoc/require-returns': 'warn',
62
+ 'no-comments/disallowComments': 'warn',
63
+ 'no-multiple-empty-lines': ['error', { max: 1, maxBOF: 0, maxEOF: 0 }],
57
64
  'no-redeclare': 'off',
58
65
  'no-undef': 'off',
59
66
  'no-unused-vars': ['error', { args: 'none', vars: 'local' }],
package/index.js CHANGED
@@ -140,6 +140,8 @@ async function run() {
140
140
 
141
141
  try {
142
142
  const fixedFiles = runPrettier ? runPrettierTools(includePaths, excludePaths) : [];
143
+ const strippedFiles = stripCommentsAndEmptyLines(includePaths, excludePaths);
144
+ const allFixedFiles = [...new Set([...fixedFiles, ...strippedFiles])];
143
145
  const typecheckResult = runTypecheck ? runTypecheckTools() : { error: null, ran: false };
144
146
  const reportData = runEslint ? runEslintTools(includePaths, excludePaths) : [];
145
147
  const { totalErrors, totalWarnings } = calculateTotals(reportData);
@@ -163,10 +165,10 @@ async function run() {
163
165
  }
164
166
 
165
167
  if (response.reportType === 'terminal') {
166
- printTerminalSummary(reportData, fixedFiles, totalErrors, totalWarnings, typecheckResult);
168
+ printTerminalSummary(reportData, allFixedFiles, totalErrors, totalWarnings, typecheckResult);
167
169
  } else if (response.reportType === 'ui') {
168
170
  console.log('⏳ Generating UI Dashboard...');
169
- const outputPath = generateHtmlReport(reportData, fixedFiles);
171
+ const outputPath = generateHtmlReport(reportData, allFixedFiles);
170
172
  console.log(`🚀 Opening report in browser: ${outputPath}`);
171
173
  await open(outputPath);
172
174
  } else if (response.reportType === 'hosted') {
@@ -174,7 +176,7 @@ async function run() {
174
176
  const templatePath = path.join(configDir, 'report-template.html');
175
177
  let html = fs.readFileSync(templatePath, 'utf-8');
176
178
  html = html.replace('/* REPORT_DATA_PLACEHOLDER */ null', JSON.stringify(reportData));
177
- html = html.replace('/* FIXED_FILES_PLACEHOLDER */ []', JSON.stringify(fixedFiles));
179
+ html = html.replace('/* FIXED_FILES_PLACEHOLDER */ []', JSON.stringify(allFixedFiles));
178
180
  serveHostedReport(html);
179
181
  }
180
182
  } catch (globalError) {
@@ -183,6 +185,73 @@ async function run() {
183
185
  }
184
186
  }
185
187
 
188
+ /**
189
+ * Strips all comments and excess blank lines from JS/TS files in the target paths.
190
+ * Removes single-line comments (//), block comments (/* *\/), eslint-disable directives,
191
+ * and collapses multiple consecutive blank lines into one.
192
+ * @param {string[]} includePaths - Paths to process (defaults to targetDir).
193
+ * @param {string[]} excludePaths - Paths to skip.
194
+ * @returns {string[]} List of files that were modified.
195
+ */
196
+ function stripCommentsAndEmptyLines(includePaths = [], excludePaths = []) {
197
+ const extensions = ['.js', '.ts', '.jsx', '.tsx', '.mjs', '.cjs'];
198
+ const modifiedFiles = [];
199
+
200
+ const defaultIgnorePatterns = [
201
+ /node_modules/,
202
+ /\.min\.(js|cjs|mjs)$/,
203
+ /\.bundle\.js$/,
204
+ /[/\\](dist|build|vendor|libs)[/\\]/,
205
+ ];
206
+
207
+ const userIgnorePatterns = excludePaths.map((p) => new RegExp(p.replace(/\//g, '[/\\\\]')));
208
+ const allIgnorePatterns = [...defaultIgnorePatterns, ...userIgnorePatterns];
209
+
210
+ const scanDir = (dir) => {
211
+ let entries;
212
+ try {
213
+ entries = fs.readdirSync(dir, { withFileTypes: true });
214
+ } catch {
215
+ return;
216
+ }
217
+ for (const entry of entries) {
218
+ const fullPath = path.join(dir, entry.name);
219
+ if (allIgnorePatterns.some((re) => re.test(fullPath))) continue;
220
+ if (entry.isDirectory()) {
221
+ scanDir(fullPath);
222
+ } else if (entry.isFile() && extensions.includes(path.extname(entry.name))) {
223
+ const original = fs.readFileSync(fullPath, 'utf-8');
224
+ let cleaned = original;
225
+
226
+ // Remove block comments /** */ and /* */ (but not shebang)
227
+ cleaned = cleaned.replace(/\/\*[\s\S]*?\*\//g, '');
228
+
229
+ // Remove single-line comments // (including eslint-disable)
230
+ cleaned = cleaned.replace(/[ \t]*\/\/.*$/gm, '');
231
+
232
+ // Collapse multiple blank lines into one
233
+ cleaned = cleaned.replace(/\n{3,}/g, '\n\n');
234
+
235
+ // Remove blank lines at start of file
236
+ cleaned = cleaned.replace(/^\n+/, '');
237
+
238
+ // Ensure single newline at end of file
239
+ cleaned = cleaned.trimEnd() + '\n';
240
+
241
+ if (cleaned !== original) {
242
+ fs.writeFileSync(fullPath, cleaned, 'utf-8');
243
+ modifiedFiles.push(path.relative(targetDir, fullPath));
244
+ }
245
+ }
246
+ }
247
+ };
248
+
249
+ const targets = includePaths.length > 0 ? includePaths.map((p) => path.resolve(targetDir, p)) : [targetDir];
250
+ targets.forEach((t) => scanDir(t));
251
+
252
+ return modifiedFiles;
253
+ }
254
+
186
255
  /**
187
256
  * Executes ESLint to analyze code.
188
257
  * @param {string[]} includePaths - Paths to include in analysis.
@@ -229,11 +298,19 @@ function runPrettierTools(includePaths = [], excludePaths = []) {
229
298
  let fixedFiles = [];
230
299
 
231
300
  const targets = includePaths.length > 0 ? includePaths.map((p) => `"${p}"`).join(' ') : '.';
232
- const ignoreFlags = excludePaths.map((p) => `--ignore-path-without-warn "${p}"`).join(' ');
301
+
302
+ // Build a temporary .prettierignore combining the default one + user excludes
303
+ const defaultIgnorePath = path.join(configDir, '.prettierignore');
304
+ let ignoreContent = fs.readFileSync(defaultIgnorePath, 'utf-8');
305
+ if (excludePaths.length > 0) {
306
+ ignoreContent += '\n# User-specified excludes\n' + excludePaths.join('\n') + '\n';
307
+ }
308
+ const tempIgnorePath = path.join(targetDir, '.tz-clean-prettierignore');
309
+ fs.writeFileSync(tempIgnorePath, ignoreContent);
233
310
 
234
311
  try {
235
312
  const prettierOutput = execSync(
236
- `npx prettier --write ${targets} --config "${path.join(configDir, '.prettierrc')}" --ignore-unknown ${ignoreFlags}`,
313
+ `npx prettier --write ${targets} --config "${path.join(configDir, '.prettierrc')}" --ignore-path "${tempIgnorePath}" --ignore-unknown`,
237
314
  { encoding: 'utf-8' },
238
315
  );
239
316
  fixedFiles = prettierOutput
@@ -247,6 +324,8 @@ function runPrettierTools(includePaths = [], excludePaths = []) {
247
324
  .filter((line) => line.trim() && !line.includes('(unchanged)'))
248
325
  .map((line) => line.split(' ')[0]);
249
326
  }
327
+ } finally {
328
+ if (fs.existsSync(tempIgnorePath)) fs.unlinkSync(tempIgnorePath);
250
329
  }
251
330
  return fixedFiles;
252
331
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tz-clean",
3
- "version": "2.1.0",
3
+ "version": "2.3.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -45,6 +45,7 @@
45
45
  "@eslint/js": "^10.0.1",
46
46
  "eslint": "^10.6.0",
47
47
  "eslint-plugin-jsdoc": "^63.0.12",
48
+ "eslint-plugin-no-comments": "^1.2.1",
48
49
  "eslint-plugin-perfectionist": "^5.10.0",
49
50
  "eslint-plugin-project-structure": "^3.14.3",
50
51
  "eslint-plugin-sonarjs": "^4.1.0",