@node-cli/comments 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.
- package/LICENSE +21 -0
- package/README.md +47 -0
- package/dist/__tests__/glob.test.js +135 -0
- package/dist/__tests__/glob.test.js.map +1 -0
- package/dist/__tests__/lib.test.js +247 -0
- package/dist/__tests__/lib.test.js.map +1 -0
- package/dist/comments.d.ts +2 -0
- package/dist/comments.js +86 -0
- package/dist/comments.js.map +1 -0
- package/dist/defaults.d.ts +5 -0
- package/dist/defaults.js +7 -0
- package/dist/defaults.js.map +1 -0
- package/dist/glob.d.ts +5 -0
- package/dist/glob.js +280 -0
- package/dist/glob.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/lib.d.ts +14 -0
- package/dist/lib.js +444 -0
- package/dist/lib.js.map +1 -0
- package/dist/parse.d.ts +19 -0
- package/dist/parse.js +87 -0
- package/dist/parse.js.map +1 -0
- package/package.json +41 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Arno Versini
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# @node-cli/comments
|
|
2
|
+
|
|
3
|
+
CLI tool to reflow, normalize, and optionally merge JavaScript / TypeScript comment blocks (JSDoc and `//` single-line comments).
|
|
4
|
+
|
|
5
|
+
## Features (Planned)
|
|
6
|
+
|
|
7
|
+
- Reflow JSDoc blocks to a max line width
|
|
8
|
+
- Optional wrapping of single-line `//` comments
|
|
9
|
+
- Optional merging of consecutive `//` lines into a JSDoc block
|
|
10
|
+
- Dry run mode with diff output
|
|
11
|
+
- Width / punctuation heuristics and NOTE normalization
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
comments [options] <files...>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Examples:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
comments src/**/*.ts
|
|
23
|
+
comments --dry-run src/index.ts
|
|
24
|
+
comments --width 100 --merge-line-comments 'src/**/*.ts'
|
|
25
|
+
comments --no-line-wrap src/file.ts
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Flags
|
|
29
|
+
|
|
30
|
+
| Flag | Description |
|
|
31
|
+
| ----------------------- | --------------------------------------------- |
|
|
32
|
+
| `--width <n>` | Max output line width (default 80) |
|
|
33
|
+
| `--dry-run` | Show diff only; exit 1 if changes would occur |
|
|
34
|
+
| `--stdout` | Print transformed content of a single file |
|
|
35
|
+
| `--no-line-wrap` | Disable wrapping of `//` comments |
|
|
36
|
+
| `--merge-line-comments` | Merge groups of `//` into JSDoc blocks |
|
|
37
|
+
| `-h, --help` | Show help |
|
|
38
|
+
| `-v, --version` | Show version |
|
|
39
|
+
|
|
40
|
+
## Exit Codes
|
|
41
|
+
|
|
42
|
+
- `0` success or dry run with no changes
|
|
43
|
+
- `1` dry run with changes or usage error
|
|
44
|
+
|
|
45
|
+
## Roadmap
|
|
46
|
+
|
|
47
|
+
See project PRD `reflow-jsdoc-PRD.md` for full specification.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { describe, expect, it } from "vitest";
|
|
5
|
+
import { augmentPatterns, expandGlobs } from "../glob.js";
|
|
6
|
+
import { parseAndTransformComments } from "../lib.js";
|
|
7
|
+
describe("glob utilities & additional lib branches", function() {
|
|
8
|
+
it("augmentPatterns adds deep variant only when needed", function() {
|
|
9
|
+
var input = [
|
|
10
|
+
"/tmp/dir/*.ts",
|
|
11
|
+
"/tmp/dir/**/a.ts",
|
|
12
|
+
"/tmp/file.txt"
|
|
13
|
+
]; // second already deep, third no wildcard folder/file split
|
|
14
|
+
var out = augmentPatterns(input);
|
|
15
|
+
// Should add one deep variant for first pattern
|
|
16
|
+
var additions = out.filter(function(p) {
|
|
17
|
+
return p.includes("**/*.ts");
|
|
18
|
+
});
|
|
19
|
+
expect(additions.length).toBe(1);
|
|
20
|
+
});
|
|
21
|
+
it("expandGlobs matches literals and wildcards including ?", function() {
|
|
22
|
+
var root = fs.mkdtempSync(path.join(os.tmpdir(), "comments-glob2-"));
|
|
23
|
+
var files = [
|
|
24
|
+
"a.ts",
|
|
25
|
+
"ab.ts",
|
|
26
|
+
"abc.ts",
|
|
27
|
+
"note.md"
|
|
28
|
+
]; // to test ? wildcard and *
|
|
29
|
+
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
30
|
+
try {
|
|
31
|
+
for(var _iterator = files[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
32
|
+
var f = _step.value;
|
|
33
|
+
fs.writeFileSync(path.join(root, f), "// x", "utf8");
|
|
34
|
+
}
|
|
35
|
+
} catch (err) {
|
|
36
|
+
_didIteratorError = true;
|
|
37
|
+
_iteratorError = err;
|
|
38
|
+
} finally{
|
|
39
|
+
try {
|
|
40
|
+
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
41
|
+
_iterator.return();
|
|
42
|
+
}
|
|
43
|
+
} finally{
|
|
44
|
+
if (_didIteratorError) {
|
|
45
|
+
throw _iteratorError;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
var patterns = [
|
|
50
|
+
path.join(root, "a?.ts"),
|
|
51
|
+
path.join(root, "a*.ts"),
|
|
52
|
+
path.join(root, "note.md")
|
|
53
|
+
];
|
|
54
|
+
var expanded = expandGlobs(patterns).map(function(p) {
|
|
55
|
+
return path.basename(p);
|
|
56
|
+
}).sort();
|
|
57
|
+
expect(expanded).toEqual([
|
|
58
|
+
"a.ts",
|
|
59
|
+
"ab.ts",
|
|
60
|
+
"abc.ts",
|
|
61
|
+
"note.md"
|
|
62
|
+
].sort());
|
|
63
|
+
});
|
|
64
|
+
it("expandGlobs handles symlinks when followSymlinks true", function() {
|
|
65
|
+
var root = fs.mkdtempSync(path.join(os.tmpdir(), "comments-glob-sym-"));
|
|
66
|
+
var target = path.join(root, "target.ts");
|
|
67
|
+
fs.writeFileSync(target, "// target", "utf8");
|
|
68
|
+
var link = path.join(root, "link.ts");
|
|
69
|
+
try {
|
|
70
|
+
fs.symlinkSync(target, link);
|
|
71
|
+
} catch (e) {
|
|
72
|
+
// Some file systems may not allow symlinks (CI on Windows); skip gracefully.
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
var pattern = path.join(root, "*.ts");
|
|
76
|
+
var noFollow = expandGlobs([
|
|
77
|
+
pattern
|
|
78
|
+
], {
|
|
79
|
+
followSymlinks: false
|
|
80
|
+
});
|
|
81
|
+
expect(noFollow).toContain(target);
|
|
82
|
+
expect(noFollow).not.toContain(link);
|
|
83
|
+
var withFollow = expandGlobs([
|
|
84
|
+
pattern
|
|
85
|
+
], {
|
|
86
|
+
followSymlinks: true
|
|
87
|
+
});
|
|
88
|
+
expect(withFollow).toContain(target);
|
|
89
|
+
expect(withFollow).toContain(link);
|
|
90
|
+
});
|
|
91
|
+
it("expandGlobs handles file literals, duplicate patterns and nonexistent paths", function() {
|
|
92
|
+
var root = fs.mkdtempSync(path.join(os.tmpdir(), "comments-glob-lit-"));
|
|
93
|
+
var file = path.join(root, "only.ts");
|
|
94
|
+
fs.writeFileSync(file, "// only", "utf8");
|
|
95
|
+
// duplicate patterns plus a nonexistent literal
|
|
96
|
+
var patterns = [
|
|
97
|
+
file,
|
|
98
|
+
file,
|
|
99
|
+
path.join(root, "missing.ts")
|
|
100
|
+
];
|
|
101
|
+
var out = expandGlobs(patterns);
|
|
102
|
+
expect(out).toEqual([
|
|
103
|
+
file
|
|
104
|
+
]); // only once
|
|
105
|
+
});
|
|
106
|
+
it("lib buildJsDoc preserves blank line separation and fences (edge branch)", function() {
|
|
107
|
+
var input = [
|
|
108
|
+
"/**",
|
|
109
|
+
" * First paragraph line",
|
|
110
|
+
" *",
|
|
111
|
+
" * ```sh",
|
|
112
|
+
" * echo hi",
|
|
113
|
+
" * ```",
|
|
114
|
+
" *",
|
|
115
|
+
" * Second paragraph without period",
|
|
116
|
+
" */"
|
|
117
|
+
].join("\n");
|
|
118
|
+
var out = parseAndTransformComments(input, {
|
|
119
|
+
width: 60,
|
|
120
|
+
wrapLineComments: true,
|
|
121
|
+
mergeLineComments: false
|
|
122
|
+
}).transformed;
|
|
123
|
+
// At least one blank line (line with only '*') preserved around fence
|
|
124
|
+
var starBlankCount = out.split(/\n/).filter(function(l) {
|
|
125
|
+
return /^\s*\*\s*$/.test(l);
|
|
126
|
+
}).length;
|
|
127
|
+
expect(starBlankCount).toBeGreaterThanOrEqual(1);
|
|
128
|
+
// Fenced code block retained
|
|
129
|
+
expect(out).toContain("```sh");
|
|
130
|
+
// Second paragraph ended with period added
|
|
131
|
+
expect(/Second paragraph without period\./.test(out)).toBe(true);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
//# sourceMappingURL=glob.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/__tests__/glob.test.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { describe, expect, it } from \"vitest\";\nimport { augmentPatterns, expandGlobs } from \"../glob.js\";\nimport { parseAndTransformComments } from \"../lib.js\";\n\ndescribe(\"glob utilities & additional lib branches\", () => {\n\tit(\"augmentPatterns adds deep variant only when needed\", () => {\n\t\tconst input = [\"/tmp/dir/*.ts\", \"/tmp/dir/**/a.ts\", \"/tmp/file.txt\"]; // second already deep, third no wildcard folder/file split\n\t\tconst out = augmentPatterns(input);\n\t\t// Should add one deep variant for first pattern\n\t\tconst additions = out.filter((p) => p.includes(\"**/*.ts\"));\n\t\texpect(additions.length).toBe(1);\n\t});\n\n\tit(\"expandGlobs matches literals and wildcards including ?\", () => {\n\t\tconst root = fs.mkdtempSync(path.join(os.tmpdir(), \"comments-glob2-\"));\n\t\tconst files = [\"a.ts\", \"ab.ts\", \"abc.ts\", \"note.md\"]; // to test ? wildcard and *\n\t\tfor (const f of files) {\n\t\t\tfs.writeFileSync(path.join(root, f), \"// x\", \"utf8\");\n\t\t}\n\t\tconst patterns = [\n\t\t\tpath.join(root, \"a?.ts\"), // should match ab.ts only\n\t\t\tpath.join(root, \"a*.ts\"), // matches a.ts, ab.ts, abc.ts\n\t\t\tpath.join(root, \"note.md\"), // literal\n\t\t];\n\t\tconst expanded = expandGlobs(patterns)\n\t\t\t.map((p) => path.basename(p))\n\t\t\t.sort();\n\t\texpect(expanded).toEqual([\"a.ts\", \"ab.ts\", \"abc.ts\", \"note.md\"].sort());\n\t});\n\n\tit(\"expandGlobs handles symlinks when followSymlinks true\", () => {\n\t\tconst root = fs.mkdtempSync(path.join(os.tmpdir(), \"comments-glob-sym-\"));\n\t\tconst target = path.join(root, \"target.ts\");\n\t\tfs.writeFileSync(target, \"// target\", \"utf8\");\n\t\tconst link = path.join(root, \"link.ts\");\n\t\ttry {\n\t\t\tfs.symlinkSync(target, link);\n\t\t} catch {\n\t\t\t// Some file systems may not allow symlinks (CI on Windows); skip gracefully.\n\t\t\treturn;\n\t\t}\n\t\tconst pattern = path.join(root, \"*.ts\");\n\t\tconst noFollow = expandGlobs([pattern], { followSymlinks: false });\n\t\texpect(noFollow).toContain(target);\n\t\texpect(noFollow).not.toContain(link);\n\t\tconst withFollow = expandGlobs([pattern], { followSymlinks: true });\n\t\texpect(withFollow).toContain(target);\n\t\texpect(withFollow).toContain(link);\n\t});\n\n\tit(\"expandGlobs handles file literals, duplicate patterns and nonexistent paths\", () => {\n\t\tconst root = fs.mkdtempSync(path.join(os.tmpdir(), \"comments-glob-lit-\"));\n\t\tconst file = path.join(root, \"only.ts\");\n\t\tfs.writeFileSync(file, \"// only\", \"utf8\");\n\t\t// duplicate patterns plus a nonexistent literal\n\t\tconst patterns = [file, file, path.join(root, \"missing.ts\")];\n\t\tconst out = expandGlobs(patterns);\n\t\texpect(out).toEqual([file]); // only once\n\t});\n\n\tit(\"lib buildJsDoc preserves blank line separation and fences (edge branch)\", () => {\n\t\tconst input = [\n\t\t\t\"/**\",\n\t\t\t\" * First paragraph line\",\n\t\t\t\" *\",\n\t\t\t\" * ```sh\",\n\t\t\t\" * echo hi\",\n\t\t\t\" * ```\",\n\t\t\t\" *\",\n\t\t\t\" * Second paragraph without period\",\n\t\t\t\" */\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(input, {\n\t\t\twidth: 60,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: false,\n\t\t}).transformed;\n\t\t// At least one blank line (line with only '*') preserved around fence\n\t\tconst starBlankCount = out\n\t\t\t.split(/\\n/)\n\t\t\t.filter((l) => /^\\s*\\*\\s*$/.test(l)).length;\n\t\texpect(starBlankCount).toBeGreaterThanOrEqual(1);\n\t\t// Fenced code block retained\n\t\texpect(out).toContain(\"```sh\");\n\t\t// Second paragraph ended with period added\n\t\texpect(/Second paragraph without period\\./.test(out)).toBe(true);\n\t});\n});\n"],"names":["fs","os","path","describe","expect","it","augmentPatterns","expandGlobs","parseAndTransformComments","input","out","additions","filter","p","includes","length","toBe","root","mkdtempSync","join","tmpdir","files","f","writeFileSync","patterns","expanded","map","basename","sort","toEqual","target","link","symlinkSync","pattern","noFollow","followSymlinks","toContain","not","withFollow","file","width","wrapLineComments","mergeLineComments","transformed","starBlankCount","split","l","test","toBeGreaterThanOrEqual"],"mappings":"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"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
function _define_property(obj, key, value) {
|
|
2
|
+
if (key in obj) {
|
|
3
|
+
Object.defineProperty(obj, key, {
|
|
4
|
+
value: value,
|
|
5
|
+
enumerable: true,
|
|
6
|
+
configurable: true,
|
|
7
|
+
writable: true
|
|
8
|
+
});
|
|
9
|
+
} else {
|
|
10
|
+
obj[key] = value;
|
|
11
|
+
}
|
|
12
|
+
return obj;
|
|
13
|
+
}
|
|
14
|
+
function _object_spread(target) {
|
|
15
|
+
for(var i = 1; i < arguments.length; i++){
|
|
16
|
+
var source = arguments[i] != null ? arguments[i] : {};
|
|
17
|
+
var ownKeys = Object.keys(source);
|
|
18
|
+
if (typeof Object.getOwnPropertySymbols === "function") {
|
|
19
|
+
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
|
|
20
|
+
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
23
|
+
ownKeys.forEach(function(key) {
|
|
24
|
+
_define_property(target, key, source[key]);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return target;
|
|
28
|
+
}
|
|
29
|
+
function ownKeys(object, enumerableOnly) {
|
|
30
|
+
var keys = Object.keys(object);
|
|
31
|
+
if (Object.getOwnPropertySymbols) {
|
|
32
|
+
var symbols = Object.getOwnPropertySymbols(object);
|
|
33
|
+
if (enumerableOnly) {
|
|
34
|
+
symbols = symbols.filter(function(sym) {
|
|
35
|
+
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
keys.push.apply(keys, symbols);
|
|
39
|
+
}
|
|
40
|
+
return keys;
|
|
41
|
+
}
|
|
42
|
+
function _object_spread_props(target, source) {
|
|
43
|
+
source = source != null ? source : {};
|
|
44
|
+
if (Object.getOwnPropertyDescriptors) {
|
|
45
|
+
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
|
|
46
|
+
} else {
|
|
47
|
+
ownKeys(Object(source)).forEach(function(key) {
|
|
48
|
+
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
return target;
|
|
52
|
+
}
|
|
53
|
+
import fs from "node:fs";
|
|
54
|
+
import os from "node:os";
|
|
55
|
+
import path from "node:path";
|
|
56
|
+
import { describe, expect, it } from "vitest";
|
|
57
|
+
import { augmentPatterns, expandGlobs } from "../glob.js";
|
|
58
|
+
import { diffLines, parseAndTransformComments } from "../lib.js";
|
|
59
|
+
var baseOpts = {
|
|
60
|
+
width: 60,
|
|
61
|
+
wrapLineComments: true,
|
|
62
|
+
mergeLineComments: false
|
|
63
|
+
};
|
|
64
|
+
describe("parseAndTransformComments", function() {
|
|
65
|
+
it("reflows a simple jsdoc and adds period", function() {
|
|
66
|
+
var input = "/**\n * This function does something\n * important\n */";
|
|
67
|
+
var res = parseAndTransformComments(input, baseOpts);
|
|
68
|
+
expect(res.transformed).toContain("does something important.");
|
|
69
|
+
});
|
|
70
|
+
it("normalizes NOTE capitalization", function() {
|
|
71
|
+
var input = "/**\n * note: edge case\n */";
|
|
72
|
+
var res = parseAndTransformComments(input, baseOpts);
|
|
73
|
+
expect(/NOTE: edge case/.test(res.transformed)).toBe(true);
|
|
74
|
+
});
|
|
75
|
+
it("wraps single line comments", function() {
|
|
76
|
+
var input = "// this is a very long comment that should be wrapped across multiple lines to satisfy width";
|
|
77
|
+
var res = parseAndTransformComments(input, baseOpts);
|
|
78
|
+
expect(res.transformed.split(/\n/).length).toBeGreaterThan(1);
|
|
79
|
+
});
|
|
80
|
+
it("merges groups of line comments into jsdoc", function() {
|
|
81
|
+
var input = [
|
|
82
|
+
"// first line",
|
|
83
|
+
"// second line",
|
|
84
|
+
"// third line",
|
|
85
|
+
"const x = 1;"
|
|
86
|
+
].join("\n");
|
|
87
|
+
var res = parseAndTransformComments(input, _object_spread_props(_object_spread({}, baseOpts), {
|
|
88
|
+
mergeLineComments: true
|
|
89
|
+
}));
|
|
90
|
+
expect(/\/\*\*/.test(res.transformed)).toBe(true);
|
|
91
|
+
});
|
|
92
|
+
it("is idempotent (second pass unchanged)", function() {
|
|
93
|
+
var input = "/**\n * Example doc that will be normalized\n */";
|
|
94
|
+
var first = parseAndTransformComments(input, baseOpts).transformed;
|
|
95
|
+
var second = parseAndTransformComments(first, baseOpts).transformed;
|
|
96
|
+
expect(diffLines(first, second)).toBe("");
|
|
97
|
+
});
|
|
98
|
+
it("preserves code fence blocks", function() {
|
|
99
|
+
var input = "/**\n * Before\n * ```js\n * const x= 1; \n * ```\n * After\n */";
|
|
100
|
+
var res = parseAndTransformComments(input, baseOpts).transformed;
|
|
101
|
+
expect(/```js/.test(res)).toBe(true);
|
|
102
|
+
// ensure spacing inside fence not normalized
|
|
103
|
+
expect(/const {2}x= {2}1;/.test(res)).toBe(true);
|
|
104
|
+
});
|
|
105
|
+
it("does not merge directive or license groups", function() {
|
|
106
|
+
var input = [
|
|
107
|
+
"// eslint-disable-next-line",
|
|
108
|
+
"// second line should prevent merge due to directive",
|
|
109
|
+
"const y = 2;",
|
|
110
|
+
"// Copyright 2024 Example",
|
|
111
|
+
"// another line"
|
|
112
|
+
].join("\n");
|
|
113
|
+
var res = parseAndTransformComments(input, _object_spread_props(_object_spread({}, baseOpts), {
|
|
114
|
+
mergeLineComments: true
|
|
115
|
+
}));
|
|
116
|
+
expect(/eslint-disable/.test(res.transformed)).toBe(true);
|
|
117
|
+
// Should not have merged into a jsdoc (no /** directly before const)
|
|
118
|
+
expect(/\/\*\*/.test(res.transformed)).toBe(false);
|
|
119
|
+
});
|
|
120
|
+
it("list items are not reflowed into a paragraph", function() {
|
|
121
|
+
var input = "/**\n * First line explaining.\n * - item one more words here\n * - item two\n */";
|
|
122
|
+
var res = parseAndTransformComments(input, baseOpts).transformed;
|
|
123
|
+
// each list item remains on its own line with leading dash
|
|
124
|
+
var lines = res.split(/\n/).filter(function(l) {
|
|
125
|
+
return /- item/.test(l);
|
|
126
|
+
});
|
|
127
|
+
expect(lines.length).toBe(2);
|
|
128
|
+
});
|
|
129
|
+
it("tag lines are preserved", function() {
|
|
130
|
+
var input = "/**\n * short description\n * @param x value\n * @returns something\n */";
|
|
131
|
+
var res = parseAndTransformComments(input, baseOpts).transformed;
|
|
132
|
+
expect(/@param x value/.test(res)).toBe(true);
|
|
133
|
+
expect(/@returns something/.test(res)).toBe(true);
|
|
134
|
+
});
|
|
135
|
+
it("handles heading-like lines with colon and visually indented code & numeric lists", function() {
|
|
136
|
+
var input = [
|
|
137
|
+
"/**",
|
|
138
|
+
" * Overview:",
|
|
139
|
+
" * const x = 1;",
|
|
140
|
+
" * 1. first",
|
|
141
|
+
" * 2. second",
|
|
142
|
+
" *",
|
|
143
|
+
" * Another paragraph without period",
|
|
144
|
+
" */"
|
|
145
|
+
].join("\n");
|
|
146
|
+
var out = parseAndTransformComments(input, baseOpts).transformed;
|
|
147
|
+
// Heading preserved, not merged into previous paragraph
|
|
148
|
+
expect(out).toMatch(/Overview:/);
|
|
149
|
+
// Visually indented code line kept as-is (no extra wrapping collapse)
|
|
150
|
+
expect(out).toMatch(/const\s{3}x = 1;/);
|
|
151
|
+
// Ensure final blank line before closing preserved (one line ending with ' *')
|
|
152
|
+
var trailingBlank = /\n \*\n\*\/$/.test(out.replace(/\r/g, ""));
|
|
153
|
+
expect(trailingBlank).toBe(true);
|
|
154
|
+
// Numeric list lines preserved
|
|
155
|
+
expect(out).toMatch(/1\. first/);
|
|
156
|
+
expect(out).toMatch(/2\. second/);
|
|
157
|
+
// Trailing paragraph got terminal period
|
|
158
|
+
expect(out).toMatch(/Another paragraph without period\./);
|
|
159
|
+
});
|
|
160
|
+
it("glob expansion matches created files", function() {
|
|
161
|
+
// Create a truly temporary isolated directory outside source tree
|
|
162
|
+
var tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), "comments-glob-"));
|
|
163
|
+
var a = path.join(tmpRoot, "a.ts");
|
|
164
|
+
var nestedDir = path.join(tmpRoot, "nested");
|
|
165
|
+
fs.mkdirSync(nestedDir, {
|
|
166
|
+
recursive: true
|
|
167
|
+
});
|
|
168
|
+
var b = path.join(nestedDir, "b.ts");
|
|
169
|
+
fs.writeFileSync(a, "// file a", "utf8");
|
|
170
|
+
fs.writeFileSync(b, "// file b", "utf8");
|
|
171
|
+
var patterns = [
|
|
172
|
+
"".concat(tmpRoot, "/*.ts")
|
|
173
|
+
];
|
|
174
|
+
var augmented = augmentPatterns(patterns);
|
|
175
|
+
expect(augmented.some(function(p) {
|
|
176
|
+
return p.includes("**/*.ts");
|
|
177
|
+
})).toBe(true);
|
|
178
|
+
var expanded = expandGlobs(patterns);
|
|
179
|
+
expect(expanded.sort()).toEqual([
|
|
180
|
+
a,
|
|
181
|
+
b
|
|
182
|
+
].sort());
|
|
183
|
+
});
|
|
184
|
+
// Added test for preserving multi-line // comment groups that should NOT merge when preceded by code.
|
|
185
|
+
it("does not merge an inline explanatory multi-line // comment group following code", function() {
|
|
186
|
+
var src = [
|
|
187
|
+
"function demo() {",
|
|
188
|
+
" const x = 1; // keep",
|
|
189
|
+
" // first line explains next block",
|
|
190
|
+
" // still explaining",
|
|
191
|
+
" // final line",
|
|
192
|
+
" return x; // done",
|
|
193
|
+
"}",
|
|
194
|
+
""
|
|
195
|
+
].join("\n");
|
|
196
|
+
var out = parseAndTransformComments(src, {
|
|
197
|
+
mergeLineComments: true,
|
|
198
|
+
wrapLineComments: true,
|
|
199
|
+
width: 80
|
|
200
|
+
}).transformed;
|
|
201
|
+
expect(out).toContain(" // first line explains next block");
|
|
202
|
+
expect(out).toContain(" // still explaining");
|
|
203
|
+
expect(out).toContain(" // final line");
|
|
204
|
+
expect(out).not.toContain("/**");
|
|
205
|
+
});
|
|
206
|
+
it("converts the multi-line explanatory block from lib.ts into a multi-line JSDoc, preserving lines", function() {
|
|
207
|
+
var snippet = [
|
|
208
|
+
"// JSDoc block extraction:",
|
|
209
|
+
"// Previous pattern used a lazy dot-all: ([\\s\\S]*?) which could, under",
|
|
210
|
+
"// pathological inputs, produce excessive backtracking. We replace it with a",
|
|
211
|
+
"// tempered pattern that advances linearly by never letting the inner part",
|
|
212
|
+
"// consume a closing '*/'. This avoids catastrophic behavior while keeping",
|
|
213
|
+
"// correctness.",
|
|
214
|
+
"// Pattern explanation:",
|
|
215
|
+
"// (^ [\\t ]* ) -> capture indentation at start of line (multiline mode)",
|
|
216
|
+
"// /\\*\\* -> opening delimiter",
|
|
217
|
+
"// ( -> capture group 2 body",
|
|
218
|
+
"// (?:[^*] -> any non-* char",
|
|
219
|
+
"// |\\*(?!/) -> or a * not followed by /",
|
|
220
|
+
"// )* -> repeated greedily (cannot cross closing */)",
|
|
221
|
+
"// )",
|
|
222
|
+
"// \\n?[\\t ]*\\*/ -> optional newline + trailing indent + closing */",
|
|
223
|
+
"// The greedy repetition is safe because the inner alternatives are mutually",
|
|
224
|
+
"// exclusive and each consumes at least one char without overlapping on the",
|
|
225
|
+
"// closing sentinel."
|
|
226
|
+
].join("\n");
|
|
227
|
+
var out = parseAndTransformComments(snippet, {
|
|
228
|
+
width: 100,
|
|
229
|
+
wrapLineComments: true,
|
|
230
|
+
mergeLineComments: true
|
|
231
|
+
}).transformed;
|
|
232
|
+
// Should be converted to a JSDoc (first and last lines delimiters)
|
|
233
|
+
var lines = out.split(/\n/);
|
|
234
|
+
expect(lines[0].trim()).toBe("/**");
|
|
235
|
+
expect(lines[lines.length - 1].trim()).toBe("*/");
|
|
236
|
+
// Ensure representative internal lines are present (now without leading //)
|
|
237
|
+
expect(out).toContain("* JSDoc block extraction:");
|
|
238
|
+
expect(out).toContain("* Pattern explanation:");
|
|
239
|
+
// Arrow lines preserved
|
|
240
|
+
var arrowLineCount = lines.filter(function(l) {
|
|
241
|
+
return /->/.test(l);
|
|
242
|
+
}).length;
|
|
243
|
+
expect(arrowLineCount).toBeGreaterThanOrEqual(5);
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
//# sourceMappingURL=lib.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/__tests__/lib.test.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { describe, expect, it } from \"vitest\";\nimport { augmentPatterns, expandGlobs } from \"../glob.js\";\nimport { diffLines, parseAndTransformComments } from \"../lib.js\";\n\nconst baseOpts = {\n\twidth: 60,\n\twrapLineComments: true,\n\tmergeLineComments: false,\n};\n\ndescribe(\"parseAndTransformComments\", () => {\n\tit(\"reflows a simple jsdoc and adds period\", () => {\n\t\tconst input = \"/**\\n * This function does something\\n * important\\n */\";\n\t\tconst res = parseAndTransformComments(input, baseOpts);\n\t\texpect(res.transformed).toContain(\"does something important.\");\n\t});\n\n\tit(\"normalizes NOTE capitalization\", () => {\n\t\tconst input = \"/**\\n * note: edge case\\n */\";\n\t\tconst res = parseAndTransformComments(input, baseOpts);\n\t\texpect(/NOTE: edge case/.test(res.transformed)).toBe(true);\n\t});\n\n\tit(\"wraps single line comments\", () => {\n\t\tconst input =\n\t\t\t\"// this is a very long comment that should be wrapped across multiple lines to satisfy width\";\n\t\tconst res = parseAndTransformComments(input, baseOpts);\n\t\texpect(res.transformed.split(/\\n/).length).toBeGreaterThan(1);\n\t});\n\n\tit(\"merges groups of line comments into jsdoc\", () => {\n\t\tconst input = [\n\t\t\t\"// first line\",\n\t\t\t\"// second line\",\n\t\t\t\"// third line\",\n\t\t\t\"const x = 1;\",\n\t\t].join(\"\\n\");\n\t\tconst res = parseAndTransformComments(input, {\n\t\t\t...baseOpts,\n\t\t\tmergeLineComments: true,\n\t\t});\n\t\texpect(/\\/\\*\\*/.test(res.transformed)).toBe(true);\n\t});\n\n\tit(\"is idempotent (second pass unchanged)\", () => {\n\t\tconst input = \"/**\\n * Example doc that will be normalized\\n */\";\n\t\tconst first = parseAndTransformComments(input, baseOpts).transformed;\n\t\tconst second = parseAndTransformComments(first, baseOpts).transformed;\n\t\texpect(diffLines(first, second)).toBe(\"\");\n\t});\n\n\tit(\"preserves code fence blocks\", () => {\n\t\tconst input =\n\t\t\t\"/**\\n * Before\\n * ```js\\n * const x= 1; \\n * ```\\n * After\\n */\";\n\t\tconst res = parseAndTransformComments(input, baseOpts).transformed;\n\t\texpect(/```js/.test(res)).toBe(true);\n\t\t// ensure spacing inside fence not normalized\n\t\texpect(/const {2}x= {2}1;/.test(res)).toBe(true);\n\t});\n\n\tit(\"does not merge directive or license groups\", () => {\n\t\tconst input = [\n\t\t\t\"// eslint-disable-next-line\",\n\t\t\t\"// second line should prevent merge due to directive\",\n\t\t\t\"const y = 2;\",\n\t\t\t\"// Copyright 2024 Example\",\n\t\t\t\"// another line\",\n\t\t].join(\"\\n\");\n\t\tconst res = parseAndTransformComments(input, {\n\t\t\t...baseOpts,\n\t\t\tmergeLineComments: true,\n\t\t});\n\t\texpect(/eslint-disable/.test(res.transformed)).toBe(true);\n\t\t// Should not have merged into a jsdoc (no /** directly before const)\n\t\texpect(/\\/\\*\\*/.test(res.transformed)).toBe(false);\n\t});\n\n\tit(\"list items are not reflowed into a paragraph\", () => {\n\t\tconst input =\n\t\t\t\"/**\\n * First line explaining.\\n * - item one more words here\\n * - item two\\n */\";\n\t\tconst res = parseAndTransformComments(input, baseOpts).transformed;\n\t\t// each list item remains on its own line with leading dash\n\t\tconst lines = res.split(/\\n/).filter((l) => /- item/.test(l));\n\t\texpect(lines.length).toBe(2);\n\t});\n\n\tit(\"tag lines are preserved\", () => {\n\t\tconst input =\n\t\t\t\"/**\\n * short description\\n * @param x value\\n * @returns something\\n */\";\n\t\tconst res = parseAndTransformComments(input, baseOpts).transformed;\n\t\texpect(/@param x value/.test(res)).toBe(true);\n\t\texpect(/@returns something/.test(res)).toBe(true);\n\t});\n\n\tit(\"handles heading-like lines with colon and visually indented code & numeric lists\", () => {\n\t\tconst input = [\n\t\t\t\"/**\",\n\t\t\t\" * Overview:\",\n\t\t\t\" * const x = 1;\",\n\t\t\t\" * 1. first\",\n\t\t\t\" * 2. second\",\n\t\t\t\" *\", // blank separation\n\t\t\t\" * Another paragraph without period\",\n\t\t\t\" */\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(input, baseOpts).transformed;\n\t\t// Heading preserved, not merged into previous paragraph\n\t\texpect(out).toMatch(/Overview:/);\n\t\t// Visually indented code line kept as-is (no extra wrapping collapse)\n\t\texpect(out).toMatch(/const\\s{3}x = 1;/);\n\t\t// Ensure final blank line before closing preserved (one line ending with ' *')\n\t\tconst trailingBlank = /\\n \\*\\n\\*\\/$/.test(out.replace(/\\r/g, \"\"));\n\t\texpect(trailingBlank).toBe(true);\n\t\t// Numeric list lines preserved\n\t\texpect(out).toMatch(/1\\. first/);\n\t\texpect(out).toMatch(/2\\. second/);\n\t\t// Trailing paragraph got terminal period\n\t\texpect(out).toMatch(/Another paragraph without period\\./);\n\t});\n\n\tit(\"glob expansion matches created files\", () => {\n\t\t// Create a truly temporary isolated directory outside source tree\n\t\tconst tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), \"comments-glob-\"));\n\t\tconst a = path.join(tmpRoot, \"a.ts\");\n\t\tconst nestedDir = path.join(tmpRoot, \"nested\");\n\t\tfs.mkdirSync(nestedDir, { recursive: true });\n\t\tconst b = path.join(nestedDir, \"b.ts\");\n\t\tfs.writeFileSync(a, \"// file a\", \"utf8\");\n\t\tfs.writeFileSync(b, \"// file b\", \"utf8\");\n\t\tconst patterns = [`${tmpRoot}/*.ts`];\n\t\tconst augmented = augmentPatterns(patterns);\n\t\texpect(augmented.some((p) => p.includes(\"**/*.ts\"))).toBe(true);\n\t\tconst expanded = expandGlobs(patterns);\n\t\texpect(expanded.sort()).toEqual([a, b].sort());\n\t});\n\n\t// Added test for preserving multi-line // comment groups that should NOT merge when preceded by code.\n\tit(\"does not merge an inline explanatory multi-line // comment group following code\", () => {\n\t\tconst src = [\n\t\t\t\"function demo() {\",\n\t\t\t\" const x = 1; // keep\",\n\t\t\t\" // first line explains next block\",\n\t\t\t\" // still explaining\",\n\t\t\t\" // final line\",\n\t\t\t\" return x; // done\",\n\t\t\t\"}\",\n\t\t\t\"\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\tmergeLineComments: true,\n\t\t\twrapLineComments: true,\n\t\t\twidth: 80,\n\t\t}).transformed;\n\t\texpect(out).toContain(\" // first line explains next block\");\n\t\texpect(out).toContain(\" // still explaining\");\n\t\texpect(out).toContain(\" // final line\");\n\t\texpect(out).not.toContain(\"/**\");\n\t});\n\n\tit(\"converts the multi-line explanatory block from lib.ts into a multi-line JSDoc, preserving lines\", () => {\n\t\tconst snippet = [\n\t\t\t\"// JSDoc block extraction:\",\n\t\t\t\"// Previous pattern used a lazy dot-all: ([\\\\s\\\\S]*?) which could, under\",\n\t\t\t\"// pathological inputs, produce excessive backtracking. We replace it with a\",\n\t\t\t\"// tempered pattern that advances linearly by never letting the inner part\",\n\t\t\t\"// consume a closing '*/'. This avoids catastrophic behavior while keeping\",\n\t\t\t\"// correctness.\",\n\t\t\t\"// Pattern explanation:\",\n\t\t\t\"// (^ [\\\\t ]* ) -> capture indentation at start of line (multiline mode)\",\n\t\t\t\"// /\\\\*\\\\* -> opening delimiter\",\n\t\t\t\"// ( -> capture group 2 body\",\n\t\t\t\"// (?:[^*] -> any non-* char\",\n\t\t\t\"// |\\\\*(?!/) -> or a * not followed by /\",\n\t\t\t\"// )* -> repeated greedily (cannot cross closing */)\",\n\t\t\t\"// )\",\n\t\t\t\"// \\\\n?[\\\\t ]*\\\\*/ -> optional newline + trailing indent + closing */\",\n\t\t\t\"// The greedy repetition is safe because the inner alternatives are mutually\",\n\t\t\t\"// exclusive and each consumes at least one char without overlapping on the\",\n\t\t\t\"// closing sentinel.\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(snippet, {\n\t\t\twidth: 100,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\t// Should be converted to a JSDoc (first and last lines delimiters)\n\t\tconst lines = out.split(/\\n/);\n\t\texpect(lines[0].trim()).toBe(\"/**\");\n\t\texpect(lines[lines.length - 1].trim()).toBe(\"*/\");\n\t\t// Ensure representative internal lines are present (now without leading //)\n\t\texpect(out).toContain(\"* JSDoc block extraction:\");\n\t\texpect(out).toContain(\"* Pattern explanation:\");\n\t\t// Arrow lines preserved\n\t\tconst arrowLineCount = lines.filter((l) => /->/.test(l)).length;\n\t\texpect(arrowLineCount).toBeGreaterThanOrEqual(5);\n\t});\n});\n"],"names":["fs","os","path","describe","expect","it","augmentPatterns","expandGlobs","diffLines","parseAndTransformComments","baseOpts","width","wrapLineComments","mergeLineComments","input","res","transformed","toContain","test","toBe","split","length","toBeGreaterThan","join","first","second","lines","filter","l","out","toMatch","trailingBlank","replace","tmpRoot","mkdtempSync","tmpdir","a","nestedDir","mkdirSync","recursive","b","writeFileSync","patterns","augmented","some","p","includes","expanded","sort","toEqual","src","not","snippet","trim","arrowLineCount","toBeGreaterThanOrEqual"],"mappings":"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"}
|
package/dist/comments.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* v8 ignore start */ import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import kleur from "kleur";
|
|
5
|
+
import { expandGlobs } from "./glob.js";
|
|
6
|
+
import { diffLines, logger, parseAndTransformComments } from "./lib.js";
|
|
7
|
+
import { config } from "./parse.js";
|
|
8
|
+
function exit(code) {
|
|
9
|
+
process.exit(code);
|
|
10
|
+
}
|
|
11
|
+
function readFileSafe(file) {
|
|
12
|
+
try {
|
|
13
|
+
return fs.readFileSync(file, "utf8");
|
|
14
|
+
} catch (e) {
|
|
15
|
+
logger.error("File not found: ".concat(file));
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
var width = Number(config.flags.width || 80);
|
|
20
|
+
var wrapLineComments = config.flags.noLineWrap !== true;
|
|
21
|
+
var mergeLineComments = config.flags.mergeLineComments === true;
|
|
22
|
+
var fileArgs = Object.values(config.parameters || {});
|
|
23
|
+
// Expand simple glob patterns (*, **, ?) per PRD.
|
|
24
|
+
if (fileArgs.length > 0) {
|
|
25
|
+
fileArgs = expandGlobs(fileArgs);
|
|
26
|
+
}
|
|
27
|
+
var files = fileArgs;
|
|
28
|
+
if (!files.length) {
|
|
29
|
+
var _logger_printErrorsAndExit;
|
|
30
|
+
(_logger_printErrorsAndExit = logger.printErrorsAndExit) === null || _logger_printErrorsAndExit === void 0 ? void 0 : _logger_printErrorsAndExit.call(logger, [
|
|
31
|
+
"No matching files found"
|
|
32
|
+
], 1);
|
|
33
|
+
}
|
|
34
|
+
var anyChanges = false;
|
|
35
|
+
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
36
|
+
try {
|
|
37
|
+
for(var _iterator = files[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
38
|
+
var file = _step.value;
|
|
39
|
+
var source = readFileSafe(file);
|
|
40
|
+
if (source === undefined) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
var result = parseAndTransformComments(source, {
|
|
44
|
+
width: width,
|
|
45
|
+
wrapLineComments: wrapLineComments,
|
|
46
|
+
mergeLineComments: mergeLineComments
|
|
47
|
+
});
|
|
48
|
+
if (config.flags.dryRun) {
|
|
49
|
+
if (result.changed) {
|
|
50
|
+
anyChanges = true;
|
|
51
|
+
logger.info("Changes in ".concat(file));
|
|
52
|
+
var d = diffLines(source, result.transformed);
|
|
53
|
+
if (d) {
|
|
54
|
+
process.stdout.write(kleur.gray("\n".concat(d, "\n\n")));
|
|
55
|
+
}
|
|
56
|
+
} else {
|
|
57
|
+
logger.info("No changes needed in ".concat(file));
|
|
58
|
+
}
|
|
59
|
+
} else if (config.flags.stdout) {
|
|
60
|
+
process.stdout.write(result.transformed);
|
|
61
|
+
} else if (result.changed) {
|
|
62
|
+
fs.writeFileSync(file, result.transformed, "utf8");
|
|
63
|
+
logger.info("Reflowed ".concat(path.basename(file)).concat(mergeLineComments ? " merged" : "").concat(wrapLineComments ? " wrapped" : ""));
|
|
64
|
+
} else {
|
|
65
|
+
process.stdout.write(kleur.gray("Unchanged ".concat(file, "\n")));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
} catch (err) {
|
|
69
|
+
_didIteratorError = true;
|
|
70
|
+
_iteratorError = err;
|
|
71
|
+
} finally{
|
|
72
|
+
try {
|
|
73
|
+
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
74
|
+
_iterator.return();
|
|
75
|
+
}
|
|
76
|
+
} finally{
|
|
77
|
+
if (_didIteratorError) {
|
|
78
|
+
throw _iteratorError;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (config.flags.dryRun) {
|
|
83
|
+
exit(anyChanges ? 1 : 0);
|
|
84
|
+
} /* v8 ignore stop */
|
|
85
|
+
|
|
86
|
+
//# sourceMappingURL=comments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/comments.ts"],"sourcesContent":["#!/usr/bin/env node\n/* v8 ignore start */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport kleur from \"kleur\";\nimport { expandGlobs } from \"./glob.js\";\nimport { diffLines, logger, parseAndTransformComments } from \"./lib.js\";\nimport { config } from \"./parse.js\";\n\nfunction exit(code: number) {\n\tprocess.exit(code);\n}\n\nfunction readFileSafe(file: string): string | undefined {\n\ttry {\n\t\treturn fs.readFileSync(file, \"utf8\");\n\t} catch {\n\t\tlogger.error(`File not found: ${file}`);\n\t\treturn undefined;\n\t}\n}\n\nconst width = Number(config.flags.width || 80);\nconst wrapLineComments = config.flags.noLineWrap !== true;\nconst mergeLineComments = config.flags.mergeLineComments === true;\n\nlet fileArgs: string[] = Object.values(config.parameters || {});\n// Expand simple glob patterns (*, **, ?) per PRD.\nif (fileArgs.length > 0) {\n\tfileArgs = expandGlobs(fileArgs);\n}\nconst files: string[] = fileArgs;\nif (!files.length) {\n\tlogger.printErrorsAndExit?.([\"No matching files found\"], 1);\n}\n\nlet anyChanges = false;\n\nfor (const file of files) {\n\tconst source = readFileSafe(file);\n\tif (source === undefined) {\n\t\tcontinue;\n\t}\n\tconst result = parseAndTransformComments(source, {\n\t\twidth,\n\t\twrapLineComments,\n\t\tmergeLineComments,\n\t});\n\tif (config.flags.dryRun) {\n\t\tif (result.changed) {\n\t\t\tanyChanges = true;\n\t\t\tlogger.info(`Changes in ${file}`);\n\t\t\tconst d = diffLines(source, result.transformed);\n\t\t\tif (d) {\n\t\t\t\tprocess.stdout.write(kleur.gray(`\\n${d}\\n\\n`));\n\t\t\t}\n\t\t} else {\n\t\t\tlogger.info(`No changes needed in ${file}`);\n\t\t}\n\t} else if (config.flags.stdout) {\n\t\tprocess.stdout.write(result.transformed);\n\t} else if (result.changed) {\n\t\tfs.writeFileSync(file, result.transformed, \"utf8\");\n\t\tlogger.info(\n\t\t\t`Reflowed ${path.basename(file)}${mergeLineComments ? \" merged\" : \"\"}${wrapLineComments ? \" wrapped\" : \"\"}`,\n\t\t);\n\t} else {\n\t\tprocess.stdout.write(kleur.gray(`Unchanged ${file}\\n`));\n\t}\n}\n\nif (config.flags.dryRun) {\n\texit(anyChanges ? 1 : 0);\n}\n/* v8 ignore stop */\n"],"names":["fs","path","kleur","expandGlobs","diffLines","logger","parseAndTransformComments","config","exit","code","process","readFileSafe","file","readFileSync","error","undefined","width","Number","flags","wrapLineComments","noLineWrap","mergeLineComments","fileArgs","Object","values","parameters","length","files","printErrorsAndExit","anyChanges","source","result","dryRun","changed","info","d","transformed","stdout","write","gray","writeFileSync","basename"],"mappings":";AACA,mBAAmB,GACnB,OAAOA,QAAQ,UAAU;AACzB,OAAOC,UAAU,YAAY;AAC7B,OAAOC,WAAW,QAAQ;AAC1B,SAASC,WAAW,QAAQ,YAAY;AACxC,SAASC,SAAS,EAAEC,MAAM,EAAEC,yBAAyB,QAAQ,WAAW;AACxE,SAASC,MAAM,QAAQ,aAAa;AAEpC,SAASC,KAAKC,IAAY;IACzBC,QAAQF,IAAI,CAACC;AACd;AAEA,SAASE,aAAaC,IAAY;IACjC,IAAI;QACH,OAAOZ,GAAGa,YAAY,CAACD,MAAM;IAC9B,EAAE,UAAM;QACPP,OAAOS,KAAK,CAAC,AAAC,mBAAuB,OAALF;QAChC,OAAOG;IACR;AACD;AAEA,IAAMC,QAAQC,OAAOV,OAAOW,KAAK,CAACF,KAAK,IAAI;AAC3C,IAAMG,mBAAmBZ,OAAOW,KAAK,CAACE,UAAU,KAAK;AACrD,IAAMC,oBAAoBd,OAAOW,KAAK,CAACG,iBAAiB,KAAK;AAE7D,IAAIC,WAAqBC,OAAOC,MAAM,CAACjB,OAAOkB,UAAU,IAAI,CAAC;AAC7D,kDAAkD;AAClD,IAAIH,SAASI,MAAM,GAAG,GAAG;IACxBJ,WAAWnB,YAAYmB;AACxB;AACA,IAAMK,QAAkBL;AACxB,IAAI,CAACK,MAAMD,MAAM,EAAE;QAClBrB;KAAAA,6BAAAA,OAAOuB,kBAAkB,cAAzBvB,iDAAAA,gCAAAA,QAA4B;QAAC;KAA0B,EAAE;AAC1D;AAEA,IAAIwB,aAAa;IAEZ,kCAAA,2BAAA;;IAAL,QAAK,YAAcF,0BAAd,SAAA,6BAAA,QAAA,yBAAA,iCAAqB;QAArB,IAAMf,OAAN;QACJ,IAAMkB,SAASnB,aAAaC;QAC5B,IAAIkB,WAAWf,WAAW;YACzB;QACD;QACA,IAAMgB,SAASzB,0BAA0BwB,QAAQ;YAChDd,OAAAA;YACAG,kBAAAA;YACAE,mBAAAA;QACD;QACA,IAAId,OAAOW,KAAK,CAACc,MAAM,EAAE;YACxB,IAAID,OAAOE,OAAO,EAAE;gBACnBJ,aAAa;gBACbxB,OAAO6B,IAAI,CAAC,AAAC,cAAkB,OAALtB;gBAC1B,IAAMuB,IAAI/B,UAAU0B,QAAQC,OAAOK,WAAW;gBAC9C,IAAID,GAAG;oBACNzB,QAAQ2B,MAAM,CAACC,KAAK,CAACpC,MAAMqC,IAAI,CAAC,AAAC,KAAM,OAAFJ,GAAE;gBACxC;YACD,OAAO;gBACN9B,OAAO6B,IAAI,CAAC,AAAC,wBAA4B,OAALtB;YACrC;QACD,OAAO,IAAIL,OAAOW,KAAK,CAACmB,MAAM,EAAE;YAC/B3B,QAAQ2B,MAAM,CAACC,KAAK,CAACP,OAAOK,WAAW;QACxC,OAAO,IAAIL,OAAOE,OAAO,EAAE;YAC1BjC,GAAGwC,aAAa,CAAC5B,MAAMmB,OAAOK,WAAW,EAAE;YAC3C/B,OAAO6B,IAAI,CACV,AAAC,YAAiCb,OAAtBpB,KAAKwC,QAAQ,CAAC7B,OAA6CO,OAArCE,oBAAoB,YAAY,IAAwC,OAAnCF,mBAAmB,aAAa;QAEzG,OAAO;YACNT,QAAQ2B,MAAM,CAACC,KAAK,CAACpC,MAAMqC,IAAI,CAAC,AAAC,aAAiB,OAAL3B,MAAK;QACnD;IACD;;IA/BK;IAAA;;;aAAA,6BAAA;YAAA;;;YAAA;kBAAA;;;;AAiCL,IAAIL,OAAOW,KAAK,CAACc,MAAM,EAAE;IACxBxB,KAAKqB,aAAa,IAAI;AACvB,EACA,kBAAkB"}
|
package/dist/defaults.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/defaults.ts"],"sourcesContent":["/* v8 ignore start */\nexport const defaultFlags = {\n\twidth: 80,\n\twrapLineComments: true,\n\tmergeLineComments: false,\n};\n/* v8 ignore stop */\n"],"names":["defaultFlags","width","wrapLineComments","mergeLineComments"],"mappings":"AAAA,mBAAmB,GACnB,OAAO,IAAMA,eAAe;IAC3BC,OAAO;IACPC,kBAAkB;IAClBC,mBAAmB;AACpB,EAAE,CACF,kBAAkB"}
|