@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/dist/remove.js ADDED
@@ -0,0 +1,223 @@
1
+ import { isLegalComment } from "./directives.js";
2
+ import { scanComments } from "./scanner.js";
3
+ /**
4
+ * Removes comments from TypeScript source without touching code.
5
+ *
6
+ * Safety properties:
7
+ * - AST-based ranges: strings, template literals and regexes are never affected.
8
+ * - Directives (`@ts-expect-error`, `eslint-disable`, ...) and license headers are
9
+ * kept by default, since deleting them changes build/lint behaviour.
10
+ * - A space is inserted where removing a block comment would merge two tokens,
11
+ * and a line break is kept where the comment acted as one (ASI stays intact).
12
+ * - A leading byte-order mark is preserved.
13
+ * - The result is re-scanned; if the remaining comments do not match the kept
14
+ * set, an error is thrown instead of returning corrupted output.
15
+ */
16
+ export function removeComments(source, options = {}) {
17
+ const jsx = options.jsx === true;
18
+ const bom = source.startsWith("\uFEFF") ? "\uFEFF" : "";
19
+ const body = bom === "" ? source : source.slice(bom.length);
20
+ const comments = scanComments(body, { jsx });
21
+ let removed = [];
22
+ const kept = [];
23
+ const skipped = [];
24
+ for (const comment of comments) {
25
+ if (options.shouldRemove?.(comment) === false) {
26
+ skipped.push(comment);
27
+ }
28
+ else if (isProtected(comment, options)) {
29
+ kept.push(comment);
30
+ }
31
+ else {
32
+ removed.push(comment);
33
+ }
34
+ }
35
+ removed = shieldNextLineDirectives(body, removed, kept, skipped);
36
+ if (removed.length === 0) {
37
+ return { code: source, removed, kept, skipped, changed: false };
38
+ }
39
+ const code = bom + splice(body, removed);
40
+ if (scanComments(code, { jsx }).length !== kept.length + skipped.length) {
41
+ throw new Error("comment removal produced an unexpected result; refusing to continue");
42
+ }
43
+ return { code, removed, kept, skipped, changed: true };
44
+ }
45
+ function isProtected(comment, options) {
46
+ if (comment.directive !== undefined && options.removeDirectives !== true)
47
+ return true;
48
+ if (isLegalComment(comment.text) && options.removeLegal !== true)
49
+ return true;
50
+ return false;
51
+ }
52
+ /**
53
+ * Re-protects whole-line comments sitting directly below a surviving
54
+ * next-line directive (`@ts-expect-error`, `eslint-disable-next-line`, ...).
55
+ * Dropping such a line would shift the following code up, silently changing
56
+ * which line the directive applies to.
57
+ */
58
+ function shieldNextLineDirectives(source, removed, kept, skipped) {
59
+ const shieldedLines = new Set();
60
+ for (const comment of [...kept, ...skipped]) {
61
+ if (comment.directive !== undefined && isNextLineDirective(comment.directive)) {
62
+ // Counted pragmas like `c8 ignore next 3` cover several lines.
63
+ for (let offset = 1; offset <= shieldedLineCount(comment.text); offset += 1) {
64
+ shieldedLines.add(comment.endLine + offset);
65
+ }
66
+ }
67
+ }
68
+ if (shieldedLines.size === 0)
69
+ return removed;
70
+ const stillRemoved = [];
71
+ for (const comment of removed) {
72
+ if (shieldedLines.has(comment.line) && occupiesWholeLines(source, comment)) {
73
+ kept.push(comment);
74
+ }
75
+ else {
76
+ stillRemoved.push(comment);
77
+ }
78
+ }
79
+ if (stillRemoved.length !== removed.length) {
80
+ kept.sort((a, b) => a.start - b.start);
81
+ }
82
+ return stillRemoved;
83
+ }
84
+ // File- and range-scoped pragmas (`c8 ignore start`, `istanbul ignore file`,
85
+ // ...) do not target the following line, so they never shield it.
86
+ function isNextLineDirective(name) {
87
+ return (name.endsWith("-next-line") ||
88
+ [
89
+ "@ts-ignore",
90
+ "@ts-expect-error",
91
+ "biome-ignore",
92
+ "deno-lint-ignore",
93
+ "deno-fmt-ignore",
94
+ "deno-coverage-ignore",
95
+ "prettier-ignore",
96
+ "istanbul-ignore",
97
+ "istanbul-ignore-next",
98
+ "istanbul-ignore-if",
99
+ "istanbul-ignore-else",
100
+ "c8-ignore",
101
+ "c8-ignore-next",
102
+ "v8-ignore",
103
+ "v8-ignore-next",
104
+ "node:coverage-ignore",
105
+ ].includes(name));
106
+ }
107
+ /** Number of following lines a next-line pragma covers (`ignore next 3` → 3). */
108
+ function shieldedLineCount(text) {
109
+ const match = /\bignore\s+next\s+(\d{1,4})\b/.exec(text);
110
+ return match ? Math.max(1, Number(match[1])) : 1;
111
+ }
112
+ /** True when nothing but whitespace shares the comment's first and last lines. */
113
+ function occupiesWholeLines(source, comment) {
114
+ const lineStart = source.lastIndexOf("\n", comment.start - 1) + 1;
115
+ if (!isBlank(source.slice(lineStart, comment.start)))
116
+ return false;
117
+ const newlineIndex = source.indexOf("\n", comment.end);
118
+ const lineEnd = newlineIndex === -1 ? source.length : newlineIndex;
119
+ return isBlank(source.slice(comment.end, lineEnd));
120
+ }
121
+ const isBlank = (text) => /^\s*$/.test(text);
122
+ const isHorizontalSpace = (char) => char === " " || char === "\t";
123
+ const LINE_TERMINATOR = /[\n\r\u2028\u2029]/;
124
+ /**
125
+ * Splices sorted, non-overlapping comment ranges out of the source, tidying lines.
126
+ * Output is accumulated as segments with incremental line-state tracking, so the
127
+ * work stays linear in the source size even for comment-dense files.
128
+ */
129
+ function splice(source, removals) {
130
+ const segments = [];
131
+ let cursor = 0;
132
+ /** Whether the output's current (unterminated) line is all whitespace so far. */
133
+ let lineIsBlank = true;
134
+ /** Last character of the output so far ("" while empty). */
135
+ let lastChar = "";
136
+ const push = (chunk) => {
137
+ if (chunk === "")
138
+ return;
139
+ segments.push(chunk);
140
+ const newlineIndex = chunk.lastIndexOf("\n");
141
+ lineIsBlank = newlineIndex === -1 ? lineIsBlank && isBlank(chunk) : isBlank(chunk.slice(newlineIndex + 1));
142
+ lastChar = chunk.slice(-1);
143
+ };
144
+ /** Deletes everything the output holds after its last line break. */
145
+ const dropCurrentLine = () => {
146
+ while (segments.length > 0) {
147
+ const last = segments[segments.length - 1];
148
+ const newlineIndex = last.lastIndexOf("\n");
149
+ if (newlineIndex === -1) {
150
+ segments.pop();
151
+ continue;
152
+ }
153
+ segments[segments.length - 1] = last.slice(0, newlineIndex + 1);
154
+ lineIsBlank = true;
155
+ lastChar = "\n";
156
+ return;
157
+ }
158
+ lineIsBlank = true;
159
+ lastChar = "";
160
+ };
161
+ /** Deletes trailing spaces/tabs of the output's current line. */
162
+ const trimLineEnd = () => {
163
+ while (segments.length > 0) {
164
+ const last = segments[segments.length - 1];
165
+ let end = last.length;
166
+ while (end > 0 && isHorizontalSpace(last[end - 1]))
167
+ end -= 1;
168
+ if (end === 0) {
169
+ segments.pop();
170
+ continue;
171
+ }
172
+ if (end < last.length)
173
+ segments[segments.length - 1] = last.slice(0, end);
174
+ lastChar = segments[segments.length - 1].slice(-1);
175
+ return;
176
+ }
177
+ lastChar = "";
178
+ };
179
+ for (const comment of removals) {
180
+ push(source.slice(cursor, comment.start));
181
+ cursor = comment.end;
182
+ const newlineIndex = source.indexOf("\n", cursor);
183
+ const lineEnd = newlineIndex === -1 ? source.length : newlineIndex + 1;
184
+ const rest = source.slice(cursor, lineEnd);
185
+ const eolLength = rest.endsWith("\r\n") ? 2 : rest.endsWith("\n") ? 1 : 0;
186
+ const restContent = rest.slice(0, rest.length - eolLength);
187
+ if (lineIsBlank && isBlank(restContent)) {
188
+ // The comment occupied whole line(s): drop them entirely.
189
+ dropCurrentLine();
190
+ cursor = lineEnd;
191
+ }
192
+ else if (isBlank(restContent)) {
193
+ // Trailing comment after code: trim the gap, keep the line break.
194
+ trimLineEnd();
195
+ push(rest.slice(restContent.length));
196
+ cursor = lineEnd;
197
+ }
198
+ else if (!lineIsBlank && LINE_TERMINATOR.test(comment.text)) {
199
+ // Code on both sides of a block comment that spans lines. Per ECMA-262
200
+ // such a comment acts as a line terminator for semicolon insertion, so
201
+ // replace it with a real line break (matching the file's style) instead
202
+ // of merging the lines.
203
+ trimLineEnd();
204
+ push(comment.text.includes("\r\n") ? "\r\n" : "\n");
205
+ }
206
+ else {
207
+ // Inline comment with code after it on the same line.
208
+ const next = source.charAt(cursor);
209
+ if (lastChar !== "" && !isBlank(lastChar) && !isBlank(next)) {
210
+ // `a/* x */b` would merge tokens: keep them apart.
211
+ push(" ");
212
+ }
213
+ else if (lastChar === "" || isBlank(lastChar)) {
214
+ // Collapse the horizontal whitespace that followed the comment.
215
+ while (cursor < lineEnd && isHorizontalSpace(source[cursor]))
216
+ cursor += 1;
217
+ }
218
+ }
219
+ }
220
+ segments.push(source.slice(cursor));
221
+ return segments.join("");
222
+ }
223
+ //# sourceMappingURL=remove.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remove.js","sourceRoot":"","sources":["../src/remove.ts"],"names":[],"mappings":"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"}
package/dist/report.d.ts CHANGED
@@ -1,4 +1,12 @@
1
1
  import type { FileScanResult } from "./types.js";
2
+ /** Formats `3 comments`, `1 file`, ... with naive pluralization. */
3
+ export declare function count(value: number, noun: string): string;
2
4
  export declare function formatText(results: FileScanResult[]): string;
3
5
  export declare function formatJson(results: FileScanResult[]): string;
6
+ /**
7
+ * Formats results as GitHub Actions workflow commands so each comment shows up
8
+ * as an annotation on the corresponding file and line in CI.
9
+ * See https://docs.github.com/actions/reference/workflow-commands-for-github-actions
10
+ */
11
+ export declare function formatGitHub(results: FileScanResult[]): string;
4
12
  //# sourceMappingURL=report.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,wBAAgB,UAAU,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,MAAM,CAkB5D;AAcD,wBAAgB,UAAU,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,MAAM,CAK5D"}
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,cAAc,EAAE,MAAM,YAAY,CAAC;AAE1D,oEAAoE;AACpE,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAwBD,wBAAgB,UAAU,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,MAAM,CAK5D;AAUD,wBAAgB,UAAU,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,MAAM,CAS5D;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,MAAM,CAE9D"}
package/dist/report.js CHANGED
@@ -1,19 +1,32 @@
1
- export function formatText(results) {
2
- const withComments = results.filter((result) => result.comments.length > 0);
3
- if (withComments.length === 0) {
4
- return "No comments found.";
5
- }
1
+ /** Formats `3 comments`, `1 file`, ... with naive pluralization. */
2
+ export function count(value, noun) {
3
+ return `${value} ${noun}${value === 1 ? "" : "s"}`;
4
+ }
5
+ function renderComments(results, renderLine) {
6
6
  const lines = [];
7
7
  let total = 0;
8
- for (const { file, comments } of withComments) {
8
+ let fileCount = 0;
9
+ for (const { file, comments } of results) {
10
+ if (comments.length === 0)
11
+ continue;
12
+ fileCount += 1;
9
13
  for (const comment of comments) {
10
- lines.push(`${file}:${comment.line}:${comment.column} [${comment.kind}] ${preview(comment.text)}`);
14
+ lines.push(renderLine(file, comment));
11
15
  total += 1;
12
16
  }
13
17
  }
14
- lines.push("", `${count(total, "comment")} across ${count(withComments.length, "file")}`);
18
+ if (total === 0) {
19
+ return "No comments found.";
20
+ }
21
+ lines.push("", `${count(total, "comment")} across ${count(fileCount, "file")}`);
15
22
  return lines.join("\n");
16
23
  }
24
+ export function formatText(results) {
25
+ return renderComments(results, (file, comment) => {
26
+ const tag = comment.directive === undefined ? "" : ` [${comment.directive}]`;
27
+ return `${file}:${comment.line}:${comment.column} [${comment.kind}]${tag} ${preview(comment.text)}`;
28
+ });
29
+ }
17
30
  function preview(text) {
18
31
  return text
19
32
  .split("\n")
@@ -21,12 +34,33 @@ function preview(text) {
21
34
  .join(" ")
22
35
  .trim();
23
36
  }
24
- function count(value, noun) {
25
- return `${value} ${noun}${value === 1 ? "" : "s"}`;
26
- }
27
37
  export function formatJson(results) {
28
38
  const files = results.filter((result) => result.comments.length > 0);
29
39
  const comments = files.reduce((sum, file) => sum + file.comments.length, 0);
30
- return JSON.stringify({ summary: { files: files.length, comments }, files }, null, 2);
40
+ const directives = files.reduce((sum, file) => sum + file.comments.filter((comment) => comment.directive !== undefined).length, 0);
41
+ return JSON.stringify({ summary: { files: files.length, comments, directives }, files }, null, 2);
42
+ }
43
+ /**
44
+ * Formats results as GitHub Actions workflow commands so each comment shows up
45
+ * as an annotation on the corresponding file and line in CI.
46
+ * See https://docs.github.com/actions/reference/workflow-commands-for-github-actions
47
+ */
48
+ export function formatGitHub(results) {
49
+ return renderComments(results, annotation);
50
+ }
51
+ function annotation(file, comment) {
52
+ const title = comment.directive === undefined ? `${comment.kind} comment` : `${comment.kind} comment (${comment.directive})`;
53
+ const properties = [`file=${escapeProperty(file)}`, `line=${comment.line}`, `endLine=${comment.endLine}`];
54
+ if (comment.line === comment.endLine) {
55
+ properties.push(`col=${comment.column}`, `endColumn=${comment.endColumn}`);
56
+ }
57
+ properties.push(`title=${escapeProperty(title)}`);
58
+ return `::notice ${properties.join(",")}::${escapeData(comment.text)}`;
59
+ }
60
+ function escapeData(value) {
61
+ return value.replaceAll("%", "%25").replaceAll("\r", "%0D").replaceAll("\n", "%0A");
62
+ }
63
+ function escapeProperty(value) {
64
+ return escapeData(value).replaceAll(":", "%3A").replaceAll(",", "%2C");
31
65
  }
32
66
  //# sourceMappingURL=report.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,UAAU,CAAC,OAAyB;IAClD,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAE5E,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,oBAAoB,CAAC;IAC9B,CAAC;IAED,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,YAAY,EAAE,CAAC;QAC9C,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACnG,KAAK,IAAI,CAAC,CAAC;QACb,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,SAAS,CAAC,WAAW,KAAK,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IAC1F,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,OAAO,CAAC,IAAY;IAC3B,OAAO,IAAI;SACR,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,IAAI,CAAC,GAAG,CAAC;SACT,IAAI,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,KAAK,CAAC,KAAa,EAAE,IAAY;IACxC,OAAO,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAyB;IAClD,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACrE,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAE5E,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACxF,CAAC"}
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"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"}
package/dist/run.d.ts CHANGED
@@ -2,6 +2,6 @@ export interface CliIO {
2
2
  out: (text: string) => void;
3
3
  err: (text: string) => void;
4
4
  }
5
- export declare const HELP_TEXT = "Usage: ts-comment-scanner [options] [paths...]\n\nDetect and report comments across a TypeScript project.\n\nOptions:\n --json Output results as JSON\n -v, --version Print the version number\n -h, --help Show this help\n\nPaths default to the current directory. Directories are scanned recursively\nfor .ts, .tsx, .mts and .cts files, skipping node_modules and .git.\n\nExamples:\n ts-comment-scanner src\n ts-comment-scanner --json src test\n";
5
+ export declare const HELP_TEXT = "Usage: ts-comment-scanner [options] [paths...]\n\nDetect, report and clean up comments across a TypeScript project.\n\nOutput:\n --format <fmt> Output format: text, json or github (default: text)\n --json Shorthand for --format json\n\nFiltering:\n --ignore <glob> Skip files/directories matching the glob (repeatable)\n --ext <list> Comma-separated extensions to scan (default: .ts,.tsx,.mts,.cts)\n --diff <range> Only files git reports changed in the revision range\n --skip-directives Hide compiler/linter directives (@ts-ignore, eslint-disable, ...)\n --only-directives Report only compiler/linter directives\n\nCI:\n --fail-on-comment Exit with code 1 when any comment is reported\n\nRemoval:\n --remove Delete the reported comments from the files (in place)\n --dry-run With --remove: show what would be removed, change nothing\n --remove-directives With --remove: also delete directive comments\n --remove-legal With --remove: also delete license/legal comments\n\nGeneral:\n -h, --help Show this help\n -v, --version Print the version number\n\nPaths default to the current directory. Directories are scanned recursively,\nskipping node_modules and .git. Removal keeps directives and license headers\nunless explicitly requested, so builds and linters keep working.\n\n--diff narrows any scan or removal to files changed in git: a single revision\ncompares the working tree against it (HEAD covers all uncommitted work,\nuntracked files included), while main..HEAD compares two commits. Handy for\ncleaning up only the files a coding agent just touched.\n\nExit codes: 0 success, 1 comments reported with --fail-on-comment, 2 error.\n\nExamples:\n ts-comment-scanner src\n ts-comment-scanner --format github --fail-on-comment src\n ts-comment-scanner --ignore \"**/*.test.ts\" --skip-directives src\n ts-comment-scanner --remove --dry-run src\n ts-comment-scanner --remove --diff main..HEAD\n";
6
6
  export declare function run(argv: string[], io: CliIO): Promise<number>;
7
7
  //# sourceMappingURL=run.d.ts.map
package/dist/run.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,KAAK;IACpB,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B;AAED,eAAO,MAAM,SAAS,kdAerB,CAAC;AAEF,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBpE"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,KAAK;IACpB,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B;AAED,eAAO,MAAM,SAAS,o+DA6CrB,CAAC;AAEF,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CA4CpE"}
package/dist/run.js CHANGED
@@ -1,42 +1,207 @@
1
- import { parseArgs } from "./args.js";
2
- import { scanPaths } from "./files.js";
3
- import { formatJson, formatText } from "./report.js";
1
+ import { realpathSync } from "node:fs";
2
+ import { readFile, stat, writeFile } from "node:fs/promises";
3
+ import { basename, dirname, join, resolve } from "node:path";
4
+ import { parseArgs, UsageError } from "./args.js";
5
+ import { collectFiles, isJsxFile, mapLimit, scanFile, FILE_CONCURRENCY } from "./files.js";
6
+ import { changedFiles } from "./git.js";
7
+ import { removeComments } from "./remove.js";
8
+ import { count, formatGitHub, formatJson, formatText } from "./report.js";
4
9
  import { getVersion } from "./version.js";
5
10
  export const HELP_TEXT = `Usage: ts-comment-scanner [options] [paths...]
6
11
 
7
- Detect and report comments across a TypeScript project.
12
+ Detect, report and clean up comments across a TypeScript project.
8
13
 
9
- Options:
10
- --json Output results as JSON
11
- -v, --version Print the version number
12
- -h, --help Show this help
14
+ Output:
15
+ --format <fmt> Output format: text, json or github (default: text)
16
+ --json Shorthand for --format json
13
17
 
14
- Paths default to the current directory. Directories are scanned recursively
15
- for .ts, .tsx, .mts and .cts files, skipping node_modules and .git.
18
+ Filtering:
19
+ --ignore <glob> Skip files/directories matching the glob (repeatable)
20
+ --ext <list> Comma-separated extensions to scan (default: .ts,.tsx,.mts,.cts)
21
+ --diff <range> Only files git reports changed in the revision range
22
+ --skip-directives Hide compiler/linter directives (@ts-ignore, eslint-disable, ...)
23
+ --only-directives Report only compiler/linter directives
24
+
25
+ CI:
26
+ --fail-on-comment Exit with code 1 when any comment is reported
27
+
28
+ Removal:
29
+ --remove Delete the reported comments from the files (in place)
30
+ --dry-run With --remove: show what would be removed, change nothing
31
+ --remove-directives With --remove: also delete directive comments
32
+ --remove-legal With --remove: also delete license/legal comments
33
+
34
+ General:
35
+ -h, --help Show this help
36
+ -v, --version Print the version number
37
+
38
+ Paths default to the current directory. Directories are scanned recursively,
39
+ skipping node_modules and .git. Removal keeps directives and license headers
40
+ unless explicitly requested, so builds and linters keep working.
41
+
42
+ --diff narrows any scan or removal to files changed in git: a single revision
43
+ compares the working tree against it (HEAD covers all uncommitted work,
44
+ untracked files included), while main..HEAD compares two commits. Handy for
45
+ cleaning up only the files a coding agent just touched.
46
+
47
+ Exit codes: 0 success, 1 comments reported with --fail-on-comment, 2 error.
16
48
 
17
49
  Examples:
18
50
  ts-comment-scanner src
19
- ts-comment-scanner --json src test
51
+ ts-comment-scanner --format github --fail-on-comment src
52
+ ts-comment-scanner --ignore "**/*.test.ts" --skip-directives src
53
+ ts-comment-scanner --remove --dry-run src
54
+ ts-comment-scanner --remove --diff main..HEAD
20
55
  `;
21
56
  export async function run(argv, io) {
22
- const options = parseArgs(argv);
23
- if (options.help) {
57
+ // Help always wins, even on an otherwise-invalid command line.
58
+ if (wantsHelp(argv)) {
24
59
  io.out(HELP_TEXT);
25
60
  return 0;
26
61
  }
27
- if (options.version) {
28
- io.out(`${await getVersion()}\n`);
29
- return 0;
62
+ let options;
63
+ try {
64
+ options = parseArgs(argv);
65
+ }
66
+ catch (error) {
67
+ if (error instanceof UsageError) {
68
+ io.err(`ts-comment-scanner: ${error.message}\nTry 'ts-comment-scanner --help' for usage.\n`);
69
+ return 2;
70
+ }
71
+ throw error;
30
72
  }
31
73
  try {
32
- const results = await scanPaths(options.paths);
33
- io.out(`${options.json ? formatJson(results) : formatText(results)}\n`);
34
- return 0;
74
+ if (options.version) {
75
+ io.out(`${await getVersion()}\n`);
76
+ return 0;
77
+ }
78
+ const collectOptions = {
79
+ ignore: options.ignore,
80
+ ...(options.extensions === undefined ? {} : { extensions: options.extensions }),
81
+ };
82
+ if (options.remove) {
83
+ return await runRemove(options, collectOptions, io);
84
+ }
85
+ const files = await collectTargets(options, collectOptions);
86
+ const results = filterDirectives(await mapLimit(files, FILE_CONCURRENCY, scanFile), options.directives);
87
+ io.out(`${render(results, options.format)}\n`);
88
+ const total = results.reduce((sum, result) => sum + result.comments.length, 0);
89
+ return options.failOnComment && total > 0 ? 1 : 0;
35
90
  }
36
91
  catch (error) {
37
92
  const message = error instanceof Error ? error.message : String(error);
38
93
  io.err(`ts-comment-scanner: ${message}\n`);
39
- return 1;
94
+ return 2;
95
+ }
96
+ }
97
+ /**
98
+ * Collects the input files, narrowed to the files git reports changed when
99
+ * --diff is set. git runs in the repository containing the first input path
100
+ * (not the collected files, which could sit in a nested repository), so
101
+ * scanning another repository's checkout works from anywhere.
102
+ */
103
+ async function collectTargets(options, collectOptions) {
104
+ const files = await collectFiles(options.paths, collectOptions);
105
+ if (options.diff === undefined)
106
+ return files;
107
+ const first = resolve(options.paths[0]);
108
+ const anchor = (await stat(first)).isDirectory() ? first : dirname(first);
109
+ const changed = new Set(await changedFiles(options.diff, anchor));
110
+ // Realpath only the directory part: spellings through symlinked directories
111
+ // then compare equal, while a tracked symlink still matches the path git
112
+ // reports it at instead of dereferencing to its target.
113
+ return files.filter((file) => changed.has(join(realpathSync(dirname(file)), basename(file))));
114
+ }
115
+ /** True when -h/--help appears before any `--` separator. */
116
+ function wantsHelp(argv) {
117
+ for (const arg of argv) {
118
+ if (arg === "--")
119
+ return false;
120
+ if (arg === "-h" || arg === "--help")
121
+ return true;
122
+ }
123
+ return false;
124
+ }
125
+ function render(results, format) {
126
+ if (format === "json")
127
+ return formatJson(results);
128
+ if (format === "github")
129
+ return formatGitHub(results);
130
+ return formatText(results);
131
+ }
132
+ function inScope(comment, mode) {
133
+ if (mode === "skip")
134
+ return comment.directive === undefined;
135
+ if (mode === "only")
136
+ return comment.directive !== undefined;
137
+ return true;
138
+ }
139
+ function filterDirectives(results, mode) {
140
+ if (mode === "include")
141
+ return results;
142
+ return results.map((result) => ({
143
+ file: result.file,
144
+ comments: result.comments.filter((comment) => inScope(comment, mode)),
145
+ }));
146
+ }
147
+ async function runRemove(options, collectOptions, io) {
148
+ const files = await collectTargets(options, collectOptions);
149
+ const outcomes = await mapLimit(files, FILE_CONCURRENCY, async (file) => {
150
+ try {
151
+ const source = await readFile(file, "utf8");
152
+ const result = removeComments(source, {
153
+ jsx: isJsxFile(file),
154
+ removeDirectives: options.removeDirectives,
155
+ removeLegal: options.removeLegal,
156
+ shouldRemove: (comment) => inScope(comment, options.directives),
157
+ });
158
+ if (result.changed && !options.dryRun) {
159
+ await writeFile(file, result.code, "utf8");
160
+ }
161
+ return { file, removed: result.removed, kept: result.kept };
162
+ }
163
+ catch (error) {
164
+ const message = error instanceof Error ? error.message : String(error);
165
+ return { file, failure: `${file}: ${message}` };
166
+ }
167
+ });
168
+ const removals = [];
169
+ const failures = [];
170
+ for (const outcome of outcomes) {
171
+ if ("failure" in outcome) {
172
+ failures.push(outcome.failure);
173
+ }
174
+ else if (outcome.removed.length > 0 || outcome.kept.length > 0) {
175
+ removals.push(outcome);
176
+ }
177
+ }
178
+ io.out(`${renderRemoval(removals, options)}\n`);
179
+ for (const failure of failures) {
180
+ io.err(`ts-comment-scanner: ${failure}\n`);
181
+ }
182
+ return failures.length > 0 ? 2 : 0;
183
+ }
184
+ function renderRemoval(removals, options) {
185
+ const totalRemoved = removals.reduce((sum, entry) => sum + entry.removed.length, 0);
186
+ const totalKept = removals.reduce((sum, entry) => sum + entry.kept.length, 0);
187
+ const changedEntries = removals.filter((entry) => entry.removed.length > 0);
188
+ const keptNote = totalKept > 0 ? ` Kept ${count(totalKept, "protected comment")}.` : "";
189
+ if (options.format === "json") {
190
+ return JSON.stringify({
191
+ summary: { files: changedEntries.length, removed: totalRemoved, kept: totalKept, dryRun: options.dryRun },
192
+ files: removals,
193
+ }, null, 2);
194
+ }
195
+ if (totalRemoved === 0) {
196
+ return `No removable comments found.${keptNote}`;
40
197
  }
198
+ const verb = options.dryRun ? "would remove" : "removed";
199
+ const lines = changedEntries.map((entry) => {
200
+ const kept = entry.kept.length > 0 ? ` (kept ${entry.kept.length})` : "";
201
+ return `${entry.file}: ${verb} ${entry.removed.length}${kept}`;
202
+ });
203
+ const sentenceVerb = verb.charAt(0).toUpperCase() + verb.slice(1);
204
+ lines.push("", `${sentenceVerb} ${count(totalRemoved, "comment")} across ${count(changedEntries.length, "file")}.${keptNote}`);
205
+ return lines.join("\n");
41
206
  }
42
207
  //# 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":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,UAAU,EAAuC,MAAM,WAAW,CAAC;AACvF,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,gBAAgB,EAAuB,MAAM,YAAY,CAAC;AAChH,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAQ1C,MAAM,CAAC,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6CxB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,IAAc,EAAE,EAAS;IACjD,+DAA+D;IAC/D,IAAI,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;QACpB,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAClB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,OAAmB,CAAC;IACxB,IAAI,CAAC;QACH,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,UAAU,EAAE,CAAC;YAChC,EAAE,CAAC,GAAG,CAAC,uBAAuB,KAAK,CAAC,OAAO,gDAAgD,CAAC,CAAC;YAC7F,OAAO,CAAC,CAAC;QACX,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,EAAE,CAAC,GAAG,CAAC,GAAG,MAAM,UAAU,EAAE,IAAI,CAAC,CAAC;YAClC,OAAO,CAAC,CAAC;QACX,CAAC;QAED,MAAM,cAAc,GAAmB;YACrC,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,GAAG,CAAC,OAAO,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC;SAChF,CAAC;QAEF,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,OAAO,MAAM,SAAS,CAAC,OAAO,EAAE,cAAc,EAAE,EAAE,CAAC,CAAC;QACtD,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;QAC5D,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,QAAQ,CAAC,KAAK,EAAE,gBAAgB,EAAE,QAAQ,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;QACxG,EAAE,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAE/C,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC/E,OAAO,OAAO,CAAC,aAAa,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,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;AAED;;;;;GAKG;AACH,KAAK,UAAU,cAAc,CAAC,OAAmB,EAAE,cAA8B;IAC/E,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;IAChE,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAE7C,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAW,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC1E,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAClE,4EAA4E;IAC5E,yEAAyE;IACzE,wDAAwD;IACxD,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAChG,CAAC;AAED,6DAA6D;AAC7D,SAAS,SAAS,CAAC,IAAc;IAC/B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,GAAG,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QAC/B,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;IACpD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,MAAM,CAAC,OAAyB,EAAE,MAA4B;IACrE,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC;IAClD,IAAI,MAAM,KAAK,QAAQ;QAAE,OAAO,YAAY,CAAC,OAAO,CAAC,CAAC;IACtD,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,OAAO,CAAC,OAAgB,EAAE,IAAmB;IACpD,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC;IAC5D,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC;IAC5D,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,gBAAgB,CAAC,OAAyB,EAAE,IAAmB;IACtE,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC;IACvC,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC9B,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;KACtE,CAAC,CAAC,CAAC;AACN,CAAC;AAQD,KAAK,UAAU,SAAS,CAAC,OAAmB,EAAE,cAA8B,EAAE,EAAS;IACrF,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;IAE5D,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACtE,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAC5C,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,EAAE;gBACpC,GAAG,EAAE,SAAS,CAAC,IAAI,CAAC;gBACpB,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;gBAC1C,WAAW,EAAE,OAAO,CAAC,WAAW;gBAChC,YAAY,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC;aAChE,CAAC,CAAC;YACH,IAAI,MAAM,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;gBACtC,MAAM,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAC7C,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;QAC9D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,KAAK,OAAO,EAAE,EAAE,CAAC;QAClD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAkB,EAAE,CAAC;IACnC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,SAAS,IAAI,OAAO,EAAE,CAAC;YACzB,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACjC,CAAC;aAAM,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACjE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,EAAE,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,EAAE,CAAC,GAAG,CAAC,uBAAuB,OAAO,IAAI,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,aAAa,CAAC,QAAuB,EAAE,OAAmB;IACjE,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACpF,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC9E,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC5E,MAAM,QAAQ,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,SAAS,EAAE,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAExF,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC,SAAS,CACnB;YACE,OAAO,EAAE,EAAE,KAAK,EAAE,cAAc,CAAC,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE;YACzG,KAAK,EAAE,QAAQ;SAChB,EACD,IAAI,EACJ,CAAC,CACF,CAAC;IACJ,CAAC;IAED,IAAI,YAAY,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,+BAA+B,QAAQ,EAAE,CAAC;IACnD,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC;IACzD,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACzC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACzE,OAAO,GAAG,KAAK,CAAC,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAClE,KAAK,CAAC,IAAI,CACR,EAAE,EACF,GAAG,YAAY,IAAI,KAAK,CAAC,YAAY,EAAE,SAAS,CAAC,WAAW,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,QAAQ,EAAE,CAC/G,CAAC;IACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -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"}