@macrulez/devtoolz 0.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.
Files changed (135) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +262 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +330 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/case-check/core.d.ts +17 -0
  7. package/dist/commands/case-check/core.js +46 -0
  8. package/dist/commands/case-check/core.js.map +1 -0
  9. package/dist/commands/case-check/parse.d.ts +10 -0
  10. package/dist/commands/case-check/parse.js +52 -0
  11. package/dist/commands/case-check/parse.js.map +1 -0
  12. package/dist/commands/case-check/report.d.ts +3 -0
  13. package/dist/commands/case-check/report.js +38 -0
  14. package/dist/commands/case-check/report.js.map +1 -0
  15. package/dist/commands/case-check/resolve-case.d.ts +14 -0
  16. package/dist/commands/case-check/resolve-case.js +163 -0
  17. package/dist/commands/case-check/resolve-case.js.map +1 -0
  18. package/dist/commands/case-check/run.d.ts +31 -0
  19. package/dist/commands/case-check/run.js +72 -0
  20. package/dist/commands/case-check/run.js.map +1 -0
  21. package/dist/commands/case-check/tsconfig-paths.d.ts +19 -0
  22. package/dist/commands/case-check/tsconfig-paths.js +119 -0
  23. package/dist/commands/case-check/tsconfig-paths.js.map +1 -0
  24. package/dist/commands/case-check/vue.d.ts +8 -0
  25. package/dist/commands/case-check/vue.js +26 -0
  26. package/dist/commands/case-check/vue.js.map +1 -0
  27. package/dist/commands/console-strip/core.d.ts +23 -0
  28. package/dist/commands/console-strip/core.js +104 -0
  29. package/dist/commands/console-strip/core.js.map +1 -0
  30. package/dist/commands/console-strip/report.d.ts +3 -0
  31. package/dist/commands/console-strip/report.js +47 -0
  32. package/dist/commands/console-strip/report.js.map +1 -0
  33. package/dist/commands/console-strip/run.d.ts +30 -0
  34. package/dist/commands/console-strip/run.js +55 -0
  35. package/dist/commands/console-strip/run.js.map +1 -0
  36. package/dist/commands/console-strip/vue.d.ts +8 -0
  37. package/dist/commands/console-strip/vue.js +28 -0
  38. package/dist/commands/console-strip/vue.js.map +1 -0
  39. package/dist/commands/dead-exports/core.d.ts +19 -0
  40. package/dist/commands/dead-exports/core.js +136 -0
  41. package/dist/commands/dead-exports/core.js.map +1 -0
  42. package/dist/commands/dead-exports/entry.d.ts +2 -0
  43. package/dist/commands/dead-exports/entry.js +93 -0
  44. package/dist/commands/dead-exports/entry.js.map +1 -0
  45. package/dist/commands/dead-exports/parse.d.ts +30 -0
  46. package/dist/commands/dead-exports/parse.js +174 -0
  47. package/dist/commands/dead-exports/parse.js.map +1 -0
  48. package/dist/commands/dead-exports/report.d.ts +3 -0
  49. package/dist/commands/dead-exports/report.js +27 -0
  50. package/dist/commands/dead-exports/report.js.map +1 -0
  51. package/dist/commands/dead-exports/resolve.d.ts +10 -0
  52. package/dist/commands/dead-exports/resolve.js +58 -0
  53. package/dist/commands/dead-exports/resolve.js.map +1 -0
  54. package/dist/commands/dead-exports/run.d.ts +21 -0
  55. package/dist/commands/dead-exports/run.js +51 -0
  56. package/dist/commands/dead-exports/run.js.map +1 -0
  57. package/dist/commands/dead-exports/workspace.d.ts +14 -0
  58. package/dist/commands/dead-exports/workspace.js +99 -0
  59. package/dist/commands/dead-exports/workspace.js.map +1 -0
  60. package/dist/commands/exports-doctor/core.d.ts +13 -0
  61. package/dist/commands/exports-doctor/core.js +85 -0
  62. package/dist/commands/exports-doctor/core.js.map +1 -0
  63. package/dist/commands/exports-doctor/parse.d.ts +20 -0
  64. package/dist/commands/exports-doctor/parse.js +80 -0
  65. package/dist/commands/exports-doctor/parse.js.map +1 -0
  66. package/dist/commands/exports-doctor/report.d.ts +3 -0
  67. package/dist/commands/exports-doctor/report.js +36 -0
  68. package/dist/commands/exports-doctor/report.js.map +1 -0
  69. package/dist/commands/exports-doctor/resolve-path.d.ts +10 -0
  70. package/dist/commands/exports-doctor/resolve-path.js +46 -0
  71. package/dist/commands/exports-doctor/resolve-path.js.map +1 -0
  72. package/dist/commands/exports-doctor/run.d.ts +13 -0
  73. package/dist/commands/exports-doctor/run.js +25 -0
  74. package/dist/commands/exports-doctor/run.js.map +1 -0
  75. package/dist/commands/readme-check/core.d.ts +22 -0
  76. package/dist/commands/readme-check/core.js +92 -0
  77. package/dist/commands/readme-check/core.js.map +1 -0
  78. package/dist/commands/readme-check/extract.d.ts +9 -0
  79. package/dist/commands/readme-check/extract.js +48 -0
  80. package/dist/commands/readme-check/extract.js.map +1 -0
  81. package/dist/commands/readme-check/lang.d.ts +8 -0
  82. package/dist/commands/readme-check/lang.js +21 -0
  83. package/dist/commands/readme-check/lang.js.map +1 -0
  84. package/dist/commands/readme-check/report.d.ts +3 -0
  85. package/dist/commands/readme-check/report.js +31 -0
  86. package/dist/commands/readme-check/report.js.map +1 -0
  87. package/dist/commands/readme-check/run.d.ts +19 -0
  88. package/dist/commands/readme-check/run.js +34 -0
  89. package/dist/commands/readme-check/run.js.map +1 -0
  90. package/dist/commands/readme-check/tsconfig.d.ts +9 -0
  91. package/dist/commands/readme-check/tsconfig.js +26 -0
  92. package/dist/commands/readme-check/tsconfig.js.map +1 -0
  93. package/dist/commands/readme-check/typecheck.d.ts +31 -0
  94. package/dist/commands/readme-check/typecheck.js +82 -0
  95. package/dist/commands/readme-check/typecheck.js.map +1 -0
  96. package/dist/commands/strip-comments/apply-deletions.d.ts +17 -0
  97. package/dist/commands/strip-comments/apply-deletions.js +74 -0
  98. package/dist/commands/strip-comments/apply-deletions.js.map +1 -0
  99. package/dist/commands/strip-comments/core.d.ts +15 -0
  100. package/dist/commands/strip-comments/core.js +111 -0
  101. package/dist/commands/strip-comments/core.js.map +1 -0
  102. package/dist/commands/strip-comments/report.d.ts +6 -0
  103. package/dist/commands/strip-comments/report.js +30 -0
  104. package/dist/commands/strip-comments/report.js.map +1 -0
  105. package/dist/commands/strip-comments/run.d.ts +28 -0
  106. package/dist/commands/strip-comments/run.js +50 -0
  107. package/dist/commands/strip-comments/run.js.map +1 -0
  108. package/dist/commands/strip-comments/vue.d.ts +6 -0
  109. package/dist/commands/strip-comments/vue.js +65 -0
  110. package/dist/commands/strip-comments/vue.js.map +1 -0
  111. package/dist/format/colors.d.ts +8 -0
  112. package/dist/format/colors.js +14 -0
  113. package/dist/format/colors.js.map +1 -0
  114. package/dist/format/diff-render.d.ts +2 -0
  115. package/dist/format/diff-render.js +35 -0
  116. package/dist/format/diff-render.js.map +1 -0
  117. package/dist/format/file-list.d.ts +14 -0
  118. package/dist/format/file-list.js +26 -0
  119. package/dist/format/file-list.js.map +1 -0
  120. package/dist/format/findings-list.d.ts +14 -0
  121. package/dist/format/findings-list.js +23 -0
  122. package/dist/format/findings-list.js.map +1 -0
  123. package/dist/format/vibes.d.ts +10 -0
  124. package/dist/format/vibes.js +67 -0
  125. package/dist/format/vibes.js.map +1 -0
  126. package/dist/index.d.ts +47 -0
  127. package/dist/index.js +29 -0
  128. package/dist/index.js.map +1 -0
  129. package/dist/utils/diff.d.ts +1 -0
  130. package/dist/utils/diff.js +13 -0
  131. package/dist/utils/diff.js.map +1 -0
  132. package/dist/utils/walk.d.ts +19 -0
  133. package/dist/utils/walk.js +96 -0
  134. package/dist/utils/walk.js.map +1 -0
  135. package/package.json +57 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tsconfig.js","sourceRoot":"","sources":["../../../src/commands/readme-check/tsconfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAA;AAC3B,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAS5C,MAAM,UAAU,mBAAmB,CACjC,UAAkB,EAClB,gBAAyB;IAEzB,MAAM,UAAU,GAAG,gBAAgB;QACjC,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,gBAAgB,CAAC;QACvC,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,UAAU,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,EAAE,eAAe,CAAC,CAAA;IAErE,IAAI,CAAC,UAAU,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAClD,OAAO;YACL,KAAK,EAAE,gCAAgC,UAAU,oDAAoD;SACtG,CAAA;IACH,CAAC;IAED,MAAM,IAAI,GAAG,EAAE,CAAC,cAAc,CAAC,UAAU,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAC3D,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,4BAA4B,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,CAAA;IACjF,CAAC;IAED,MAAM,MAAM,GAAG,EAAE,CAAC,0BAA0B,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAA;IACtF,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO;YACL,KAAK,EAAE,MAAM,CAAC,MAAM;iBACjB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,4BAA4B,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;iBAChE,IAAI,CAAC,IAAI,CAAC;SACd,CAAA;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,CAAA;AAChD,CAAC"}
@@ -0,0 +1,31 @@
1
+ import ts from 'typescript';
2
+ export interface BlockDiagnostic {
3
+ /** 0-based line WITHIN the block's own code, matches ts.LineAndCharacter */
4
+ line: number;
5
+ character: number;
6
+ message: string;
7
+ category: 'error' | 'warning';
8
+ /** TS diagnostic code, e.g. 2304 for "Cannot find name" — lets a caller filter by known-noisy codes */
9
+ code: number;
10
+ }
11
+ /**
12
+ * Typechecks one code block in complete isolation against the target
13
+ * package's real types — no code is ever executed, only compiled. The
14
+ * block is presented to the compiler as a virtual file sitting AT THE
15
+ * PACKAGE ROOT (same directory as package.json), which is what lets both
16
+ * relative imports (`./dist/foo`) and self-referencing package-name
17
+ * imports (`import { x } from '@scope/this-same-package'`) resolve
18
+ * exactly as they would for a real consumer — Node/TS's self-reference
19
+ * resolution walks up from the importing FILE's real directory looking
20
+ * for the nearest package.json, and that lookup hits the real one on
21
+ * disk since only `getSourceFile`/`fileExists`/`readFile` are overridden
22
+ * for the single virtual path; everything else delegates to the real
23
+ * filesystem via `ts.createCompilerHost`.
24
+ *
25
+ * Returns null when `lang` isn't a checkable language (block is skipped
26
+ * upstream), otherwise the list of diagnostics raised for THIS file only
27
+ * — diagnostics whose `file` is some OTHER file pulled into the module
28
+ * graph (e.g. a real type error inside the package's own .d.ts) are not
29
+ * this block's fault and are filtered out.
30
+ */
31
+ export declare function typecheckBlock(code: string, lang: string, packageDir: string, baseOptions: ts.CompilerOptions): BlockDiagnostic[] | null;
@@ -0,0 +1,82 @@
1
+ import ts from 'typescript';
2
+ import { join } from 'node:path';
3
+ import { resolveLangInfo } from './lang.js';
4
+ /**
5
+ * Typechecks one code block in complete isolation against the target
6
+ * package's real types — no code is ever executed, only compiled. The
7
+ * block is presented to the compiler as a virtual file sitting AT THE
8
+ * PACKAGE ROOT (same directory as package.json), which is what lets both
9
+ * relative imports (`./dist/foo`) and self-referencing package-name
10
+ * imports (`import { x } from '@scope/this-same-package'`) resolve
11
+ * exactly as they would for a real consumer — Node/TS's self-reference
12
+ * resolution walks up from the importing FILE's real directory looking
13
+ * for the nearest package.json, and that lookup hits the real one on
14
+ * disk since only `getSourceFile`/`fileExists`/`readFile` are overridden
15
+ * for the single virtual path; everything else delegates to the real
16
+ * filesystem via `ts.createCompilerHost`.
17
+ *
18
+ * Returns null when `lang` isn't a checkable language (block is skipped
19
+ * upstream), otherwise the list of diagnostics raised for THIS file only
20
+ * — diagnostics whose `file` is some OTHER file pulled into the module
21
+ * graph (e.g. a real type error inside the package's own .d.ts) are not
22
+ * this block's fault and are filtered out.
23
+ */
24
+ export function typecheckBlock(code, lang, packageDir, baseOptions) {
25
+ const langInfo = resolveLangInfo(lang);
26
+ if (!langInfo)
27
+ return null;
28
+ // TypeScript normalizes every file path it works with to forward
29
+ // slashes internally, even on Windows — comparing against a
30
+ // `path.join`-built name (backslashes on win32) would never match what
31
+ // the compiler actually passes back into `getSourceFile`/`fileExists`,
32
+ // silently turning every block into a false "file not found", 0
33
+ // diagnostics ever produced. Caught by an isolated repro against a real
34
+ // package before writing tests, not by the tests themselves.
35
+ const virtualFileName = join(packageDir, `__devtoolz_readme_check__${langInfo.extension}`).replace(/\\/g, '/');
36
+ const options = {
37
+ ...baseOptions,
38
+ noEmit: true,
39
+ skipLibCheck: true,
40
+ ...(langInfo.needsAllowJs ? { allowJs: true, checkJs: true } : {}),
41
+ };
42
+ const baseHost = ts.createCompilerHost(options);
43
+ const virtualSourceFile = ts.createSourceFile(virtualFileName, code, ts.ScriptTarget.Latest, true, langInfo.scriptKind);
44
+ const host = {
45
+ ...baseHost,
46
+ getSourceFile(fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile) {
47
+ if (fileName === virtualFileName)
48
+ return virtualSourceFile;
49
+ return baseHost.getSourceFile(fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile);
50
+ },
51
+ fileExists(fileName) {
52
+ if (fileName === virtualFileName)
53
+ return true;
54
+ return baseHost.fileExists(fileName);
55
+ },
56
+ readFile(fileName) {
57
+ if (fileName === virtualFileName)
58
+ return code;
59
+ return baseHost.readFile(fileName);
60
+ },
61
+ writeFile() {
62
+ // noEmit is always forced above — never actually called, kept as a safe no-op
63
+ },
64
+ };
65
+ const program = ts.createProgram({ rootNames: [virtualFileName], options, host });
66
+ const diagnostics = ts
67
+ .getPreEmitDiagnostics(program)
68
+ .filter((d) => d.file?.fileName === virtualFileName);
69
+ return diagnostics.map((d) => {
70
+ const pos = d.file && d.start !== undefined
71
+ ? d.file.getLineAndCharacterOfPosition(d.start)
72
+ : { line: 0, character: 0 };
73
+ return {
74
+ line: pos.line,
75
+ character: pos.character,
76
+ message: ts.flattenDiagnosticMessageText(d.messageText, '\n'),
77
+ category: d.category === ts.DiagnosticCategory.Error ? 'error' : 'warning',
78
+ code: d.code,
79
+ };
80
+ });
81
+ }
82
+ //# sourceMappingURL=typecheck.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typecheck.js","sourceRoot":"","sources":["../../../src/commands/readme-check/typecheck.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ export type Range = [start: number, end: number];
2
+ export declare function lineBoundsAllWhitespace(text: string, start: number, end: number): {
3
+ lineStart: number;
4
+ lineEnd: number;
5
+ beforeIsWs: boolean;
6
+ afterIsWs: boolean;
7
+ };
8
+ /**
9
+ * Deletes `ranges` from `text`. A range that has nothing but whitespace
10
+ * before and after it on its own line is treated as a whole-line
11
+ * comment — its entire line, including the trailing newline, is removed,
12
+ * so no blank line is left behind. Otherwise, only the range itself plus
13
+ * the run of spaces/tabs immediately before it is removed, keeping real
14
+ * code that shares its line intact.
15
+ */
16
+ export declare function applyDeletions(text: string, ranges: Range[]): string;
17
+ export declare function collapseBlankLineRuns(text: string): string;
@@ -0,0 +1,74 @@
1
+ // Shared "delete these ranges, but a whole-line comment takes its newline
2
+ // with it" logic — used by core.ts (real TS comment tokens) and vue.ts
3
+ // (regex-matched `<!-- -->` in a <template> block). Checking whole-line-
4
+ // ness against the SURROUNDING TEXT (not just the matched substring in
5
+ // isolation) matters: a substring-only check misclassifies a trailing
6
+ // inline comment as "whole line" whenever the comment itself, in
7
+ // isolation, happens to look like one (leading/trailing whitespace) even
8
+ // though real content precedes it on the same source line — a real bug
9
+ // found via testing in the original draft this package is based on.
10
+ export function lineBoundsAllWhitespace(text, start, end) {
11
+ let lineStart = start;
12
+ while (lineStart > 0 && text[lineStart - 1] !== '\n')
13
+ lineStart--;
14
+ const beforeIsWs = /^[ \t]*$/.test(text.slice(lineStart, start));
15
+ let lineEnd = end;
16
+ while (lineEnd < text.length && text[lineEnd] !== '\n')
17
+ lineEnd++;
18
+ const afterIsWs = /^[ \t\r]*$/.test(text.slice(end, lineEnd));
19
+ return { lineStart, lineEnd, beforeIsWs, afterIsWs };
20
+ }
21
+ /**
22
+ * Deletes `ranges` from `text`. A range that has nothing but whitespace
23
+ * before and after it on its own line is treated as a whole-line
24
+ * comment — its entire line, including the trailing newline, is removed,
25
+ * so no blank line is left behind. Otherwise, only the range itself plus
26
+ * the run of spaces/tabs immediately before it is removed, keeping real
27
+ * code that shares its line intact.
28
+ */
29
+ export function applyDeletions(text, ranges) {
30
+ if (ranges.length === 0)
31
+ return text;
32
+ const deletions = [];
33
+ for (const [start, end] of ranges) {
34
+ const { lineStart, lineEnd, beforeIsWs, afterIsWs } = lineBoundsAllWhitespace(text, start, end);
35
+ if (beforeIsWs && afterIsWs) {
36
+ const delEnd = lineEnd < text.length && text[lineEnd] === '\n' ? lineEnd + 1 : lineEnd;
37
+ deletions.push([lineStart, delEnd]);
38
+ }
39
+ else {
40
+ let s = start;
41
+ while (s > 0 && (text[s - 1] === ' ' || text[s - 1] === '\t'))
42
+ s--;
43
+ deletions.push([s, end]);
44
+ }
45
+ }
46
+ deletions.sort((a, b) => a[0] - b[0]);
47
+ const merged = [];
48
+ for (const d of deletions) {
49
+ const last = merged[merged.length - 1];
50
+ if (last && d[0] <= last[1]) {
51
+ last[1] = Math.max(last[1], d[1]);
52
+ }
53
+ else {
54
+ merged.push(d);
55
+ }
56
+ }
57
+ let out = '';
58
+ let cursor = 0;
59
+ for (const [s, e] of merged) {
60
+ out += text.slice(cursor, s);
61
+ cursor = e;
62
+ }
63
+ out += text.slice(cursor);
64
+ return out;
65
+ }
66
+ // Collapses 3+ consecutive blank lines to one — `\r?` around each `\n` so
67
+ // a stray `\r` (CRLF files) doesn't survive between the newlines and
68
+ // defeat the collapse, and the replacement matches whichever line ending
69
+ // the matched stretch itself used, so a CRLF file doesn't end up with
70
+ // LF-only gaps mixed in.
71
+ export function collapseBlankLineRuns(text) {
72
+ return text.replace(/(?:\r?\n){3,}/g, (match) => (match.includes('\r') ? '\r\n\r\n' : '\n\n'));
73
+ }
74
+ //# sourceMappingURL=apply-deletions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply-deletions.js","sourceRoot":"","sources":["../../../src/commands/strip-comments/apply-deletions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import ts from 'typescript';
2
+ export interface StripCommentsOptions {
3
+ /** ts.ScriptKind.TS (default) or ts.ScriptKind.JS — pass JS for plain .js/.cjs/.mjs files */
4
+ scriptKind?: ts.ScriptKind;
5
+ /** don't delete a /** *\/ comment immediately above an exported declaration. default false */
6
+ keepJsdoc?: boolean;
7
+ }
8
+ export interface StripCommentsResult {
9
+ text: string;
10
+ /** true if anything was actually deleted — lets callers skip a no-op write */
11
+ changed: boolean;
12
+ /** how many individual comments were removed (before adjacent ones get merged into one deletion) */
13
+ count: number;
14
+ }
15
+ export declare function stripComments(text: string, options?: StripCommentsOptions): StripCommentsResult;
@@ -0,0 +1,111 @@
1
+ // Core comment-stripping logic for a single TS/JS source string. Ported
2
+ // from the working draft at C:\work\Наработки\strip-comments — same
3
+ // approach, same guarantees, now with `keepJsdoc` added on top (the draft
4
+ // didn't have it — see features.md's strip-comments edge cases).
5
+ //
6
+ // Why not a naive regex or a plain `ts.createScanner` loop: without full
7
+ // parser context, a raw scanner can't tell a regex literal's `/` from a
8
+ // comment-start `/` (e.g. `/^\/([^/]+)\//`), and can't tell `//` inside a
9
+ // template literal (e.g. `` `${url.protocol}//${url.hostname}` ``) from a
10
+ // real line comment either — both cases silently corrupt the file. This
11
+ // fully parses the source first to find every string/template/regex/JSX
12
+ // text span, masks their contents (same length, so positions don't
13
+ // shift), then scans the masked copy for comments and deletes those exact
14
+ // byte ranges from the ORIGINAL text. No re-printing/reformatting —
15
+ // everything outside a comment is byte-identical to the input.
16
+ import ts from 'typescript';
17
+ import { applyDeletions, collapseBlankLineRuns } from './apply-deletions.js';
18
+ const LITERAL_KINDS = new Set([
19
+ ts.SyntaxKind.StringLiteral,
20
+ ts.SyntaxKind.NoSubstitutionTemplateLiteral,
21
+ ts.SyntaxKind.TemplateHead,
22
+ ts.SyntaxKind.TemplateMiddle,
23
+ ts.SyntaxKind.TemplateTail,
24
+ ts.SyntaxKind.RegularExpressionLiteral,
25
+ ts.SyntaxKind.JsxText,
26
+ ]);
27
+ function findLiteralRanges(sf) {
28
+ const ranges = [];
29
+ function visit(node) {
30
+ if (LITERAL_KINDS.has(node.kind)) {
31
+ ranges.push([node.getStart(sf), node.getEnd()]);
32
+ }
33
+ ts.forEachChild(node, visit);
34
+ }
35
+ visit(sf);
36
+ return ranges;
37
+ }
38
+ function maskLiterals(text, ranges) {
39
+ // `ts.SourceFile` positions are UTF-16 CODE UNIT offsets (same as
40
+ // `string.length`/`charAt`) — `[...text]`/`Array.from(text)` iterate by
41
+ // CODE POINT instead, collapsing any surrogate pair (an emoji, or any
42
+ // character outside the BMP) into a single array element. The moment a
43
+ // literal masked earlier in the file contains one, every position after
44
+ // it drifts by one (or more) index, and later deletions land on the
45
+ // wrong bytes entirely. `split('')` is UTF-16-code-unit based — it
46
+ // splits a surrogate pair into its two halves instead of merging them,
47
+ // which is exactly what keeps this array's indices aligned with the
48
+ // parser's.
49
+ const chars = text.split('');
50
+ for (const [s, e] of ranges) {
51
+ for (let i = s; i < e; i++) {
52
+ if (chars[i] !== '\n')
53
+ chars[i] = 'x';
54
+ }
55
+ }
56
+ return chars.join('');
57
+ }
58
+ function findCommentRanges(maskedText) {
59
+ const ranges = [];
60
+ const scanner = ts.createScanner(ts.ScriptTarget.Latest, false, ts.LanguageVariant.Standard, maskedText);
61
+ let tok = scanner.scan();
62
+ while (tok !== ts.SyntaxKind.EndOfFileToken) {
63
+ if (tok === ts.SyntaxKind.SingleLineCommentTrivia ||
64
+ tok === ts.SyntaxKind.MultiLineCommentTrivia) {
65
+ ranges.push([scanner.getTokenStart(), scanner.getTokenEnd()]);
66
+ }
67
+ tok = scanner.scan();
68
+ }
69
+ return ranges;
70
+ }
71
+ // Every `/** ... */` immediately leading an `export`-modified declaration
72
+ // — these are what `keepJsdoc` protects from deletion. Only JSDoc-style
73
+ // (`/**`, not a plain `/*`) counts, matching the convention IDEs actually
74
+ // read tooltips from.
75
+ function findExportedJsdocRanges(sf, text) {
76
+ const ranges = [];
77
+ function visit(node) {
78
+ const hasExportModifier = ts.canHaveModifiers(node) &&
79
+ ts.getModifiers(node)?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword);
80
+ if (hasExportModifier) {
81
+ const leading = ts.getLeadingCommentRanges(text, node.getFullStart()) ?? [];
82
+ for (const c of leading) {
83
+ if (c.kind === ts.SyntaxKind.MultiLineCommentTrivia &&
84
+ text.slice(c.pos, c.pos + 3) === '/**') {
85
+ ranges.push([c.pos, c.end]);
86
+ }
87
+ }
88
+ }
89
+ ts.forEachChild(node, visit);
90
+ }
91
+ visit(sf);
92
+ return ranges;
93
+ }
94
+ export function stripComments(text, options = {}) {
95
+ const scriptKind = options.scriptKind ?? ts.ScriptKind.TS;
96
+ const sf = ts.createSourceFile('f.ts', text, ts.ScriptTarget.Latest, true, scriptKind);
97
+ const literalRanges = findLiteralRanges(sf);
98
+ const masked = maskLiterals(text, literalRanges);
99
+ let comments = findCommentRanges(masked);
100
+ if (comments.length === 0)
101
+ return { text, changed: false, count: 0 };
102
+ if (options.keepJsdoc) {
103
+ const protectedRanges = new Set(findExportedJsdocRanges(sf, text).map(([s, e]) => `${s}:${e}`));
104
+ comments = comments.filter(([s, e]) => !protectedRanges.has(`${s}:${e}`));
105
+ if (comments.length === 0)
106
+ return { text, changed: false, count: 0 };
107
+ }
108
+ const out = collapseBlankLineRuns(applyDeletions(text, comments));
109
+ return { text: out, changed: true, count: comments.length };
110
+ }
111
+ //# sourceMappingURL=core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../../../src/commands/strip-comments/core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { type VibesOptions } from '../../format/vibes.js';
2
+ import type { StripCommentsReport } from './run.js';
3
+ export interface RenderOptions extends VibesOptions {
4
+ dryRun?: boolean;
5
+ }
6
+ export declare function renderStripCommentsReport(report: StripCommentsReport, options?: RenderOptions): string;
@@ -0,0 +1,30 @@
1
+ import { banner, cleanCelebration } from '../../format/vibes.js';
2
+ import { formatFileCountRows } from '../../format/file-list.js';
3
+ import { renderDiffForHumans } from '../../format/diff-render.js';
4
+ export function renderStripCommentsReport(report, options = {}) {
5
+ if (options.quiet && report.changes.length === 0)
6
+ return '';
7
+ const lines = [];
8
+ if (!options.quiet && !options.plain)
9
+ lines.push(banner(), '');
10
+ lines.push(`Scanned ${report.filesScanned} file${report.filesScanned === 1 ? '' : 's'}.`, '');
11
+ if (report.changes.length === 0) {
12
+ lines.push(cleanCelebration(options));
13
+ return lines.join('\n');
14
+ }
15
+ const verb = report.applied ? 'Stripped comments in' : 'Would strip comments in';
16
+ lines.push(`${verb} ${report.changes.length} file(s):`);
17
+ lines.push(...formatFileCountRows(report.changes, (n) => `comment${n === 1 ? '' : 's'}`, options));
18
+ if (!report.applied) {
19
+ const diffHint = report.changes.some((c) => c.diff) ? '' : ', or --diff to see exactly what';
20
+ lines.push('', `(nothing written — pass -y to apply${diffHint}, or --dry-run to keep previewing)`);
21
+ }
22
+ for (const change of report.changes) {
23
+ if (!change.diff)
24
+ continue;
25
+ const unit = `comment${change.count === 1 ? '' : 's'}`;
26
+ lines.push('', renderDiffForHumans(change.file, change.count, unit, change.diff, options));
27
+ }
28
+ return lines.join('\n');
29
+ }
30
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../../src/commands/strip-comments/report.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAqB,MAAM,uBAAuB,CAAA;AACnF,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAA;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAOjE,MAAM,UAAU,yBAAyB,CACvC,MAA2B,EAC3B,UAAyB,EAAE;IAE3B,IAAI,OAAO,CAAC,KAAK,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAA;IAE3D,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,KAAK;QAAE,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,CAAC,CAAA;IAE9D,KAAK,CAAC,IAAI,CAAC,WAAW,MAAM,CAAC,YAAY,QAAQ,MAAM,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,EAAE,CAAC,CAAA;IAE7F,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAA;QACrC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACzB,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,yBAAyB,CAAA;IAChF,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,WAAW,CAAC,CAAA;IACvD,KAAK,CAAC,IAAI,CAAC,GAAG,mBAAmB,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC,CAAA;IAElG,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,iCAAiC,CAAA;QAC5F,KAAK,CAAC,IAAI,CACR,EAAE,EACF,sCAAsC,QAAQ,oCAAoC,CACnF,CAAA;IACH,CAAC;IAED,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACpC,IAAI,CAAC,MAAM,CAAC,IAAI;YAAE,SAAQ;QAC1B,MAAM,IAAI,GAAG,UAAU,MAAM,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAA;QACtD,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,mBAAmB,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAA;IAC5F,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC"}
@@ -0,0 +1,28 @@
1
+ export interface StripCommentsRunOptions {
2
+ paths: string[];
3
+ cwd: string;
4
+ extensions?: string[];
5
+ ignoreGlobs?: string[];
6
+ respectGitignore?: boolean;
7
+ keepJsdoc?: boolean;
8
+ /** show what would change, write nothing */
9
+ dryRun?: boolean;
10
+ /** actually write changes to disk — without this OR dryRun, behaves as a preview (nothing written) */
11
+ yes?: boolean;
12
+ /** include a unified diff per changed file in the report */
13
+ diff?: boolean;
14
+ }
15
+ export interface StripCommentsFileChange {
16
+ file: string;
17
+ /** how many individual comments were removed from this file */
18
+ count: number;
19
+ diff?: string;
20
+ }
21
+ export interface StripCommentsReport {
22
+ filesScanned: number;
23
+ changes: StripCommentsFileChange[];
24
+ /** true if changes were actually written to disk */
25
+ applied: boolean;
26
+ exitCode: number;
27
+ }
28
+ export declare function runStripComments(options: StripCommentsRunOptions): StripCommentsReport;
@@ -0,0 +1,50 @@
1
+ import { readFileSync, writeFileSync } from 'node:fs';
2
+ import { relative } from 'node:path';
3
+ import ts from 'typescript';
4
+ import { walk } from '../../utils/walk.js';
5
+ import { unifiedDiff } from '../../utils/diff.js';
6
+ import { stripComments } from './core.js';
7
+ import { stripVueComments } from './vue.js';
8
+ const DEFAULT_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.cjs', '.mjs', '.vue'];
9
+ function scriptKindFor(file) {
10
+ return file.endsWith('.ts') || file.endsWith('.tsx') ? ts.ScriptKind.TS : ts.ScriptKind.JS;
11
+ }
12
+ export function runStripComments(options) {
13
+ const extensions = options.extensions ?? DEFAULT_EXTENSIONS;
14
+ const files = walk(options.paths, {
15
+ cwd: options.cwd,
16
+ extensions,
17
+ ...(options.ignoreGlobs ? { ignoreGlobs: options.ignoreGlobs } : {}),
18
+ ...(options.respectGitignore !== undefined
19
+ ? { respectGitignore: options.respectGitignore }
20
+ : {}),
21
+ });
22
+ const willApply = options.yes === true && options.dryRun !== true;
23
+ const changes = [];
24
+ for (const file of files) {
25
+ const before = readFileSync(file, 'utf8');
26
+ const result = file.endsWith('.vue')
27
+ ? stripVueComments(before, { keepJsdoc: options.keepJsdoc ?? false })
28
+ : stripComments(before, {
29
+ scriptKind: scriptKindFor(file),
30
+ keepJsdoc: options.keepJsdoc ?? false,
31
+ });
32
+ if (!result.changed)
33
+ continue;
34
+ const relFile = relative(options.cwd, file).split('\\').join('/');
35
+ const change = { file: relFile, count: result.count };
36
+ if (options.diff)
37
+ change.diff = unifiedDiff(relFile, before, result.text);
38
+ changes.push(change);
39
+ if (willApply)
40
+ writeFileSync(file, result.text);
41
+ }
42
+ const exitCode = !willApply && changes.length > 0 ? 1 : 0;
43
+ return {
44
+ filesScanned: files.length,
45
+ changes,
46
+ applied: willApply,
47
+ exitCode,
48
+ };
49
+ }
50
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/commands/strip-comments/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { type StripCommentsOptions } from './core.js';
2
+ export declare function stripVueComments(text: string, options?: StripCommentsOptions): {
3
+ text: string;
4
+ changed: boolean;
5
+ count: number;
6
+ };
@@ -0,0 +1,65 @@
1
+ // `.vue` handling: the `<script>` block goes through the real TS-parser
2
+ // path in core.ts (safe against strings/templates/regex inside it); the
3
+ // `<template>` block's `<!-- -->` comments go through the same
4
+ // line-aware deletion helper as core.ts, just fed regex-matched comment
5
+ // ranges instead of TS scanner tokens — there's no full Vue SFC template
6
+ // parser here, so a `<!-- -->`-looking sequence INSIDE a bound attribute
7
+ // string (e.g. `:title="'<!-- x -->'"`) would still be misread as a real
8
+ // comment. Known limitation, documented in features.md — not something
9
+ // fixable without a real template parser, which is out of scope here.
10
+ import ts from 'typescript';
11
+ import { stripComments } from './core.js';
12
+ import { applyDeletions, collapseBlankLineRuns } from './apply-deletions.js';
13
+ const SCRIPT_RE = /(<script[^>]*>)([\s\S]*?)(<\/script>)/;
14
+ const TEMPLATE_RE = /(<template[^>]*>)([\s\S]*?)(<\/template>)/;
15
+ const TEMPLATE_COMMENT_RE = /<!--[\s\S]*?-->/g;
16
+ function stripTemplateComments(body) {
17
+ const ranges = [];
18
+ for (const match of body.matchAll(TEMPLATE_COMMENT_RE)) {
19
+ const start = match.index;
20
+ ranges.push([start, start + match[0].length]);
21
+ }
22
+ if (ranges.length === 0)
23
+ return { text: body, changed: false, count: 0 };
24
+ return {
25
+ text: collapseBlankLineRuns(applyDeletions(body, ranges)),
26
+ changed: true,
27
+ count: ranges.length,
28
+ };
29
+ }
30
+ export function stripVueComments(text, options = {}) {
31
+ let changed = false;
32
+ let count = 0;
33
+ const scriptMatch = text.match(SCRIPT_RE);
34
+ if (scriptMatch) {
35
+ const [whole, open, body, close] = scriptMatch;
36
+ const result = stripComments(body, { ...options, scriptKind: ts.ScriptKind.TS });
37
+ if (result.changed) {
38
+ changed = true;
39
+ count += result.count;
40
+ text =
41
+ text.slice(0, scriptMatch.index) +
42
+ open +
43
+ result.text +
44
+ close +
45
+ text.slice(scriptMatch.index + whole.length);
46
+ }
47
+ }
48
+ const templateMatch = text.match(TEMPLATE_RE);
49
+ if (templateMatch) {
50
+ const [whole, open, body, close] = templateMatch;
51
+ const result = stripTemplateComments(body);
52
+ if (result.changed) {
53
+ changed = true;
54
+ count += result.count;
55
+ text =
56
+ text.slice(0, templateMatch.index) +
57
+ open +
58
+ result.text +
59
+ close +
60
+ text.slice(templateMatch.index + whole.length);
61
+ }
62
+ }
63
+ return { text, changed, count };
64
+ }
65
+ //# sourceMappingURL=vue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vue.js","sourceRoot":"","sources":["../../../src/commands/strip-comments/vue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export declare const RESET = "\u001B[0m";
2
+ export declare const BOLD = "\u001B[1m";
3
+ export declare const DIM = "\u001B[2m";
4
+ export declare const RED = "\u001B[31m";
5
+ export declare const GREEN = "\u001B[32m";
6
+ export declare const CYAN = "\u001B[36m";
7
+ export declare const WHITE = "\u001B[97m";
8
+ export declare function colorize(color: string, text: string): string;
@@ -0,0 +1,14 @@
1
+ // Minimal ANSI palette — no chalk/picocolors dependency for a handful of
2
+ // escape codes. Every caller gates these behind `isFancyOutputEnabled()`
3
+ // from vibes.ts, never applied unconditionally.
4
+ export const RESET = '\x1b[0m';
5
+ export const BOLD = '\x1b[1m';
6
+ export const DIM = '\x1b[2m';
7
+ export const RED = '\x1b[31m';
8
+ export const GREEN = '\x1b[32m';
9
+ export const CYAN = '\x1b[36m';
10
+ export const WHITE = '\x1b[97m';
11
+ export function colorize(color, text) {
12
+ return `${color}${text}${RESET}`;
13
+ }
14
+ //# sourceMappingURL=colors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colors.js","sourceRoot":"","sources":["../../src/format/colors.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,yEAAyE;AACzE,gDAAgD;AAChD,MAAM,CAAC,MAAM,KAAK,GAAG,SAAS,CAAA;AAC9B,MAAM,CAAC,MAAM,IAAI,GAAG,SAAS,CAAA;AAC7B,MAAM,CAAC,MAAM,GAAG,GAAG,SAAS,CAAA;AAC5B,MAAM,CAAC,MAAM,GAAG,GAAG,UAAU,CAAA;AAC7B,MAAM,CAAC,MAAM,KAAK,GAAG,UAAU,CAAA;AAC/B,MAAM,CAAC,MAAM,IAAI,GAAG,UAAU,CAAA;AAC9B,MAAM,CAAC,MAAM,KAAK,GAAG,UAAU,CAAA;AAE/B,MAAM,UAAU,QAAQ,CAAC,KAAa,EAAE,IAAY;IAClD,OAAO,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,EAAE,CAAA;AAClC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { type VibesOptions } from './vibes.js';
2
+ export declare function renderDiffForHumans(file: string, count: number, unit: string, patch: string, options?: VibesOptions): string;