@kongyo2/ts-comment-scanner 0.0.0 → 1.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.en.md ADDED
@@ -0,0 +1,208 @@
1
+ # ts-comment-scanner
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@kongyo2/ts-comment-scanner.svg)](https://www.npmjs.com/package/@kongyo2/ts-comment-scanner)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@kongyo2/ts-comment-scanner.svg)](https://www.npmjs.com/package/@kongyo2/ts-comment-scanner)
5
+ [![CI](https://github.com/kongyo2/ts-comment-scanner/actions/workflows/ci.yml/badge.svg)](https://github.com/kongyo2/ts-comment-scanner/actions/workflows/ci.yml)
6
+ ![CodeRabbit Pull Request Reviews](https://img.shields.io/coderabbit/prs/github/kongyo2/ts-comment-scanner?utm_source=oss&utm_medium=github&utm_campaign=kongyo2%2Fts-comment-scanner&labelColor=171717&color=FF570A&link=https%3A%2F%2Fcoderabbit.ai&label=CodeRabbit+Reviews)
7
+ [![node](https://img.shields.io/node/v/@kongyo2/ts-comment-scanner.svg)](https://nodejs.org)
8
+ [![license](https://img.shields.io/npm/l/@kongyo2/ts-comment-scanner.svg)](./LICENSE)
9
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/kongyo2/ts-comment-scanner)
10
+
11
+ [日本語](./README.md) | **English**
12
+
13
+ A CLI / library that detects, lists, and summarizes comments in a TypeScript project — and can also remove them safely. It analyzes code through the TypeScript AST, so it never mistakes strings, template literals, regular expressions, or JSX text for comments.
14
+
15
+ ## Features
16
+
17
+ - Recursively scans `.ts` `.tsx` `.mts` `.cts` (excluding `node_modules` and `.git`)
18
+ - Reports line comments (`//`) and block comments (`/* */`) with position information
19
+ - Outputs in three formats: text / JSON / **GitHub Actions annotations**
20
+ - **Automatically identifies compiler and linter directives** such as `@ts-ignore` and `eslint-disable`, so you can filter them in or out
21
+ - **Safe comment removal** (code cleanup): directives and license headers are kept by default
22
+ - **Custom ignore patterns** via glob (`--ignore`) and configurable target extensions (`--ext`)
23
+ - **git integration (`--diff`)**: narrow the scan to files touched between specific commits or in uncommitted work
24
+ - `--fail-on-comment` for CI (exit code 1 when comments are detected)
25
+ - Usable both as a CLI and as a library
26
+
27
+ ## Installation
28
+
29
+ ```bash
30
+ npm install @kongyo2/ts-comment-scanner
31
+ ```
32
+
33
+ To run without installing:
34
+
35
+ ```bash
36
+ npx @kongyo2/ts-comment-scanner src
37
+ ```
38
+
39
+ ## CLI usage
40
+
41
+ ```
42
+ ts-comment-scanner [options] [paths...]
43
+
44
+ Output:
45
+ --format <fmt> Output format: text / json / github (default: text)
46
+ --json Shorthand for --format json
47
+
48
+ Filtering:
49
+ --ignore <glob> Exclude files/directories matching the glob (repeatable)
50
+ --ext <list> Extensions to scan (comma-separated, default: .ts,.tsx,.mts,.cts)
51
+ --diff <range> Only files git reports changed (e.g. HEAD, main..HEAD)
52
+ --skip-directives Exclude compiler/linter directives from the results
53
+ --only-directives Report only directives
54
+
55
+ CI:
56
+ --fail-on-comment Exit with code 1 if any comment is reported
57
+
58
+ Removal:
59
+ --remove Remove reported comments from files (in place)
60
+ --dry-run With --remove: show what would be removed without changing files
61
+ --remove-directives With --remove: also remove directive comments
62
+ --remove-legal With --remove: also remove license/legal comments
63
+
64
+ Other:
65
+ -h, --help Show help
66
+ -v, --version Show version
67
+ ```
68
+
69
+ If no paths are given, the current directory is used. A glob without a slash (e.g. `*.test.ts`) matches against file names, while one that contains a slash (e.g. `src/legacy/**`) matches against paths. Files passed explicitly are never subject to `--ignore`.
70
+
71
+ **Exit codes**: `0` success / `1` comments detected when `--fail-on-comment` is set / `2` argument or runtime error
72
+
73
+ ### Example output
74
+
75
+ ```bash
76
+ $ ts-comment-scanner src
77
+ src/index.ts:1:1 [line] // entry point
78
+ src/scanner.ts:8:3 [block] /* walk the AST */
79
+ src/legacy.ts:3:1 [line] [@ts-ignore] // @ts-ignore fix later
80
+
81
+ 3 comments across 3 files
82
+ ```
83
+
84
+ JSON output:
85
+
86
+ ```bash
87
+ $ ts-comment-scanner --json src
88
+ {
89
+ "summary": { "files": 1, "comments": 1, "directives": 0 },
90
+ "files": [
91
+ {
92
+ "file": "src/index.ts",
93
+ "comments": [
94
+ {
95
+ "kind": "line",
96
+ "text": "// entry point",
97
+ "start": 0,
98
+ "end": 12,
99
+ "line": 1,
100
+ "column": 1,
101
+ "endLine": 1,
102
+ "endColumn": 13
103
+ }
104
+ ]
105
+ }
106
+ ]
107
+ }
108
+ ```
109
+
110
+ Comments identified as directives get a name attached, such as `"directive": "@ts-ignore"`.
111
+
112
+ ### Using it in GitHub Actions
113
+
114
+ `--format github` emits each comment as a [workflow command](https://docs.github.com/actions/reference/workflow-commands-for-github-actions), so annotations appear on the relevant lines of a PR.
115
+
116
+ ```yaml
117
+ - name: Check for stray comments
118
+ run: npx @kongyo2/ts-comment-scanner --format github --skip-directives --fail-on-comment src
119
+ ```
120
+
121
+ ```
122
+ ::notice file=src/index.ts,line=1,endLine=1,col=1,endColumn=13,title=line comment::// entry point
123
+ ```
124
+
125
+ ### Bulk comment removal (code cleanup)
126
+
127
+ ```bash
128
+ # First, check what would be removed
129
+ ts-comment-scanner --remove --dry-run src
130
+
131
+ # Actually remove (directives and license headers are kept)
132
+ ts-comment-scanner --remove src
133
+
134
+ # Remove everything, including directives and legal comments
135
+ ts-comment-scanner --remove --remove-directives --remove-legal src
136
+ ```
137
+
138
+ Removal is driven by the AST's comment ranges, so it never touches strings or code. In addition:
139
+
140
+ - Directives such as `@ts-expect-error` / `eslint-disable` are **kept by default**, because removing them would break the build or the linter
141
+ - Legal comments — `/*! ... */` or those containing `@license` / `@preserve` / `@copyright` — are also **kept by default**
142
+ - Whitespace is inserted where removing a block comment would otherwise join tokens together (`a/* x */b` → `a b`)
143
+ - Comment-only lines are removed entirely, and trailing comments are removed together with the preceding whitespace
144
+ - The result is re-scanned to verify it, and if the outcome is unexpected the file is left unchanged and an error is reported
145
+
146
+ ### Scanning only changed files (`--diff`)
147
+
148
+ With `--diff <range>`, scanning and removal are limited to the files git reports as changed. The range is exactly what `git diff` accepts as revisions: a single revision compares the working tree against it (untracked new files included, honouring `.gitignore`), while `a..b` / `a...b` compare two commits.
149
+
150
+ ```bash
151
+ # Scan only files with uncommitted changes
152
+ ts-comment-scanner --diff HEAD
153
+
154
+ # Remove comments only from files changed on the branch
155
+ ts-comment-scanner --remove --diff main...HEAD
156
+
157
+ # Check only files changed between two commits in CI
158
+ ts-comment-scanner --fail-on-comment --diff a1b2c3..d4e5f6 src
159
+ ```
160
+
161
+ This is designed for workflows like letting a coding agent do some work and then sweeping noise comments out of just the files it touched. Files deleted within the range are excluded, and renames are handled at their new path. git runs in the repository that contains the first input path, so pointing at another repository's checkout works too. Note that unlike `--ignore`, the narrowing also applies to explicitly listed files.
162
+
163
+ ### Detectable directives (excerpt)
164
+
165
+ `@ts-ignore` `@ts-expect-error` `@ts-nocheck` `@ts-check` / the `eslint-disable` family, `eslint-env`, `/* global */` / `tslint:` / the `oxlint-disable` family / the `biome-ignore` family / the `deno-lint-ignore` family / `prettier-ignore` / `istanbul ignore`, `c8 ignore`, `v8 ignore`, `node:coverage` / webpack magic comments such as `webpackChunkName:` / `@vite-ignore` / `#__PURE__` / `//# sourceMappingURL=`, `//# sourceURL=` / `@jsx`-family pragmas / `@jest-environment`, `@vitest-environment` / `/// <reference>` / `#region`, `#endregion`
166
+
167
+ ## Using it as a library
168
+
169
+ ```ts
170
+ import { scanPaths, scanComments, removeComments, changedFiles, formatText } from "@kongyo2/ts-comment-scanner";
171
+
172
+ // Scan files / directories together
173
+ const results = await scanPaths(["src"], { ignore: ["**/*.test.ts"] });
174
+ console.log(formatText(results));
175
+
176
+ // Scan a source string directly
177
+ const comments = scanComments("// hello\nconst x = 1;");
178
+
179
+ // Remove comments safely
180
+ const { code, removed, kept } = removeComments("// note\nconst x = 1;\n");
181
+
182
+ // Absolute paths of files changed in a git revision range
183
+ const changed = await changedFiles("main..HEAD");
184
+ ```
185
+
186
+ ### Main API
187
+
188
+ | Function | Summary |
189
+ | --- | --- |
190
+ | `scanComments(source, options?)` | Get an array of comments from a source string (parse TSX with `options.jsx`) |
191
+ | `scanFile(file)` | Scan a single file |
192
+ | `scanPaths(inputs, options?)` | Recursively scan files / directories (supports `ignore` / `extensions`) |
193
+ | `collectFiles(inputs, options?)` | Collect the list of target file paths |
194
+ | `changedFiles(range, cwd?)` | Absolute paths of working-tree files changed in a git revision range |
195
+ | `removeComments(source, options?)` | Remove comments safely (`removeDirectives` / `removeLegal` / `shouldRemove`) |
196
+ | `detectDirective(kind, text)` | Return a normalized name if the comment is a directive |
197
+ | `isLegalComment(text)` | Determine whether a comment is a license/legal comment |
198
+ | `formatText(results)` / `formatJson(results)` / `formatGitHub(results)` | Format scan results |
199
+
200
+ Types: `Comment` / `CommentKind` / `FileScanResult` / `ScanOptions` / `CollectOptions` / `RemoveOptions` / `RemoveResult`
201
+
202
+ ## Requirements
203
+
204
+ Node.js 20 or later
205
+
206
+ ## License
207
+
208
+ MIT
package/README.md CHANGED
@@ -1,12 +1,27 @@
1
1
  # ts-comment-scanner
2
2
 
3
- TypeScript プロジェクト内のコメントを検出して一覧・集計する CLI / ライブラリです。TypeScript の AST を使って解析するため、文字列やコードの一部を誤検出しません。
3
+ [![npm version](https://img.shields.io/npm/v/@kongyo2/ts-comment-scanner.svg)](https://www.npmjs.com/package/@kongyo2/ts-comment-scanner)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@kongyo2/ts-comment-scanner.svg)](https://www.npmjs.com/package/@kongyo2/ts-comment-scanner)
5
+ [![CI](https://github.com/kongyo2/ts-comment-scanner/actions/workflows/ci.yml/badge.svg)](https://github.com/kongyo2/ts-comment-scanner/actions/workflows/ci.yml)
6
+ ![CodeRabbit Pull Request Reviews](https://img.shields.io/coderabbit/prs/github/kongyo2/ts-comment-scanner?utm_source=oss&utm_medium=github&utm_campaign=kongyo2%2Fts-comment-scanner&labelColor=171717&color=FF570A&link=https%3A%2F%2Fcoderabbit.ai&label=CodeRabbit+Reviews)
7
+ [![node](https://img.shields.io/node/v/@kongyo2/ts-comment-scanner.svg)](https://nodejs.org)
8
+ [![license](https://img.shields.io/npm/l/@kongyo2/ts-comment-scanner.svg)](./LICENSE)
9
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/kongyo2/ts-comment-scanner)
10
+
11
+ **日本語** | [English](./README.en.md)
12
+
13
+ TypeScript プロジェクト内のコメントを検出・一覧・集計し、安全に削除もできる CLI / ライブラリです。TypeScript の AST を使って解析するため、文字列・テンプレートリテラル・正規表現・JSX テキストを誤検出しません。
4
14
 
5
15
  ## 特徴
6
16
 
7
- - `.ts` `.tsx` `.mts` `.cts` を再帰的にスキャン(`node_modules` と `.git` は除外)
17
+ - `.ts` `.tsx` `.mts` `.cts` を再帰的にスキャン(`node_modules` と `.git` は除外)
8
18
  - 行コメント (`//`) とブロックコメント (`/* */`) を位置情報つきで報告
9
- - テキスト形式と JSON 形式の出力に対応
19
+ - テキスト / JSON / **GitHub Actions アノテーション**の 3 形式で出力
20
+ - `@ts-ignore` や `eslint-disable` などの**コンパイラ・リンター指示子(ディレクティブ)を自動判別**し、絞り込み・除外が可能
21
+ - **安全なコメント削除**(コードクリーンアップ): ディレクティブとライセンスヘッダーはデフォルトで保持
22
+ - Glob による**カスタム無視パターン** (`--ignore`)、対象拡張子の変更 (`--ext`)
23
+ - **git 連携 (`--diff`)**: 特定コミット間や未コミットの変更で触れられたファイルだけに対象を絞り込み
24
+ - CI 向けの `--fail-on-comment`(コメント検出時に終了コード 1)
10
25
  - CLI としても、ライブラリとしても利用可能
11
26
 
12
27
  ## インストール
@@ -26,13 +41,34 @@ npx @kongyo2/ts-comment-scanner src
26
41
  ```
27
42
  ts-comment-scanner [options] [paths...]
28
43
 
29
- Options:
30
- --json 結果を JSON で出力
31
- -v, --version バージョンを表示
32
- -h, --help ヘルプを表示
44
+ 出力:
45
+ --format <fmt> 出力形式: text / json / github(既定: text)
46
+ --json --format json の短縮形
47
+
48
+ フィルタリング:
49
+ --ignore <glob> Glob に一致するファイル・ディレクトリを除外(複数指定可)
50
+ --ext <list> スキャン対象の拡張子(カンマ区切り、既定: .ts,.tsx,.mts,.cts)
51
+ --diff <range> git で変更されたファイルのみを対象(例: HEAD, main..HEAD)
52
+ --skip-directives コンパイラ・リンター指示子を結果から除外
53
+ --only-directives 指示子のみを報告
54
+
55
+ CI:
56
+ --fail-on-comment コメントが報告された場合に終了コード 1 で終了
57
+
58
+ 削除:
59
+ --remove 報告対象のコメントをファイルから削除(インプレース)
60
+ --dry-run --remove と併用: 変更せずに削除対象のみ表示
61
+ --remove-directives --remove と併用: 指示子コメントも削除
62
+ --remove-legal --remove と併用: ライセンス・法的コメントも削除
63
+
64
+ その他:
65
+ -h, --help ヘルプを表示
66
+ -v, --version バージョンを表示
33
67
  ```
34
68
 
35
- パスを省略するとカレントディレクトリを対象にします。
69
+ パスを省略するとカレントディレクトリを対象にします。スラッシュを含まない Glob(例: `*.test.ts`)はファイル名に、含むもの(例: `src/legacy/**`)はパスに一致します。明示的に指定したファイルは `--ignore` の対象になりません。
70
+
71
+ **終了コード**: `0` 成功 / `1` `--fail-on-comment` 指定時にコメントを検出 / `2` 引数・実行時エラー
36
72
 
37
73
  ### 出力例
38
74
 
@@ -40,8 +76,9 @@ Options:
40
76
  $ ts-comment-scanner src
41
77
  src/index.ts:1:1 [line] // エントリーポイント
42
78
  src/scanner.ts:8:3 [block] /* AST を走査する */
79
+ src/legacy.ts:3:1 [line] [@ts-ignore] // @ts-ignore 後で直す
43
80
 
44
- 2 comments across 2 files
81
+ 3 comments across 3 files
45
82
  ```
46
83
 
47
84
  JSON 出力:
@@ -49,42 +86,118 @@ JSON 出力:
49
86
  ```bash
50
87
  $ ts-comment-scanner --json src
51
88
  {
52
- "summary": { "files": 1, "comments": 1 },
89
+ "summary": { "files": 1, "comments": 1, "directives": 0 },
53
90
  "files": [
54
91
  {
55
92
  "file": "src/index.ts",
56
93
  "comments": [
57
- { "kind": "line", "text": "// エントリーポイント", "start": 0, "end": 12, "line": 1, "column": 1 }
94
+ {
95
+ "kind": "line",
96
+ "text": "// エントリーポイント",
97
+ "start": 0,
98
+ "end": 12,
99
+ "line": 1,
100
+ "column": 1,
101
+ "endLine": 1,
102
+ "endColumn": 13
103
+ }
58
104
  ]
59
105
  }
60
106
  ]
61
107
  }
62
108
  ```
63
109
 
110
+ ディレクティブと判定されたコメントには `"directive": "@ts-ignore"` のように名前が付きます。
111
+
112
+ ### GitHub Actions で使う
113
+
114
+ `--format github` は各コメントを [workflow command](https://docs.github.com/actions/reference/workflow-commands-for-github-actions) として出力するため、PR の該当行にアノテーションが表示されます。
115
+
116
+ ```yaml
117
+ - name: Check for stray comments
118
+ run: npx @kongyo2/ts-comment-scanner --format github --skip-directives --fail-on-comment src
119
+ ```
120
+
121
+ ```
122
+ ::notice file=src/index.ts,line=1,endLine=1,col=1,endColumn=13,title=line comment::// エントリーポイント
123
+ ```
124
+
125
+ ### コメントの一括削除(コードクリーンアップ)
126
+
127
+ ```bash
128
+ # まず削除対象を確認
129
+ ts-comment-scanner --remove --dry-run src
130
+
131
+ # 実際に削除(ディレクティブとライセンスヘッダーは保持される)
132
+ ts-comment-scanner --remove src
133
+
134
+ # 指示子・ライセンスも含めて完全に削除
135
+ ts-comment-scanner --remove --remove-directives --remove-legal src
136
+ ```
137
+
138
+ 削除は AST のコメント範囲に基づいて行われるため、文字列やコードには影響しません。さらに:
139
+
140
+ - `@ts-expect-error` / `eslint-disable` などの指示子は、削除するとビルドやリントが壊れるため**デフォルトで保持**
141
+ - `/*! ... */` や `@license` / `@preserve` / `@copyright` を含む法的コメントも**デフォルトで保持**
142
+ - ブロックコメント除去でトークンが結合してしまう位置には空白を挿入(`a/* x */b` → `a b`)
143
+ - コメントだけの行は行ごと削除、行末コメントは手前の空白ごと削除
144
+ - 削除後のソースを再スキャンして検証し、想定外の結果になる場合はファイルを変更せずエラー報告
145
+
146
+ ### 変更されたファイルだけを対象にする(`--diff`)
147
+
148
+ `--diff <range>` を付けると、git が変更ありと報告するファイルだけにスキャン・削除を絞り込めます。範囲は `git diff` がリビジョンとして受け付ける書式そのままで、単一リビジョンなら作業ツリーとの比較(未追跡の新規ファイルも含む・`.gitignore` は尊重)、`a..b` / `a...b` ならコミット同士の比較になります。
149
+
150
+ ```bash
151
+ # 未コミットの変更があるファイルだけをスキャン
152
+ ts-comment-scanner --diff HEAD
153
+
154
+ # ブランチで変更されたファイルだけからコメントを削除
155
+ ts-comment-scanner --remove --diff main...HEAD
156
+
157
+ # 特定コミット間で変更されたファイルのみを CI でチェック
158
+ ts-comment-scanner --fail-on-comment --diff a1b2c3..d4e5f6 src
159
+ ```
160
+
161
+ コーディングエージェントに作業させた後、その変更範囲だけを対象にノイズコメントを掃除する、といった使い方を想定しています。範囲内で削除されたファイルは対象外になり、リネームは新しいパスで扱われます。git は最初の入力パスが属するリポジトリで実行されるため、別リポジトリのパスを指定しても動作します。なお `--ignore` と異なり、明示的に指定したファイルにも絞り込みが適用されます。
162
+
163
+ ### 検出できるディレクティブ(抜粋)
164
+
165
+ `@ts-ignore` `@ts-expect-error` `@ts-nocheck` `@ts-check` / `eslint-disable` 系・`eslint-env`・`/* global */` / `tslint:` / `oxlint-disable` 系 / `biome-ignore` 系 / `deno-lint-ignore` 系 / `prettier-ignore` / `istanbul ignore`・`c8 ignore`・`v8 ignore`・`node:coverage` / `webpackChunkName:` などの webpack マジックコメント / `@vite-ignore` / `#__PURE__` / `//# sourceMappingURL=`・`//# sourceURL=` / `@jsx` 系プラグマ / `@jest-environment`・`@vitest-environment` / `/// <reference>` / `#region`・`#endregion`
166
+
64
167
  ## ライブラリとして使う
65
168
 
66
169
  ```ts
67
- import { scanPaths, scanComments, formatText } from "@kongyo2/ts-comment-scanner";
170
+ import { scanPaths, scanComments, removeComments, changedFiles, formatText } from "@kongyo2/ts-comment-scanner";
68
171
 
69
172
  // ファイル / ディレクトリをまとめてスキャン
70
- const results = await scanPaths(["src"]);
173
+ const results = await scanPaths(["src"], { ignore: ["**/*.test.ts"] });
71
174
  console.log(formatText(results));
72
175
 
73
176
  // ソース文字列を直接スキャン
74
177
  const comments = scanComments("// hello\nconst x = 1;");
178
+
179
+ // コメントを安全に削除
180
+ const { code, removed, kept } = removeComments("// note\nconst x = 1;\n");
181
+
182
+ // git のリビジョン範囲で変更されたファイルの絶対パスを取得
183
+ const changed = await changedFiles("main..HEAD");
75
184
  ```
76
185
 
77
186
  ### 主な API
78
187
 
79
188
  | 関数 | 概要 |
80
189
  | --- | --- |
81
- | `scanComments(source, options?)` | ソース文字列からコメント配列を取得(`options.jsx` で TSX を解析) |
190
+ | `scanComments(source, options?)` | ソース文字列からコメント配列を取得(`options.jsx` で TSX を解析) |
82
191
  | `scanFile(file)` | 1 ファイルをスキャン |
83
- | `scanPaths(inputs, options?)` | ファイル / ディレクトリ群を再帰的にスキャン |
192
+ | `scanPaths(inputs, options?)` | ファイル / ディレクトリ群を再帰的にスキャン(`ignore` / `extensions` 対応) |
84
193
  | `collectFiles(inputs, options?)` | 対象ファイルのパス一覧を収集 |
85
- | `formatText(results)` / `formatJson(results)` | スキャン結果を整形 |
194
+ | `changedFiles(range, cwd?)` | git のリビジョン範囲で変更された作業ツリーのファイルを絶対パスで返す |
195
+ | `removeComments(source, options?)` | コメントを安全に削除(`removeDirectives` / `removeLegal` / `shouldRemove`) |
196
+ | `detectDirective(kind, text)` | コメントがディレクティブなら正規化した名前を返す |
197
+ | `isLegalComment(text)` | ライセンス・法的コメントかどうかを判定 |
198
+ | `formatText(results)` / `formatJson(results)` / `formatGitHub(results)` | スキャン結果を整形 |
86
199
 
87
- 型: `Comment` / `CommentKind` / `FileScanResult` / `ScanOptions` / `CollectOptions`
200
+ 型: `Comment` / `CommentKind` / `FileScanResult` / `ScanOptions` / `CollectOptions` / `RemoveOptions` / `RemoveResult`
88
201
 
89
202
  ## 必要環境
90
203
 
package/dist/args.d.ts CHANGED
@@ -1,8 +1,23 @@
1
+ export type OutputFormat = "text" | "json" | "github";
2
+ export type DirectiveMode = "include" | "skip" | "only";
1
3
  export interface CliOptions {
2
4
  paths: string[];
3
- json: boolean;
5
+ format: OutputFormat;
6
+ ignore: string[];
7
+ extensions: string[] | undefined;
8
+ diff: string | undefined;
9
+ directives: DirectiveMode;
10
+ failOnComment: boolean;
11
+ remove: boolean;
12
+ removeDirectives: boolean;
13
+ removeLegal: boolean;
14
+ dryRun: boolean;
4
15
  help: boolean;
5
16
  version: boolean;
6
17
  }
18
+ /** Invalid command line input; the CLI reports the message and exits with code 2. */
19
+ export declare class UsageError extends Error {
20
+ constructor(message: string);
21
+ }
7
22
  export declare function parseArgs(argv: string[]): CliOptions;
8
23
  //# sourceMappingURL=args.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAyBpD"}
1
+ {"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;AACtD,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;AAExD,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACjC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,UAAU,EAAE,aAAa,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,qFAAqF;AACrF,qBAAa,UAAW,SAAQ,KAAK;gBACvB,OAAO,EAAE,MAAM;CAI5B;AAKD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CA+JpD"}
package/dist/args.js CHANGED
@@ -1,25 +1,175 @@
1
+ /** Invalid command line input; the CLI reports the message and exits with code 2. */
2
+ export class UsageError extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "UsageError";
6
+ }
7
+ }
8
+ const FORMATS = ["text", "json", "github"];
9
+ const DIRECTIVE_CONFLICT = "--skip-directives and --only-directives cannot be combined";
1
10
  export function parseArgs(argv) {
2
11
  const paths = [];
3
- let json = false;
12
+ const ignore = [];
13
+ const extensions = [];
14
+ let format = "text";
15
+ let diff;
16
+ let directives = "include";
17
+ let failOnComment = false;
18
+ let remove = false;
19
+ let removeDirectives = false;
20
+ let removeLegal = false;
21
+ let dryRun = false;
4
22
  let help = false;
5
23
  let version = false;
6
- for (const arg of argv) {
7
- switch (arg) {
24
+ let pathsOnly = false;
25
+ for (let index = 0; index < argv.length; index += 1) {
26
+ const arg = argv[index];
27
+ if (pathsOnly || !arg.startsWith("-") || arg === "-") {
28
+ paths.push(arg);
29
+ continue;
30
+ }
31
+ const [flag, inlineValue] = splitFlag(arg);
32
+ const readValue = () => {
33
+ if (inlineValue !== undefined)
34
+ return inlineValue;
35
+ const next = argv[index + 1];
36
+ if (next === undefined)
37
+ throw new UsageError(`option ${flag} requires a value`);
38
+ index += 1;
39
+ return next;
40
+ };
41
+ const rejectValue = () => {
42
+ if (inlineValue !== undefined)
43
+ throw new UsageError(`option ${flag} does not take a value`);
44
+ };
45
+ switch (flag) {
46
+ case "--":
47
+ rejectValue();
48
+ pathsOnly = true;
49
+ break;
50
+ case "--format": {
51
+ const value = readValue();
52
+ if (!FORMATS.includes(value)) {
53
+ throw new UsageError(`unknown format: ${value} (expected ${FORMATS.join(", ")})`);
54
+ }
55
+ format = value;
56
+ break;
57
+ }
8
58
  case "--json":
9
- json = true;
59
+ rejectValue();
60
+ format = "json";
61
+ break;
62
+ case "--ignore":
63
+ ignore.push(readValue());
64
+ break;
65
+ case "--ext": {
66
+ const parsed = readValue()
67
+ .split(",")
68
+ .map((extension) => extension.trim())
69
+ .filter((extension) => extension !== "");
70
+ if (parsed.length === 0) {
71
+ throw new UsageError("option --ext requires at least one extension");
72
+ }
73
+ extensions.push(...parsed);
74
+ break;
75
+ }
76
+ case "--diff": {
77
+ const value = readValue();
78
+ if (value === "" || value.startsWith("-")) {
79
+ throw new UsageError("option --diff requires a git revision range (e.g. HEAD or main..HEAD)");
80
+ }
81
+ diff = value;
82
+ break;
83
+ }
84
+ case "--skip-directives":
85
+ rejectValue();
86
+ if (directives === "only")
87
+ throw new UsageError(DIRECTIVE_CONFLICT);
88
+ directives = "skip";
89
+ break;
90
+ case "--only-directives":
91
+ rejectValue();
92
+ if (directives === "skip")
93
+ throw new UsageError(DIRECTIVE_CONFLICT);
94
+ directives = "only";
95
+ break;
96
+ case "--fail-on-comment":
97
+ rejectValue();
98
+ failOnComment = true;
99
+ break;
100
+ case "--remove":
101
+ rejectValue();
102
+ remove = true;
103
+ break;
104
+ case "--remove-directives":
105
+ rejectValue();
106
+ removeDirectives = true;
107
+ break;
108
+ case "--remove-legal":
109
+ rejectValue();
110
+ removeLegal = true;
111
+ break;
112
+ case "--dry-run":
113
+ rejectValue();
114
+ dryRun = true;
10
115
  break;
11
116
  case "-h":
12
117
  case "--help":
118
+ rejectValue();
13
119
  help = true;
14
120
  break;
15
121
  case "-v":
16
122
  case "--version":
123
+ rejectValue();
17
124
  version = true;
18
125
  break;
19
126
  default:
20
- paths.push(arg);
127
+ throw new UsageError(`unknown option: ${flag}`);
21
128
  }
22
129
  }
23
- return { paths: paths.length > 0 ? paths : ["."], json, help, version };
130
+ if (!remove) {
131
+ for (const [set, flag] of [
132
+ [dryRun, "--dry-run"],
133
+ [removeDirectives, "--remove-directives"],
134
+ [removeLegal, "--remove-legal"],
135
+ ]) {
136
+ if (set)
137
+ throw new UsageError(`${flag} requires --remove`);
138
+ }
139
+ }
140
+ if (remove && failOnComment) {
141
+ throw new UsageError("--fail-on-comment cannot be combined with --remove");
142
+ }
143
+ if (remove && format === "github") {
144
+ throw new UsageError("--format github cannot be combined with --remove");
145
+ }
146
+ if (remove && directives === "only" && !removeDirectives) {
147
+ throw new UsageError("--remove --only-directives would remove nothing; add --remove-directives to delete directives");
148
+ }
149
+ if (remove && directives === "skip" && removeDirectives) {
150
+ throw new UsageError("--remove-directives cannot be combined with --skip-directives");
151
+ }
152
+ return {
153
+ paths: paths.length > 0 ? paths : ["."],
154
+ format,
155
+ ignore,
156
+ extensions: extensions.length > 0 ? extensions : undefined,
157
+ diff,
158
+ directives,
159
+ failOnComment,
160
+ remove,
161
+ removeDirectives,
162
+ removeLegal,
163
+ dryRun,
164
+ help,
165
+ version,
166
+ };
167
+ }
168
+ function splitFlag(arg) {
169
+ const equalsIndex = arg.indexOf("=");
170
+ if (arg.startsWith("--") && equalsIndex > 2) {
171
+ return [arg.slice(0, equalsIndex), arg.slice(equalsIndex + 1)];
172
+ }
173
+ return [arg, undefined];
24
174
  }
25
175
  //# sourceMappingURL=args.js.map
package/dist/args.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,SAAS,CAAC,IAAc;IACtC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,IAAI,GAAG,KAAK,CAAC;IACjB,IAAI,IAAI,GAAG,KAAK,CAAC;IACjB,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,QAAQ,GAAG,EAAE,CAAC;YACZ,KAAK,QAAQ;gBACX,IAAI,GAAG,IAAI,CAAC;gBACZ,MAAM;YACR,KAAK,IAAI,CAAC;YACV,KAAK,QAAQ;gBACX,IAAI,GAAG,IAAI,CAAC;gBACZ,MAAM;YACR,KAAK,IAAI,CAAC;YACV,KAAK,WAAW;gBACd,OAAO,GAAG,IAAI,CAAC;gBACf,MAAM;YACR;gBACE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC1E,CAAC"}
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../src/args.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { CommentKind } from "./types.js";
2
+ /**
3
+ * Returns the canonical name of the compiler/linter/tooling directive the
4
+ * comment represents, or `undefined` when the comment is an ordinary comment.
5
+ */
6
+ export declare function detectDirective(kind: CommentKind, text: string): string | undefined;
7
+ /**
8
+ * True for license/legal comments (`/*!`, `@license`, `@preserve`, `@copyright`)
9
+ * that build tools conventionally keep when stripping comments.
10
+ */
11
+ export declare function isLegalComment(text: string): boolean;
12
+ //# sourceMappingURL=directives.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directives.d.ts","sourceRoot":"","sources":["../src/directives.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAmE9C;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAkCnF;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGpD"}