@kongyo2/ts-comment-scanner 0.0.0 → 1.0.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/dist/run.js CHANGED
@@ -1,42 +1,178 @@
1
- import { parseArgs } from "./args.js";
2
- import { scanPaths } from "./files.js";
3
- import { formatJson, formatText } from "./report.js";
1
+ import { readFile, writeFile } from "node:fs/promises";
2
+ import { parseArgs, UsageError } from "./args.js";
3
+ import { collectFiles, isJsxFile, mapLimit, scanPaths, FILE_CONCURRENCY } from "./files.js";
4
+ import { removeComments } from "./remove.js";
5
+ import { count, formatGitHub, formatJson, formatText } from "./report.js";
4
6
  import { getVersion } from "./version.js";
5
7
  export const HELP_TEXT = `Usage: ts-comment-scanner [options] [paths...]
6
8
 
7
- Detect and report comments across a TypeScript project.
9
+ Detect, report and clean up comments across a TypeScript project.
8
10
 
9
- Options:
10
- --json Output results as JSON
11
- -v, --version Print the version number
12
- -h, --help Show this help
11
+ Output:
12
+ --format <fmt> Output format: text, json or github (default: text)
13
+ --json Shorthand for --format json
13
14
 
14
- Paths default to the current directory. Directories are scanned recursively
15
- for .ts, .tsx, .mts and .cts files, skipping node_modules and .git.
15
+ Filtering:
16
+ --ignore <glob> Skip files/directories matching the glob (repeatable)
17
+ --ext <list> Comma-separated extensions to scan (default: .ts,.tsx,.mts,.cts)
18
+ --skip-directives Hide compiler/linter directives (@ts-ignore, eslint-disable, ...)
19
+ --only-directives Report only compiler/linter directives
20
+
21
+ CI:
22
+ --fail-on-comment Exit with code 1 when any comment is reported
23
+
24
+ Removal:
25
+ --remove Delete the reported comments from the files (in place)
26
+ --dry-run With --remove: show what would be removed, change nothing
27
+ --remove-directives With --remove: also delete directive comments
28
+ --remove-legal With --remove: also delete license/legal comments
29
+
30
+ General:
31
+ -h, --help Show this help
32
+ -v, --version Print the version number
33
+
34
+ Paths default to the current directory. Directories are scanned recursively,
35
+ skipping node_modules and .git. Removal keeps directives and license headers
36
+ unless explicitly requested, so builds and linters keep working.
37
+
38
+ Exit codes: 0 success, 1 comments reported with --fail-on-comment, 2 error.
16
39
 
17
40
  Examples:
18
41
  ts-comment-scanner src
19
- ts-comment-scanner --json src test
42
+ ts-comment-scanner --format github --fail-on-comment src
43
+ ts-comment-scanner --ignore "**/*.test.ts" --skip-directives src
44
+ ts-comment-scanner --remove --dry-run src
20
45
  `;
21
46
  export async function run(argv, io) {
22
- const options = parseArgs(argv);
23
- if (options.help) {
47
+ // Help always wins, even on an otherwise-invalid command line.
48
+ if (wantsHelp(argv)) {
24
49
  io.out(HELP_TEXT);
25
50
  return 0;
26
51
  }
27
- if (options.version) {
28
- io.out(`${await getVersion()}\n`);
29
- return 0;
52
+ let options;
53
+ try {
54
+ options = parseArgs(argv);
55
+ }
56
+ catch (error) {
57
+ if (error instanceof UsageError) {
58
+ io.err(`ts-comment-scanner: ${error.message}\nTry 'ts-comment-scanner --help' for usage.\n`);
59
+ return 2;
60
+ }
61
+ throw error;
30
62
  }
31
63
  try {
32
- const results = await scanPaths(options.paths);
33
- io.out(`${options.json ? formatJson(results) : formatText(results)}\n`);
34
- return 0;
64
+ if (options.version) {
65
+ io.out(`${await getVersion()}\n`);
66
+ return 0;
67
+ }
68
+ const collectOptions = {
69
+ ignore: options.ignore,
70
+ ...(options.extensions === undefined ? {} : { extensions: options.extensions }),
71
+ };
72
+ if (options.remove) {
73
+ return await runRemove(options, collectOptions, io);
74
+ }
75
+ const results = filterDirectives(await scanPaths(options.paths, collectOptions), options.directives);
76
+ io.out(`${render(results, options.format)}\n`);
77
+ const total = results.reduce((sum, result) => sum + result.comments.length, 0);
78
+ return options.failOnComment && total > 0 ? 1 : 0;
35
79
  }
36
80
  catch (error) {
37
81
  const message = error instanceof Error ? error.message : String(error);
38
82
  io.err(`ts-comment-scanner: ${message}\n`);
39
- return 1;
83
+ return 2;
84
+ }
85
+ }
86
+ /** True when -h/--help appears before any `--` separator. */
87
+ function wantsHelp(argv) {
88
+ for (const arg of argv) {
89
+ if (arg === "--")
90
+ return false;
91
+ if (arg === "-h" || arg === "--help")
92
+ return true;
93
+ }
94
+ return false;
95
+ }
96
+ function render(results, format) {
97
+ if (format === "json")
98
+ return formatJson(results);
99
+ if (format === "github")
100
+ return formatGitHub(results);
101
+ return formatText(results);
102
+ }
103
+ function inScope(comment, mode) {
104
+ if (mode === "skip")
105
+ return comment.directive === undefined;
106
+ if (mode === "only")
107
+ return comment.directive !== undefined;
108
+ return true;
109
+ }
110
+ function filterDirectives(results, mode) {
111
+ if (mode === "include")
112
+ return results;
113
+ return results.map((result) => ({
114
+ file: result.file,
115
+ comments: result.comments.filter((comment) => inScope(comment, mode)),
116
+ }));
117
+ }
118
+ async function runRemove(options, collectOptions, io) {
119
+ const files = await collectFiles(options.paths, collectOptions);
120
+ const outcomes = await mapLimit(files, FILE_CONCURRENCY, async (file) => {
121
+ try {
122
+ const source = await readFile(file, "utf8");
123
+ const result = removeComments(source, {
124
+ jsx: isJsxFile(file),
125
+ removeDirectives: options.removeDirectives,
126
+ removeLegal: options.removeLegal,
127
+ shouldRemove: (comment) => inScope(comment, options.directives),
128
+ });
129
+ if (result.changed && !options.dryRun) {
130
+ await writeFile(file, result.code, "utf8");
131
+ }
132
+ return { file, removed: result.removed, kept: result.kept };
133
+ }
134
+ catch (error) {
135
+ const message = error instanceof Error ? error.message : String(error);
136
+ return { file, failure: `${file}: ${message}` };
137
+ }
138
+ });
139
+ const removals = [];
140
+ const failures = [];
141
+ for (const outcome of outcomes) {
142
+ if ("failure" in outcome) {
143
+ failures.push(outcome.failure);
144
+ }
145
+ else if (outcome.removed.length > 0 || outcome.kept.length > 0) {
146
+ removals.push(outcome);
147
+ }
148
+ }
149
+ io.out(`${renderRemoval(removals, options)}\n`);
150
+ for (const failure of failures) {
151
+ io.err(`ts-comment-scanner: ${failure}\n`);
152
+ }
153
+ return failures.length > 0 ? 2 : 0;
154
+ }
155
+ function renderRemoval(removals, options) {
156
+ const totalRemoved = removals.reduce((sum, entry) => sum + entry.removed.length, 0);
157
+ const totalKept = removals.reduce((sum, entry) => sum + entry.kept.length, 0);
158
+ const changedFiles = removals.filter((entry) => entry.removed.length > 0);
159
+ const keptNote = totalKept > 0 ? ` Kept ${count(totalKept, "protected comment")}.` : "";
160
+ if (options.format === "json") {
161
+ return JSON.stringify({
162
+ summary: { files: changedFiles.length, removed: totalRemoved, kept: totalKept, dryRun: options.dryRun },
163
+ files: removals,
164
+ }, null, 2);
165
+ }
166
+ if (totalRemoved === 0) {
167
+ return `No removable comments found.${keptNote}`;
40
168
  }
169
+ const verb = options.dryRun ? "would remove" : "removed";
170
+ const lines = changedFiles.map((entry) => {
171
+ const kept = entry.kept.length > 0 ? ` (kept ${entry.kept.length})` : "";
172
+ return `${entry.file}: ${verb} ${entry.removed.length}${kept}`;
173
+ });
174
+ const sentenceVerb = verb.charAt(0).toUpperCase() + verb.slice(1);
175
+ lines.push("", `${sentenceVerb} ${count(totalRemoved, "comment")} across ${count(changedFiles.length, "file")}.${keptNote}`);
176
+ return lines.join("\n");
41
177
  }
42
178
  //# sourceMappingURL=run.js.map
package/dist/run.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAO1C,MAAM,CAAC,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;CAexB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,IAAc,EAAE,EAAS;IACjD,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAEhC,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAClB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,EAAE,CAAC,GAAG,CAAC,GAAG,MAAM,UAAU,EAAE,IAAI,CAAC,CAAC;QAClC,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC/C,EAAE,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACxE,OAAO,CAAC,CAAC;IACX,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,EAAE,CAAC,GAAG,CAAC,uBAAuB,OAAO,IAAI,CAAC,CAAC;QAC3C,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAe,MAAM,YAAY,CAAC;AAEvD,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,EAAE,CAkDjF"}
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAe,MAAM,YAAY,CAAC;AAEvD,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,EAAE,CA4EjF"}
package/dist/scanner.js CHANGED
@@ -1,7 +1,10 @@
1
1
  import ts from "typescript";
2
+ import { detectDirective } from "./directives.js";
2
3
  export function scanComments(source, options = {}) {
3
- const scriptKind = options.jsx === true ? ts.ScriptKind.TSX : ts.ScriptKind.TS;
4
- const sourceFile = ts.createSourceFile("module.ts", source, ts.ScriptTarget.Latest, true, scriptKind);
4
+ const jsx = options.jsx === true;
5
+ const fileName = jsx ? "module.tsx" : "module.ts";
6
+ const scriptKind = jsx ? ts.ScriptKind.TSX : ts.ScriptKind.TS;
7
+ const sourceFile = ts.createSourceFile(fileName, source, ts.ScriptTarget.Latest, true, scriptKind);
5
8
  const jsxTextSpans = [];
6
9
  const ranges = [];
7
10
  const seen = new Set();
@@ -16,7 +19,10 @@ export function scanComments(source, options = {}) {
16
19
  }
17
20
  };
18
21
  const visit = (node) => {
19
- const children = node.getChildren(sourceFile);
22
+ // JSDoc nodes start inside the comment text itself; descending into them
23
+ // would hide the comment (e.g. a trailing JSDoc attached to the
24
+ // end-of-file token). Treat them as trivia like any other comment.
25
+ const children = node.getChildren(sourceFile).filter((child) => !ts.isJSDoc(child));
20
26
  if (children.length === 0) {
21
27
  if (node.kind === ts.SyntaxKind.JsxText) {
22
28
  jsxTextSpans.push([node.getFullStart(), node.getEnd()]);
@@ -31,19 +37,37 @@ export function scanComments(source, options = {}) {
31
37
  };
32
38
  visit(sourceFile);
33
39
  const insideJsxText = (pos) => jsxTextSpans.some(([start, end]) => pos >= start && pos < end);
40
+ // File-wide pragmas (check pragmas, triple-slash directives, docblock
41
+ // test-environment pragmas, Deno's *-ignore-file forms) only count before
42
+ // the first token; anywhere later the tools treat them as ordinary text.
43
+ const firstTokenStart = sourceFile.getStart(sourceFile);
44
+ const isHeaderOnlyDirective = (directive) => directive === "@ts-nocheck" ||
45
+ directive === "@ts-check" ||
46
+ directive === "@jest-environment" ||
47
+ directive === "@vitest-environment" ||
48
+ directive.endsWith("-ignore-file") ||
49
+ directive.startsWith("triple-slash-");
50
+ const isActiveDirective = (directive, pos) => !isHeaderOnlyDirective(directive) || pos < firstTokenStart;
34
51
  return ranges
35
52
  .filter((range) => !insideJsxText(range.pos))
36
53
  .sort((a, b) => a.pos - b.pos)
37
54
  .map((range) => {
38
55
  const kind = range.kind === ts.SyntaxKind.SingleLineCommentTrivia ? "line" : "block";
39
- const position = sourceFile.getLineAndCharacterOfPosition(range.pos);
56
+ const text = source.slice(range.pos, range.end);
57
+ const startPosition = sourceFile.getLineAndCharacterOfPosition(range.pos);
58
+ const endPosition = sourceFile.getLineAndCharacterOfPosition(range.end);
59
+ const detected = detectDirective(kind, text);
60
+ const directive = detected !== undefined && isActiveDirective(detected, range.pos) ? detected : undefined;
40
61
  return {
41
62
  kind,
42
- text: source.slice(range.pos, range.end),
63
+ text,
43
64
  start: range.pos,
44
65
  end: range.end,
45
- line: position.line + 1,
46
- column: position.character + 1,
66
+ line: startPosition.line + 1,
67
+ column: startPosition.character + 1,
68
+ endLine: endPosition.line + 1,
69
+ endColumn: endPosition.character + 1,
70
+ ...(directive === undefined ? {} : { directive }),
47
71
  };
48
72
  });
49
73
  }
@@ -1 +1 @@
1
- {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -6,6 +6,10 @@ export interface Comment {
6
6
  end: number;
7
7
  line: number;
8
8
  column: number;
9
+ endLine: number;
10
+ endColumn: number;
11
+ /** Canonical name of the compiler/linter directive this comment represents, if any. */
12
+ directive?: string;
9
13
  }
10
14
  export interface FileScanResult {
11
15
  file: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3C,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3C,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,uFAAuF;IACvF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,EAAE,CAAC;CACrB"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kongyo2/ts-comment-scanner",
3
- "version": "0.0.0",
4
- "description": "CLI to detect and report comments across a TypeScript project.",
3
+ "version": "1.0.0",
4
+ "description": "CLI to detect, report and safely remove comments across a TypeScript project.",
5
5
  "keywords": [
6
6
  "typescript",
7
7
  "comments",
@@ -10,6 +10,9 @@
10
10
  "scanner",
11
11
  "ast",
12
12
  "code-analysis",
13
+ "comment-removal",
14
+ "code-cleanup",
15
+ "github-actions",
13
16
  "kongyo2"
14
17
  ],
15
18
  "license": "MIT",
@@ -57,10 +60,12 @@
57
60
  "access": "public"
58
61
  },
59
62
  "dependencies": {
63
+ "picomatch": "^4.0.4",
60
64
  "typescript": "^6.0.3"
61
65
  },
62
66
  "devDependencies": {
63
67
  "@types/node": "^25.9.3",
68
+ "@types/picomatch": "^4.0.3",
64
69
  "oxlint": "^1.70.0",
65
70
  "prettier": "^3.8.4",
66
71
  "vitest": "^4.1.9"