@node-cli/comments 0.2.11 → 0.2.14
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/__tests__/lib.test.js +27 -0
- package/dist/__tests__/lib.test.js.map +1 -1
- package/dist/lib.js +7 -1
- package/dist/lib.js.map +1 -1
- package/package.json +12 -7
|
@@ -132,6 +132,33 @@ describe("parseAndTransformComments", function() {
|
|
|
132
132
|
expect(/@param x value/.test(res)).toBe(true);
|
|
133
133
|
expect(/@returns something/.test(res)).toBe(true);
|
|
134
134
|
});
|
|
135
|
+
it("does not treat a scoped package name as a JSDoc tag", function() {
|
|
136
|
+
var input = [
|
|
137
|
+
"/**",
|
|
138
|
+
" * We match on the error code. If a future",
|
|
139
|
+
" * @auth0/auth0-react release reshapes the description, the check still fires.",
|
|
140
|
+
" */"
|
|
141
|
+
].join("\n") + "\n";
|
|
142
|
+
var transformed = parseAndTransformComments(input, {
|
|
143
|
+
width: 80,
|
|
144
|
+
wrapLineComments: true,
|
|
145
|
+
mergeLineComments: true
|
|
146
|
+
}).transformed;
|
|
147
|
+
// No period injected mid-sentence.
|
|
148
|
+
expect(transformed).not.toMatch(/future\./);
|
|
149
|
+
// Sentence joined, scoped package kept inline as prose.
|
|
150
|
+
expect(transformed).toMatch(/future @auth0\/auth0-react/);
|
|
151
|
+
});
|
|
152
|
+
it("still treats real JSDoc tags as tags after the scoped-package fix", function() {
|
|
153
|
+
var input = "/**\n * Does a thing.\n * @param x in\n * @returns out\n */\n";
|
|
154
|
+
var transformed = parseAndTransformComments(input, {
|
|
155
|
+
width: 80,
|
|
156
|
+
wrapLineComments: true,
|
|
157
|
+
mergeLineComments: true
|
|
158
|
+
}).transformed;
|
|
159
|
+
expect(transformed).toMatch(/^ \* @param x in$/m);
|
|
160
|
+
expect(transformed).toMatch(/^ \* @returns out$/m);
|
|
161
|
+
});
|
|
135
162
|
it("handles heading-like lines with colon and visually indented code & numeric lists", function() {
|
|
136
163
|
var input = [
|
|
137
164
|
"/**",
|
|
@@ -1 +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 { 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/**\n\t\t * Trailing blank before closing is optional after recent trimming change. (we\n\t\t * only keep it when multiple paragraphs exist). Assert closing exists.\n\t\t * Closing delimiter should be on its own line; allow optional leading\n\t\t * space(s).\n\t\t */\n\t\texpect(/\\n\\s*\\*\\/$/.test(out)).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 deep files only with explicit globstar\", () => {\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\t// Shallow pattern should only see top-level a.ts.\n\t\tconst shallow = expandGlobs([`${tmpRoot}/*.ts`]).sort();\n\t\texpect(shallow).toEqual([a]);\n\t\t// Deep pattern matches both.\n\t\tconst deep = expandGlobs([`${tmpRoot}/**/*.ts`]).sort();\n\t\texpect(deep).toEqual([a, b].sort());\n\t});\n\n\t/**\n\t * Added test for preserving multi-line // comment groups that should NOT merge\n\t * when preceded by code.\n\t */\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\tit(\"does not insert period before list introduced by single lowercase word + colon\", () => {\n\t\tconst input = [\n\t\t\t\"/**\",\n\t\t\t\" * Some utilities have logging capabilities that needs to be\",\n\t\t\t\" * tested a little bit differently:\",\n\t\t\t\" * - mocking process.exit\",\n\t\t\t\" * - console.log\",\n\t\t\t\" * - inquirer.prompt\",\n\t\t\t\" */\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(input, baseOpts).transformed;\n\t\t// Ensure no stray period after 'be'.\n\t\texpect(out).not.toMatch(/needs to be\\./);\n\t\t// Ensure list items unchanged.\n\t\texpect(out).toMatch(/- mocking process\\.exit/);\n\t});\n\n\tit(\"does not add stray period before lowercase colon line inside jsdoc\", () => {\n\t\tconst input = [\n\t\t\t\"/**\",\n\t\t\t\" * Some utilities have logging capabilities that needs to be\",\n\t\t\t\" * tested a little bit differently:\",\n\t\t\t\" * - one\",\n\t\t\t\" * - two\",\n\t\t\t\" */\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(input, baseOpts).transformed;\n\t\texpect(out).not.toMatch(/needs to be\\./);\n\t});\n\n\tit(\"does not append periods to every line of a merged // comment group\", () => {\n\t\tconst original = [\n\t\t\t\"// We only want to add terminal punctuation once at the end of the merged\",\n\t\t\t\"// paragraph, not after every original line (which can create spurious\",\n\t\t\t\"// periods mid-sentence when lines were simple wraps). We also avoid\",\n\t\t\t\"// appending a period if the final line ends with a colon introducing a\",\n\t\t\t\"// list.\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(original, {\n\t\t\twidth: 160, // keep wide to avoid secondary wrapping noise\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\t// Ensure it became a JSDoc block.\n\t\texpect(out.startsWith(\"/**\")).toBe(true);\n\t\t// Should not contain stray periods after former line breaks.\n\t\texpect(out).not.toMatch(/merged\\./);\n\t\texpect(out).not.toMatch(/spurious\\./);\n\t\texpect(out).not.toMatch(/introducing a\\./);\n\t\t// Should still retain existing legitimate period after 'wraps).' and final\n\t\t// 'list.'\n\t\texpect(out).toMatch(/wraps\\)\\./);\n\t\texpect(out).toMatch(/list\\./);\n\t});\n\n\tit(\"merges a large explanatory // group after a statement into JSDoc\", () => {\n\t\tconst src = [\n\t\t\t\"const value = compute();\",\n\t\t\t\"// We only want to add terminal punctuation once at the end of the merged\",\n\t\t\t\"// paragraph, not after every original line (which can create spurious\",\n\t\t\t\"// periods mid-sentence when lines were simple wraps). We also avoid\",\n\t\t\t\"// appending a period if the final line ends with a colon introducing a\",\n\t\t\t\"// list.\",\n\t\t\t\"function next() {}\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 160,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\t// Expect merged into a JSDoc immediately after the statement.\n\t\tconst re = /compute\\(\\);\\n\\/\\*\\*[\\s\\S]*?\\n\\s*\\*\\//;\n\t\texpect(re.test(out)).toBe(true);\n\t\t// Ensure only one sentence-final period appended (present on final 'list.'\n\t\t// already).\n\t\texpect(out.match(/merged\\./)).toBeNull();\n\t});\n\n\tit(\"merges a 3-line explanatory // group after a statement into JSDoc (threshold lowered)\", () => {\n\t\tconst src = [\n\t\t\t\"const value = compute();\",\n\t\t\t\"// First explanatory line that starts with a capital\",\n\t\t\t\"// second line continues the explanation\",\n\t\t\t\"// third line completes it\",\n\t\t\t\"next();\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 120,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\t// The 3-line group should have been converted to a JSDoc block.\n\t\texpect(/compute\\(\\);\\n\\/\\*\\*/.test(out)).toBe(true);\n\t\t// Ensure original lines no longer start with // (inside block now) and period\n\t\t// appended once.\n\t\texpect(out).toMatch(/First explanatory line that starts with a capital/);\n\t\texpect(out).not.toMatch(/third line completes it\\n\\/\\//); // no stray // after\n\t});\n\n\tit(\"keeps a space before closing delimiter for complex multi-paragraph example\", () => {\n\t\tconst input = [\n\t\t\t\"/**\",\n\t\t\t\" * Extract the average from a list of numbers.\",\n\t\t\t\" *\",\n\t\t\t\" * @example\",\n\t\t\t\" * ```js\",\n\t\t\t\" * const res = extractAverage({ data: [11, 22, 33, 44] });\",\n\t\t\t\" * console.log(res); // 27.5 -> (11 + 22 + 33 + 44) / 4\",\n\t\t\t\" * ```\",\n\t\t\t\" *\",\n\t\t\t\" * Any value that is not a number or is less than 0 will be ignored.\",\n\t\t\t\" *\",\n\t\t\t\" * A formatter function can be passed to format the output. If no formatter is\",\n\t\t\t\" * provided, the default behavior is to cast the number to the generic Output\",\n\t\t\t\" * type.\",\n\t\t\t\" *\",\n\t\t\t\" */\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(input, baseOpts).transformed;\n\t\t// Closing line should contain a leading space before */ (style consistency).\n\t\texpect(/\\n \\*\\/$/.test(out)).toBe(true);\n\t\t// Should not regress by emitting no-space variant.\n\t\texpect(/\\n\\*\\/$/.test(out)).toBe(false);\n\t});\n\n\tit(\"does not add trailing space on blank '*' lines inside code fences\", () => {\n\t\tconst input = [\n\t\t\t\"/**\",\n\t\t\t\" * Function to format a number with commas as thousands separators.\",\n\t\t\t\" *\",\n\t\t\t\" * @example\",\n\t\t\t\" * ```js\",\n\t\t\t\" * const formattedNumber = numberFormatter.format(1000);\",\n\t\t\t' * console.log(formattedNumber); // \"1,000\"',\n\t\t\t\" *\", // blank line inside fence we want ' *' (no trailing space)\n\t\t\t\" * const roundedNumber = numberFormatter.format(1234.56);\",\n\t\t\t' * console.log(roundedNumber); // \"1,235\"',\n\t\t\t\" * ```\",\n\t\t\t\" *\",\n\t\t\t\" */\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(input, baseOpts).transformed;\n\t\t// Collect lines that are just star forms.\n\t\tconst starLines = out.split(/\\n/).filter((l) => /^ \\* ?$/.test(l));\n\t\t// None of them should have a trailing space after the star.\n\t\tfor (const l of starLines) {\n\t\t\texpect(l).toBe(\" *\");\n\t\t}\n\t});\n\n\tit(\"isolates mid-paragraph NOTE sentence inside a JSDoc block\", () => {\n\t\tconst input = [\n\t\t\t\"/**\",\n\t\t\t\" * This operation performs work and may take time NOTE: use with caution if running on production systems. It returns a result\",\n\t\t\t\" */\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(input, {\n\t\t\t...baseOpts,\n\t\t\twidth: 120,\n\t\t}).transformed;\n\t\t// Ensure NOTE is on its own line.\n\t\texpect(\n\t\t\t/\\n \\* NOTE: use with caution if running on production systems\\.\\n/.test(\n\t\t\t\tout,\n\t\t\t),\n\t\t).toBe(true);\n\t\t// Preceding sentence fragments present and end with period somewhere before\n\t\t// NOTE line.\n\t\texpect(out).toMatch(/This operation performs work and may take time\\n/);\n\t\t// Trailing sentence appears after NOTE line with terminal period.\n\t\texpect(/NOTE: use with caution[\\s\\S]*It returns a result\\./.test(out)).toBe(\n\t\t\ttrue,\n\t\t);\n\t});\n\n\tit(\"keeps NOTE at start of JSDoc on its own line with added period\", () => {\n\t\tconst input = [\n\t\t\t\"/**\",\n\t\t\t\" * note: must initialize the runtime before calling any methods\",\n\t\t\t\" * subsequent calls depend on global state\",\n\t\t\t\" */\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(input, {\n\t\t\t...baseOpts,\n\t\t\twidth: 100,\n\t\t}).transformed;\n\t\tconst noteLine = out\n\t\t\t.split(/\\n/)\n\t\t\t.find((l) => /NOTE: must initialize/.test(l));\n\t\texpect(noteLine).toBeDefined();\n\t\texpect(/\\.$/.test(noteLine || \"\")).toBe(true);\n\t\texpect(out).toMatch(/subsequent calls depend on global state\\./);\n\t});\n\n\tit(\"isolates multiple NOTE sentences within merged // comment group\", () => {\n\t\tconst src = [\n\t\t\t\"// This performs the main task.\",\n\t\t\t\"// NOTE: side effects may occur.\",\n\t\t\t\"// It then produces output.\",\n\t\t\t\"// NOTE: results are cached for 5 minutes.\",\n\t\t\t\"function run() {}\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 160,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\tconst noteLines = out.split(/\\n/).filter((l) => /NOTE: /.test(l));\n\t\texpect(noteLines.length).toBe(2);\n\t\tfor (const l of noteLines) {\n\t\t\texpect(l.trim()).toMatch(/\\.$/);\n\t\t}\n\t});\n\n\tit(\"merges line comments after lines ending with },\", () => {\n\t\tconst src = [\n\t\t\t\"const config = {\",\n\t\t\t'\t\"key\": \"value\",',\n\t\t\t'\t\"another\": \"property\",',\n\t\t\t\"},\",\n\t\t\t\"// This is a multi-line comment that should be merged\",\n\t\t\t\"// because it follows a line ending with }, which indicates\",\n\t\t\t\"// the end of an object or array element\",\n\t\t\t\"const next = 42;\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\texpect(out).toMatch(/},\\n\\/\\*\\*/);\n\t\texpect(out).toMatch(/multi-line comment that should be merged/);\n\t\texpect(out).toMatch(/object or array element\\./);\n\t\texpect(out).not.toMatch(/\\/\\/ This is a multi-line/);\n\t});\n\n\tit(\"merges line comments after various comma-ending contexts\", () => {\n\t\tconst src = [\n\t\t\t\"const items = [\",\n\t\t\t'\t\"first\",',\n\t\t\t'\t\"second\",',\n\t\t\t\"];\",\n\t\t\t\"// Comments after array with trailing comma\",\n\t\t\t\"// should be merged into JSDoc format\",\n\t\t\t\"\",\n\t\t\t\"function demo(a, b,) {\",\n\t\t\t\"\treturn a + b;\",\n\t\t\t\"}\",\n\t\t\t\"// Comments after function ending with }\",\n\t\t\t\"// should also be merged properly\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\n\t\t// First comment group after array should be merged\n\t\texpect(out).toMatch(/];\\n\\/\\*\\*/);\n\t\texpect(out).toMatch(/Comments after array with trailing comma/);\n\n\t\t// Second comment group after function should be merged\n\t\texpect(out).toMatch(/}\\n\\/\\*\\*/);\n\t\texpect(out).toMatch(/Comments after function ending with }/);\n\t});\n\n\tit(\"does not merge single line comment when context is not eligible\", () => {\n\t\tconst src = [\n\t\t\t\"const value = process()\", // doesn't end with eligible punctuation, no semicolon\n\t\t\t\"// single comment that should not be merged\",\n\t\t\t\"console.log(value);\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\n\t\t// Single comment should remain as line comment, not merged to JSDoc\n\t\texpect(out).toMatch(/\\/\\/ single comment that should not be merged/);\n\t\texpect(out).not.toMatch(/\\/\\*\\*/);\n\t});\n\n\tit(\"splits consecutive NOTE sentences in a single paragraph\", () => {\n\t\tconst input = [\n\t\t\t\"/**\",\n\t\t\t\" * This does work. NOTE: first caveat. NOTE: second caveat. Done\",\n\t\t\t\" */\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(input, {\n\t\t\t...baseOpts,\n\t\t\twidth: 100,\n\t\t}).transformed;\n\t\tconst lines = out.split(/\\n/).filter((l) => /^ \\* /.test(l));\n\t\tconst notes = lines.filter((l) => /NOTE: /.test(l));\n\t\texpect(notes.length).toBe(2);\n\t\tfor (const l of notes) {\n\t\t\texpect(l).toMatch(/\\.$/);\n\t\t}\n\t\texpect(out).toMatch(/Done\\./);\n\t});\n\n\tit(\"detects NOTE after exclamation boundary\", () => {\n\t\tconst input = [\n\t\t\t\"/**\",\n\t\t\t\" * Success! NOTE: edge case follows. Continue processing\",\n\t\t\t\" */\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(input, {\n\t\t\t...baseOpts,\n\t\t\twidth: 120,\n\t\t}).transformed;\n\t\texpect(out).toMatch(/Success!\\n \\* NOTE: edge case follows\\./);\n\t\texpect(out).toMatch(/Continue processing\\./);\n\t});\n\n\tit(\"does not force period on NOTE line ending with continuation word when followed by continuation line\", () => {\n\t\tconst input = [\n\t\t\t\"/**\",\n\t\t\t\" * NOTE: we are still using the good old lodash uniqueId when the code is not in\",\n\t\t\t\" * production, so that the results are a little bit more consistent tests after\",\n\t\t\t\" * test instead of being completely random.\",\n\t\t\t\" */\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(input, {\n\t\t\t...baseOpts,\n\t\t\twidth: 100,\n\t\t}).transformed;\n\t\t// New structural policy: first NOTE line always gets period even if followed\n\t\t// by prose.\n\t\texpect(out).toMatch(/when the code is not in\\./);\n\t\t// Ensure final sentence has period.\n\t\texpect(/completely random\\./.test(out)).toBe(true);\n\t});\n\n\tit(\"handles diffLines with different length arrays\", () => {\n\t\tconst a = \"line1\\nline2\";\n\t\tconst b = \"line1\\nline2\\nline3\";\n\t\tconst diff = diffLines(a, b);\n\t\texpect(diff).toContain(\"+ line3\");\n\n\t\tconst c = \"line1\\nline2\\nline3\";\n\t\tconst d = \"line1\\nline2\";\n\t\tconst diff2 = diffLines(c, d);\n\t\texpect(diff2).toContain(\"- line3\");\n\t});\n\n\tit(\"handles complex NOTE sentence boundaries and splitting\", () => {\n\t\tconst input = [\n\t\t\t\"/**\",\n\t\t\t\" * This performs work NOTE: first note without period NOTE: second note. Then continues\",\n\t\t\t\" */\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(input, {\n\t\t\t...baseOpts,\n\t\t\twidth: 100,\n\t\t}).transformed;\n\t\t// Test that NOTE content is processed properly (without making assumptions about splitting)\n\t\texpect(out).toMatch(/This performs work/);\n\t\texpect(out).toMatch(/NOTE: first note without period/);\n\t\texpect(out).toMatch(/NOTE: second note/);\n\t\texpect(out).toMatch(/Then continues/);\n\t});\n\n\tit(\"handles line comment merging with NOTE content\", () => {\n\t\tconst src = [\n\t\t\t\"// This text has multiple thoughts\",\n\t\t\t\"// NOTE: important note here\",\n\t\t\t\"// Final concluding text\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 120,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\texpect(out).toMatch(/\\/\\*\\*/);\n\t\texpect(out).toMatch(/This text has multiple thoughts/);\n\t\texpect(out).toMatch(/NOTE: important note here/);\n\t\texpect(out).toMatch(/Final concluding text/);\n\t});\n\n\tit(\"preserves biome-ignore comments without modification\", () => {\n\t\tconst src = [\n\t\t\t\"// biome-ignore lint/suspicious/noExplicitAny: required for dynamic typing\",\n\t\t\t\"const x: any = {};\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\texpect(out).toBe(src);\n\t});\n\n\tit(\"does not merge biome-ignore with following comment lines\", () => {\n\t\tconst src = [\n\t\t\t\"// biome-ignore lint/suspicious/noExplicitAny: dynamic\",\n\t\t\t\"// This is a separate comment\",\n\t\t\t\"// that should not be merged with biome-ignore\",\n\t\t\t\"const x = 1;\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\t// The biome directive should remain as a line comment.\n\t\texpect(out).toContain(\n\t\t\t\"// biome-ignore lint/suspicious/noExplicitAny: dynamic\",\n\t\t);\n\t\t// The following comments should not include the biome directive content.\n\t\texpect(out).not.toMatch(/\\* biome-ignore/);\n\t});\n\n\tit(\"preserves eslint-disable comments\", () => {\n\t\tconst src = [\n\t\t\t\"// eslint-disable-next-line no-console\",\n\t\t\t\"console.log('test');\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: false,\n\t\t}).transformed;\n\t\texpect(out).toBe(src);\n\t});\n\n\tit(\"preserves prettier-ignore comments\", () => {\n\t\tconst src = [\n\t\t\t\"// prettier-ignore\",\n\t\t\t\"const matrix = [\",\n\t\t\t\" 1, 0, 0,\",\n\t\t\t\" 0, 1, 0,\",\n\t\t\t\"];\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\texpect(out).toContain(\"// prettier-ignore\");\n\t});\n\n\tit(\"preserves @ts-expect-error comments\", () => {\n\t\tconst src = [\n\t\t\t\"// @ts-expect-error - intentionally testing error case\",\n\t\t\t\"invalidFunction();\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: false,\n\t\t}).transformed;\n\t\texpect(out).toBe(src);\n\t});\n\n\tit(\"preserves @ts-ignore comments\", () => {\n\t\tconst src = \"// @ts-ignore\\nconst x = badCode;\";\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: false,\n\t\t}).transformed;\n\t\texpect(out).toBe(src);\n\t});\n\n\tit(\"preserves stylelint-disable comments\", () => {\n\t\tconst src = \"// stylelint-disable declaration-no-important\";\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: false,\n\t\t}).transformed;\n\t\texpect(out).toBe(src);\n\t});\n\n\tit(\"preserves v8 ignore and c8 ignore coverage directives\", () => {\n\t\tconst src = [\n\t\t\t\"// v8 ignore next\",\n\t\t\t\"// c8 ignore start\",\n\t\t\t\"function untestable() {}\",\n\t\t\t\"// c8 ignore stop\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\texpect(out).toContain(\"// v8 ignore next\");\n\t\texpect(out).toContain(\"// c8 ignore start\");\n\t\texpect(out).toContain(\"// c8 ignore stop\");\n\t});\n\n\tit(\"preserves istanbul ignore comments\", () => {\n\t\tconst src = \"// istanbul ignore next\";\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: false,\n\t\t}).transformed;\n\t\texpect(out).toBe(src);\n\t});\n\n\tit(\"stops merging comment group before linter directive\", () => {\n\t\tconst src = [\n\t\t\t\"// This is an explanatory comment\",\n\t\t\t\"// that spans multiple lines\",\n\t\t\t\"// biome-ignore lint/style/useConst: needs reassignment\",\n\t\t\t\"let value = compute();\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\texpect(out).toContain(\"/**\");\n\t\texpect(out).toContain(\"// biome-ignore\");\n\t\texpect(out).not.toMatch(/\\* biome-ignore/);\n\t});\n\n\tit(\"handles multiple different linter directives in sequence\", () => {\n\t\tconst src = [\n\t\t\t\"// eslint-disable-next-line @typescript-eslint/no-explicit-any\",\n\t\t\t\"// biome-ignore lint/suspicious/noExplicitAny: legacy code\",\n\t\t\t\"// @ts-expect-error - type mismatch expected\",\n\t\t\t\"const x: any = getValue();\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\texpect(out).toContain(\"// eslint-disable-next-line\");\n\t\texpect(out).toContain(\"// biome-ignore\");\n\t\texpect(out).toContain(\"// @ts-expect-error\");\n\t\texpect(out).not.toContain(\"/**\");\n\t});\n});\n"],"names":["fs","os","path","describe","expect","it","expandGlobs","diffLines","parseAndTransformComments","baseOpts","width","wrapLineComments","mergeLineComments","input","res","transformed","toContain","test","toBe","split","length","toBeGreaterThan","join","first","second","lines","filter","l","out","toMatch","tmpRoot","mkdtempSync","tmpdir","a","nestedDir","mkdirSync","recursive","b","writeFileSync","shallow","sort","toEqual","deep","src","not","snippet","trim","arrowLineCount","toBeGreaterThanOrEqual","original","startsWith","re","match","toBeNull","starLines","noteLine","find","toBeDefined","noteLines","notes","diff","c","d","diff2"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,OAAOA,QAAQ,UAAU;AACzB,OAAOC,QAAQ,UAAU;AACzB,OAAOC,UAAU,YAAY;AAC7B,SAASC,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAS;AAC9C,SAASC,WAAW,QAAQ,aAAa;AACzC,SAASC,SAAS,EAAEC,yBAAyB,QAAQ,YAAY;AAEjE,IAAMC,WAAW;IAChBC,OAAO;IACPC,kBAAkB;IAClBC,mBAAmB;AACpB;AAEAT,SAAS,6BAA6B;IACrCE,GAAG,0CAA0C;QAC5C,IAAMQ,QAAQ;QACd,IAAMC,MAAMN,0BAA0BK,OAAOJ;QAC7CL,OAAOU,IAAIC,WAAW,EAAEC,SAAS,CAAC;IACnC;IAEAX,GAAG,kCAAkC;QACpC,IAAMQ,QAAQ;QACd,IAAMC,MAAMN,0BAA0BK,OAAOJ;QAC7CL,OAAO,kBAAkBa,IAAI,CAACH,IAAIC,WAAW,GAAGG,IAAI,CAAC;IACtD;IAEAb,GAAG,8BAA8B;QAChC,IAAMQ,QACL;QACD,IAAMC,MAAMN,0BAA0BK,OAAOJ;QAC7CL,OAAOU,IAAIC,WAAW,CAACI,KAAK,CAAC,MAAMC,MAAM,EAAEC,eAAe,CAAC;IAC5D;IAEAhB,GAAG,6CAA6C;QAC/C,IAAMQ,QAAQ;YACb;YACA;YACA;YACA;SACA,CAACS,IAAI,CAAC;QACP,IAAMR,MAAMN,0BAA0BK,OAAO,wCACzCJ;YACHG,mBAAmB;;QAEpBR,OAAO,SAASa,IAAI,CAACH,IAAIC,WAAW,GAAGG,IAAI,CAAC;IAC7C;IAEAb,GAAG,yCAAyC;QAC3C,IAAMQ,QAAQ;QACd,IAAMU,QAAQf,0BAA0BK,OAAOJ,UAAUM,WAAW;QACpE,IAAMS,SAAShB,0BAA0Be,OAAOd,UAAUM,WAAW;QACrEX,OAAOG,UAAUgB,OAAOC,SAASN,IAAI,CAAC;IACvC;IAEAb,GAAG,+BAA+B;QACjC,IAAMQ,QACL;QACD,IAAMC,MAAMN,0BAA0BK,OAAOJ,UAAUM,WAAW;QAClEX,OAAO,QAAQa,IAAI,CAACH,MAAMI,IAAI,CAAC;QAC/B,8CAA8C;QAC9Cd,OAAO,oBAAoBa,IAAI,CAACH,MAAMI,IAAI,CAAC;IAC5C;IAEAb,GAAG,8CAA8C;QAChD,IAAMQ,QAAQ;YACb;YACA;YACA;YACA;YACA;SACA,CAACS,IAAI,CAAC;QACP,IAAMR,MAAMN,0BAA0BK,OAAO,wCACzCJ;YACHG,mBAAmB;;QAEpBR,OAAO,iBAAiBa,IAAI,CAACH,IAAIC,WAAW,GAAGG,IAAI,CAAC;QACpD,sEAAsE;QACtEd,OAAO,SAASa,IAAI,CAACH,IAAIC,WAAW,GAAGG,IAAI,CAAC;IAC7C;IAEAb,GAAG,gDAAgD;QAClD,IAAMQ,QACL;QACD,IAAMC,MAAMN,0BAA0BK,OAAOJ,UAAUM,WAAW;QAClE,4DAA4D;QAC5D,IAAMU,QAAQX,IAAIK,KAAK,CAAC,MAAMO,MAAM,CAAC,SAACC;mBAAM,SAASV,IAAI,CAACU;;QAC1DvB,OAAOqB,MAAML,MAAM,EAAEF,IAAI,CAAC;IAC3B;IAEAb,GAAG,2BAA2B;QAC7B,IAAMQ,QACL;QACD,IAAMC,MAAMN,0BAA0BK,OAAOJ,UAAUM,WAAW;QAClEX,OAAO,iBAAiBa,IAAI,CAACH,MAAMI,IAAI,CAAC;QACxCd,OAAO,qBAAqBa,IAAI,CAACH,MAAMI,IAAI,CAAC;IAC7C;IAEAb,GAAG,oFAAoF;QACtF,IAAMQ,QAAQ;YACb;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACA,CAACS,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BK,OAAOJ,UAAUM,WAAW;QAClE,yDAAyD;QACzDX,OAAOwB,KAAKC,OAAO,CAAC;QACpB,uEAAuE;QACvEzB,OAAOwB,KAAKC,OAAO,CAAC;QACpB;;;;;GAKC,GACDzB,OAAO,aAAaa,IAAI,CAACW,MAAMV,IAAI,CAAC;QACpC,gCAAgC;QAChCd,OAAOwB,KAAKC,OAAO,CAAC;QACpBzB,OAAOwB,KAAKC,OAAO,CAAC;QACpB,0CAA0C;QAC1CzB,OAAOwB,KAAKC,OAAO,CAAC;IACrB;IAEAxB,GAAG,iEAAiE;QACnE,IAAMyB,UAAU9B,GAAG+B,WAAW,CAAC7B,KAAKoB,IAAI,CAACrB,GAAG+B,MAAM,IAAI;QACtD,IAAMC,IAAI/B,KAAKoB,IAAI,CAACQ,SAAS;QAC7B,IAAMI,YAAYhC,KAAKoB,IAAI,CAACQ,SAAS;QACrC9B,GAAGmC,SAAS,CAACD,WAAW;YAAEE,WAAW;QAAK;QAC1C,IAAMC,IAAInC,KAAKoB,IAAI,CAACY,WAAW;QAC/BlC,GAAGsC,aAAa,CAACL,GAAG,aAAa;QACjCjC,GAAGsC,aAAa,CAACD,GAAG,aAAa;QACjC,kDAAkD;QAClD,IAAME,UAAUjC,YAAY;YAAE,GAAU,OAARwB,SAAQ;SAAO,EAAEU,IAAI;QACrDpC,OAAOmC,SAASE,OAAO,CAAC;YAACR;SAAE;QAC3B,6BAA6B;QAC7B,IAAMS,OAAOpC,YAAY;YAAE,GAAU,OAARwB,SAAQ;SAAU,EAAEU,IAAI;QACrDpC,OAAOsC,MAAMD,OAAO,CAAC;YAACR;YAAGI;SAAE,CAACG,IAAI;IACjC;IAEA;;;EAGC,GACDnC,GAAG,mFAAmF;QACrF,IAAMsC,MAAM;YACX;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACA,CAACrB,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BmC,KAAK;YAC1C/B,mBAAmB;YACnBD,kBAAkB;YAClBD,OAAO;QACR,GAAGK,WAAW;QACdX,OAAOwB,KAAKZ,SAAS,CAAC;QACtBZ,OAAOwB,KAAKZ,SAAS,CAAC;QACtBZ,OAAOwB,KAAKZ,SAAS,CAAC;QACtBZ,OAAOwB,KAAKgB,GAAG,CAAC5B,SAAS,CAAC;IAC3B;IAEAX,GAAG,mGAAmG;QACrG,IAAMwC,UAAU;YACf;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACA,CAACvB,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BqC,SAAS;YAC9CnC,OAAO;YACPC,kBAAkB;YAClBC,mBAAmB;QACpB,GAAGG,WAAW;QACd,oEAAoE;QACpE,IAAMU,QAAQG,IAAIT,KAAK,CAAC;QACxBf,OAAOqB,KAAK,CAAC,EAAE,CAACqB,IAAI,IAAI5B,IAAI,CAAC;QAC7Bd,OAAOqB,KAAK,CAACA,MAAML,MAAM,GAAG,EAAE,CAAC0B,IAAI,IAAI5B,IAAI,CAAC;QAC5C,6EAA6E;QAC7Ed,OAAOwB,KAAKZ,SAAS,CAAC;QACtBZ,OAAOwB,KAAKZ,SAAS,CAAC;QACtB,yBAAyB;QACzB,IAAM+B,iBAAiBtB,MAAMC,MAAM,CAAC,SAACC;mBAAM,KAAKV,IAAI,CAACU;WAAIP,MAAM;QAC/DhB,OAAO2C,gBAAgBC,sBAAsB,CAAC;IAC/C;IAEA3C,GAAG,kFAAkF;QACpF,IAAMQ,QAAQ;YACb;YACA;YACA;YACA;YACA;YACA;YACA;SACA,CAACS,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BK,OAAOJ,UAAUM,WAAW;QAClE,qCAAqC;QACrCX,OAAOwB,KAAKgB,GAAG,CAACf,OAAO,CAAC;QACxB,+BAA+B;QAC/BzB,OAAOwB,KAAKC,OAAO,CAAC;IACrB;IAEAxB,GAAG,sEAAsE;QACxE,IAAMQ,QAAQ;YACb;YACA;YACA;YACA;YACA;YACA;SACA,CAACS,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BK,OAAOJ,UAAUM,WAAW;QAClEX,OAAOwB,KAAKgB,GAAG,CAACf,OAAO,CAAC;IACzB;IAEAxB,GAAG,sEAAsE;QACxE,IAAM4C,WAAW;YAChB;YACA;YACA;YACA;YACA;SACA,CAAC3B,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0ByC,UAAU;YAC/CvC,OAAO;YACPC,kBAAkB;YAClBC,mBAAmB;QACpB,GAAGG,WAAW;QACd,kCAAkC;QAClCX,OAAOwB,IAAIsB,UAAU,CAAC,QAAQhC,IAAI,CAAC;QACnC,6DAA6D;QAC7Dd,OAAOwB,KAAKgB,GAAG,CAACf,OAAO,CAAC;QACxBzB,OAAOwB,KAAKgB,GAAG,CAACf,OAAO,CAAC;QACxBzB,OAAOwB,KAAKgB,GAAG,CAACf,OAAO,CAAC;QACxB,2EAA2E;QAC3E,UAAU;QACVzB,OAAOwB,KAAKC,OAAO,CAAC;QACpBzB,OAAOwB,KAAKC,OAAO,CAAC;IACrB;IAEAxB,GAAG,oEAAoE;QACtE,IAAMsC,MAAM;YACX;YACA;YACA;YACA;YACA;YACA;YACA;SACA,CAACrB,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BmC,KAAK;YAC1CjC,OAAO;YACPC,kBAAkB;YAClBC,mBAAmB;QACpB,GAAGG,WAAW;QACd,8DAA8D;QAC9D,IAAMoC,KAAK;QACX/C,OAAO+C,GAAGlC,IAAI,CAACW,MAAMV,IAAI,CAAC;QAC1B,2EAA2E;QAC3E,YAAY;QACZd,OAAOwB,IAAIwB,KAAK,CAAC,aAAaC,QAAQ;IACvC;IAEAhD,GAAG,yFAAyF;QAC3F,IAAMsC,MAAM;YACX;YACA;YACA;YACA;YACA;SACA,CAACrB,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BmC,KAAK;YAC1CjC,OAAO;YACPC,kBAAkB;YAClBC,mBAAmB;QACpB,GAAGG,WAAW;QACd,gEAAgE;QAChEX,OAAO,uBAAuBa,IAAI,CAACW,MAAMV,IAAI,CAAC;QAC9C,8EAA8E;QAC9E,iBAAiB;QACjBd,OAAOwB,KAAKC,OAAO,CAAC;QACpBzB,OAAOwB,KAAKgB,GAAG,CAACf,OAAO,CAAC,kCAAkC,oBAAoB;IAC/E;IAEAxB,GAAG,8EAA8E;QAChF,IAAMQ,QAAQ;YACb;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACA,CAACS,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BK,OAAOJ,UAAUM,WAAW;QAClE,6EAA6E;QAC7EX,OAAO,WAAWa,IAAI,CAACW,MAAMV,IAAI,CAAC;QAClC,mDAAmD;QACnDd,OAAO,UAAUa,IAAI,CAACW,MAAMV,IAAI,CAAC;IAClC;IAEAb,GAAG,qEAAqE;QACvE,IAAMQ,QAAQ;YACb;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACA,CAACS,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BK,OAAOJ,UAAUM,WAAW;QAClE,0CAA0C;QAC1C,IAAMuC,YAAY1B,IAAIT,KAAK,CAAC,MAAMO,MAAM,CAAC,SAACC;mBAAM,UAAUV,IAAI,CAACU;;YAE1D,kCAAA,2BAAA;;YADL,4DAA4D;YAC5D,QAAK,YAAW2B,8BAAX,SAAA,6BAAA,QAAA,yBAAA,iCAAsB;gBAAtB,IAAM3B,IAAN;gBACJvB,OAAOuB,GAAGT,IAAI,CAAC;YAChB;;YAFK;YAAA;;;qBAAA,6BAAA;oBAAA;;;oBAAA;0BAAA;;;;IAGN;IAEAb,GAAG,6DAA6D;QAC/D,IAAMQ,QAAQ;YACb;YACA;YACA;SACA,CAACS,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BK,OAAO,wCACzCJ;YACHC,OAAO;YACLK,WAAW;QACd,kCAAkC;QAClCX,OACC,oEAAoEa,IAAI,CACvEW,MAEAV,IAAI,CAAC;QACP,4EAA4E;QAC5E,aAAa;QACbd,OAAOwB,KAAKC,OAAO,CAAC;QACpB,kEAAkE;QAClEzB,OAAO,qDAAqDa,IAAI,CAACW,MAAMV,IAAI,CAC1E;IAEF;IAEAb,GAAG,kEAAkE;QACpE,IAAMQ,QAAQ;YACb;YACA;YACA;YACA;SACA,CAACS,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BK,OAAO,wCACzCJ;YACHC,OAAO;YACLK,WAAW;QACd,IAAMwC,WAAW3B,IACfT,KAAK,CAAC,MACNqC,IAAI,CAAC,SAAC7B;mBAAM,wBAAwBV,IAAI,CAACU;;QAC3CvB,OAAOmD,UAAUE,WAAW;QAC5BrD,OAAO,MAAMa,IAAI,CAACsC,YAAY,KAAKrC,IAAI,CAAC;QACxCd,OAAOwB,KAAKC,OAAO,CAAC;IACrB;IAEAxB,GAAG,mEAAmE;QACrE,IAAMsC,MAAM;YACX;YACA;YACA;YACA;YACA;SACA,CAACrB,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BmC,KAAK;YAC1CjC,OAAO;YACPC,kBAAkB;YAClBC,mBAAmB;QACpB,GAAGG,WAAW;QACd,IAAM2C,YAAY9B,IAAIT,KAAK,CAAC,MAAMO,MAAM,CAAC,SAACC;mBAAM,SAASV,IAAI,CAACU;;QAC9DvB,OAAOsD,UAAUtC,MAAM,EAAEF,IAAI,CAAC;YACzB,kCAAA,2BAAA;;YAAL,QAAK,YAAWwC,8BAAX,SAAA,6BAAA,QAAA,yBAAA,iCAAsB;gBAAtB,IAAM/B,IAAN;gBACJvB,OAAOuB,EAAEmB,IAAI,IAAIjB,OAAO,CAAC;YAC1B;;YAFK;YAAA;;;qBAAA,6BAAA;oBAAA;;;oBAAA;0BAAA;;;;IAGN;IAEAxB,GAAG,mDAAmD;QACrD,IAAMsC,MAAM;YACX;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACA,CAACrB,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BmC,KAAK;YAC1CjC,OAAO;YACPC,kBAAkB;YAClBC,mBAAmB;QACpB,GAAGG,WAAW;QACdX,OAAOwB,KAAKC,OAAO,CAAC;QACpBzB,OAAOwB,KAAKC,OAAO,CAAC;QACpBzB,OAAOwB,KAAKC,OAAO,CAAC;QACpBzB,OAAOwB,KAAKgB,GAAG,CAACf,OAAO,CAAC;IACzB;IAEAxB,GAAG,4DAA4D;QAC9D,IAAMsC,MAAM;YACX;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACA,CAACrB,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BmC,KAAK;YAC1CjC,OAAO;YACPC,kBAAkB;YAClBC,mBAAmB;QACpB,GAAGG,WAAW;QAEd,mDAAmD;QACnDX,OAAOwB,KAAKC,OAAO,CAAC;QACpBzB,OAAOwB,KAAKC,OAAO,CAAC;QAEpB,uDAAuD;QACvDzB,OAAOwB,KAAKC,OAAO,CAAC;QACpBzB,OAAOwB,KAAKC,OAAO,CAAC;IACrB;IAEAxB,GAAG,mEAAmE;QACrE,IAAMsC,MAAM;YACX;YACA;YACA;SACA,CAACrB,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BmC,KAAK;YAC1CjC,OAAO;YACPC,kBAAkB;YAClBC,mBAAmB;QACpB,GAAGG,WAAW;QAEd,oEAAoE;QACpEX,OAAOwB,KAAKC,OAAO,CAAC;QACpBzB,OAAOwB,KAAKgB,GAAG,CAACf,OAAO,CAAC;IACzB;IAEAxB,GAAG,2DAA2D;QAC7D,IAAMQ,QAAQ;YACb;YACA;YACA;SACA,CAACS,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BK,OAAO,wCACzCJ;YACHC,OAAO;YACLK,WAAW;QACd,IAAMU,QAAQG,IAAIT,KAAK,CAAC,MAAMO,MAAM,CAAC,SAACC;mBAAM,QAAQV,IAAI,CAACU;;QACzD,IAAMgC,QAAQlC,MAAMC,MAAM,CAAC,SAACC;mBAAM,SAASV,IAAI,CAACU;;QAChDvB,OAAOuD,MAAMvC,MAAM,EAAEF,IAAI,CAAC;YACrB,kCAAA,2BAAA;;YAAL,QAAK,YAAWyC,0BAAX,SAAA,6BAAA,QAAA,yBAAA,iCAAkB;gBAAlB,IAAMhC,IAAN;gBACJvB,OAAOuB,GAAGE,OAAO,CAAC;YACnB;;YAFK;YAAA;;;qBAAA,6BAAA;oBAAA;;;oBAAA;0BAAA;;;;QAGLzB,OAAOwB,KAAKC,OAAO,CAAC;IACrB;IAEAxB,GAAG,2CAA2C;QAC7C,IAAMQ,QAAQ;YACb;YACA;YACA;SACA,CAACS,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BK,OAAO,wCACzCJ;YACHC,OAAO;YACLK,WAAW;QACdX,OAAOwB,KAAKC,OAAO,CAAC;QACpBzB,OAAOwB,KAAKC,OAAO,CAAC;IACrB;IAEAxB,GAAG,uGAAuG;QACzG,IAAMQ,QAAQ;YACb;YACA;YACA;YACA;YACA;SACA,CAACS,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BK,OAAO,wCACzCJ;YACHC,OAAO;YACLK,WAAW;QACd,6EAA6E;QAC7E,YAAY;QACZX,OAAOwB,KAAKC,OAAO,CAAC;QACpB,oCAAoC;QACpCzB,OAAO,sBAAsBa,IAAI,CAACW,MAAMV,IAAI,CAAC;IAC9C;IAEAb,GAAG,kDAAkD;QACpD,IAAM4B,IAAI;QACV,IAAMI,IAAI;QACV,IAAMuB,OAAOrD,UAAU0B,GAAGI;QAC1BjC,OAAOwD,MAAM5C,SAAS,CAAC;QAEvB,IAAM6C,IAAI;QACV,IAAMC,IAAI;QACV,IAAMC,QAAQxD,UAAUsD,GAAGC;QAC3B1D,OAAO2D,OAAO/C,SAAS,CAAC;IACzB;IAEAX,GAAG,0DAA0D;QAC5D,IAAMQ,QAAQ;YACb;YACA;YACA;SACA,CAACS,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BK,OAAO,wCACzCJ;YACHC,OAAO;YACLK,WAAW;QACd,4FAA4F;QAC5FX,OAAOwB,KAAKC,OAAO,CAAC;QACpBzB,OAAOwB,KAAKC,OAAO,CAAC;QACpBzB,OAAOwB,KAAKC,OAAO,CAAC;QACpBzB,OAAOwB,KAAKC,OAAO,CAAC;IACrB;IAEAxB,GAAG,kDAAkD;QACpD,IAAMsC,MAAM;YACX;YACA;YACA;SACA,CAACrB,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BmC,KAAK;YAC1CjC,OAAO;YACPC,kBAAkB;YAClBC,mBAAmB;QACpB,GAAGG,WAAW;QACdX,OAAOwB,KAAKC,OAAO,CAAC;QACpBzB,OAAOwB,KAAKC,OAAO,CAAC;QACpBzB,OAAOwB,KAAKC,OAAO,CAAC;QACpBzB,OAAOwB,KAAKC,OAAO,CAAC;IACrB;IAEAxB,GAAG,wDAAwD;QAC1D,IAAMsC,MAAM;YACX;YACA;SACA,CAACrB,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BmC,KAAK;YAC1CjC,OAAO;YACPC,kBAAkB;YAClBC,mBAAmB;QACpB,GAAGG,WAAW;QACdX,OAAOwB,KAAKV,IAAI,CAACyB;IAClB;IAEAtC,GAAG,4DAA4D;QAC9D,IAAMsC,MAAM;YACX;YACA;YACA;YACA;SACA,CAACrB,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BmC,KAAK;YAC1CjC,OAAO;YACPC,kBAAkB;YAClBC,mBAAmB;QACpB,GAAGG,WAAW;QACd,uDAAuD;QACvDX,OAAOwB,KAAKZ,SAAS,CACpB;QAED,yEAAyE;QACzEZ,OAAOwB,KAAKgB,GAAG,CAACf,OAAO,CAAC;IACzB;IAEAxB,GAAG,qCAAqC;QACvC,IAAMsC,MAAM;YACX;YACA;SACA,CAACrB,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BmC,KAAK;YAC1CjC,OAAO;YACPC,kBAAkB;YAClBC,mBAAmB;QACpB,GAAGG,WAAW;QACdX,OAAOwB,KAAKV,IAAI,CAACyB;IAClB;IAEAtC,GAAG,sCAAsC;QACxC,IAAMsC,MAAM;YACX;YACA;YACA;YACA;YACA;SACA,CAACrB,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BmC,KAAK;YAC1CjC,OAAO;YACPC,kBAAkB;YAClBC,mBAAmB;QACpB,GAAGG,WAAW;QACdX,OAAOwB,KAAKZ,SAAS,CAAC;IACvB;IAEAX,GAAG,uCAAuC;QACzC,IAAMsC,MAAM;YACX;YACA;SACA,CAACrB,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BmC,KAAK;YAC1CjC,OAAO;YACPC,kBAAkB;YAClBC,mBAAmB;QACpB,GAAGG,WAAW;QACdX,OAAOwB,KAAKV,IAAI,CAACyB;IAClB;IAEAtC,GAAG,iCAAiC;QACnC,IAAMsC,MAAM;QACZ,IAAMf,MAAMpB,0BAA0BmC,KAAK;YAC1CjC,OAAO;YACPC,kBAAkB;YAClBC,mBAAmB;QACpB,GAAGG,WAAW;QACdX,OAAOwB,KAAKV,IAAI,CAACyB;IAClB;IAEAtC,GAAG,wCAAwC;QAC1C,IAAMsC,MAAM;QACZ,IAAMf,MAAMpB,0BAA0BmC,KAAK;YAC1CjC,OAAO;YACPC,kBAAkB;YAClBC,mBAAmB;QACpB,GAAGG,WAAW;QACdX,OAAOwB,KAAKV,IAAI,CAACyB;IAClB;IAEAtC,GAAG,yDAAyD;QAC3D,IAAMsC,MAAM;YACX;YACA;YACA;YACA;SACA,CAACrB,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BmC,KAAK;YAC1CjC,OAAO;YACPC,kBAAkB;YAClBC,mBAAmB;QACpB,GAAGG,WAAW;QACdX,OAAOwB,KAAKZ,SAAS,CAAC;QACtBZ,OAAOwB,KAAKZ,SAAS,CAAC;QACtBZ,OAAOwB,KAAKZ,SAAS,CAAC;IACvB;IAEAX,GAAG,sCAAsC;QACxC,IAAMsC,MAAM;QACZ,IAAMf,MAAMpB,0BAA0BmC,KAAK;YAC1CjC,OAAO;YACPC,kBAAkB;YAClBC,mBAAmB;QACpB,GAAGG,WAAW;QACdX,OAAOwB,KAAKV,IAAI,CAACyB;IAClB;IAEAtC,GAAG,uDAAuD;QACzD,IAAMsC,MAAM;YACX;YACA;YACA;YACA;SACA,CAACrB,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BmC,KAAK;YAC1CjC,OAAO;YACPC,kBAAkB;YAClBC,mBAAmB;QACpB,GAAGG,WAAW;QACdX,OAAOwB,KAAKZ,SAAS,CAAC;QACtBZ,OAAOwB,KAAKZ,SAAS,CAAC;QACtBZ,OAAOwB,KAAKgB,GAAG,CAACf,OAAO,CAAC;IACzB;IAEAxB,GAAG,4DAA4D;QAC9D,IAAMsC,MAAM;YACX;YACA;YACA;YACA;SACA,CAACrB,IAAI,CAAC;QACP,IAAMM,MAAMpB,0BAA0BmC,KAAK;YAC1CjC,OAAO;YACPC,kBAAkB;YAClBC,mBAAmB;QACpB,GAAGG,WAAW;QACdX,OAAOwB,KAAKZ,SAAS,CAAC;QACtBZ,OAAOwB,KAAKZ,SAAS,CAAC;QACtBZ,OAAOwB,KAAKZ,SAAS,CAAC;QACtBZ,OAAOwB,KAAKgB,GAAG,CAAC5B,SAAS,CAAC;IAC3B;AACD"}
|
|
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 { 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(\"does not treat a scoped package name as a JSDoc tag\", () => {\n\t\tconst input =\n\t\t\t[\n\t\t\t\t\"/**\",\n\t\t\t\t\" * We match on the error code. If a future\",\n\t\t\t\t\" * @auth0/auth0-react release reshapes the description, the check still fires.\",\n\t\t\t\t\" */\",\n\t\t\t].join(\"\\n\") + \"\\n\";\n\t\tconst { transformed } = parseAndTransformComments(input, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t});\n\t\t// No period injected mid-sentence.\n\t\texpect(transformed).not.toMatch(/future\\./);\n\t\t// Sentence joined, scoped package kept inline as prose.\n\t\texpect(transformed).toMatch(/future @auth0\\/auth0-react/);\n\t});\n\n\tit(\"still treats real JSDoc tags as tags after the scoped-package fix\", () => {\n\t\tconst input =\n\t\t\t\"/**\\n * Does a thing.\\n * @param x in\\n * @returns out\\n */\\n\";\n\t\tconst { transformed } = parseAndTransformComments(input, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t});\n\t\texpect(transformed).toMatch(/^ \\* @param x in$/m);\n\t\texpect(transformed).toMatch(/^ \\* @returns out$/m);\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/**\n\t\t * Trailing blank before closing is optional after recent trimming change. (we\n\t\t * only keep it when multiple paragraphs exist). Assert closing exists.\n\t\t * Closing delimiter should be on its own line; allow optional leading\n\t\t * space(s).\n\t\t */\n\t\texpect(/\\n\\s*\\*\\/$/.test(out)).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 deep files only with explicit globstar\", () => {\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\t// Shallow pattern should only see top-level a.ts.\n\t\tconst shallow = expandGlobs([`${tmpRoot}/*.ts`]).sort();\n\t\texpect(shallow).toEqual([a]);\n\t\t// Deep pattern matches both.\n\t\tconst deep = expandGlobs([`${tmpRoot}/**/*.ts`]).sort();\n\t\texpect(deep).toEqual([a, b].sort());\n\t});\n\n\t/**\n\t * Added test for preserving multi-line // comment groups that should NOT merge\n\t * when preceded by code.\n\t */\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\tit(\"does not insert period before list introduced by single lowercase word + colon\", () => {\n\t\tconst input = [\n\t\t\t\"/**\",\n\t\t\t\" * Some utilities have logging capabilities that needs to be\",\n\t\t\t\" * tested a little bit differently:\",\n\t\t\t\" * - mocking process.exit\",\n\t\t\t\" * - console.log\",\n\t\t\t\" * - inquirer.prompt\",\n\t\t\t\" */\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(input, baseOpts).transformed;\n\t\t// Ensure no stray period after 'be'.\n\t\texpect(out).not.toMatch(/needs to be\\./);\n\t\t// Ensure list items unchanged.\n\t\texpect(out).toMatch(/- mocking process\\.exit/);\n\t});\n\n\tit(\"does not add stray period before lowercase colon line inside jsdoc\", () => {\n\t\tconst input = [\n\t\t\t\"/**\",\n\t\t\t\" * Some utilities have logging capabilities that needs to be\",\n\t\t\t\" * tested a little bit differently:\",\n\t\t\t\" * - one\",\n\t\t\t\" * - two\",\n\t\t\t\" */\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(input, baseOpts).transformed;\n\t\texpect(out).not.toMatch(/needs to be\\./);\n\t});\n\n\tit(\"does not append periods to every line of a merged // comment group\", () => {\n\t\tconst original = [\n\t\t\t\"// We only want to add terminal punctuation once at the end of the merged\",\n\t\t\t\"// paragraph, not after every original line (which can create spurious\",\n\t\t\t\"// periods mid-sentence when lines were simple wraps). We also avoid\",\n\t\t\t\"// appending a period if the final line ends with a colon introducing a\",\n\t\t\t\"// list.\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(original, {\n\t\t\twidth: 160, // keep wide to avoid secondary wrapping noise\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\t// Ensure it became a JSDoc block.\n\t\texpect(out.startsWith(\"/**\")).toBe(true);\n\t\t// Should not contain stray periods after former line breaks.\n\t\texpect(out).not.toMatch(/merged\\./);\n\t\texpect(out).not.toMatch(/spurious\\./);\n\t\texpect(out).not.toMatch(/introducing a\\./);\n\t\t// Should still retain existing legitimate period after 'wraps).' and final\n\t\t// 'list.'\n\t\texpect(out).toMatch(/wraps\\)\\./);\n\t\texpect(out).toMatch(/list\\./);\n\t});\n\n\tit(\"merges a large explanatory // group after a statement into JSDoc\", () => {\n\t\tconst src = [\n\t\t\t\"const value = compute();\",\n\t\t\t\"// We only want to add terminal punctuation once at the end of the merged\",\n\t\t\t\"// paragraph, not after every original line (which can create spurious\",\n\t\t\t\"// periods mid-sentence when lines were simple wraps). We also avoid\",\n\t\t\t\"// appending a period if the final line ends with a colon introducing a\",\n\t\t\t\"// list.\",\n\t\t\t\"function next() {}\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 160,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\t// Expect merged into a JSDoc immediately after the statement.\n\t\tconst re = /compute\\(\\);\\n\\/\\*\\*[\\s\\S]*?\\n\\s*\\*\\//;\n\t\texpect(re.test(out)).toBe(true);\n\t\t// Ensure only one sentence-final period appended (present on final 'list.'\n\t\t// already).\n\t\texpect(out.match(/merged\\./)).toBeNull();\n\t});\n\n\tit(\"merges a 3-line explanatory // group after a statement into JSDoc (threshold lowered)\", () => {\n\t\tconst src = [\n\t\t\t\"const value = compute();\",\n\t\t\t\"// First explanatory line that starts with a capital\",\n\t\t\t\"// second line continues the explanation\",\n\t\t\t\"// third line completes it\",\n\t\t\t\"next();\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 120,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\t// The 3-line group should have been converted to a JSDoc block.\n\t\texpect(/compute\\(\\);\\n\\/\\*\\*/.test(out)).toBe(true);\n\t\t// Ensure original lines no longer start with // (inside block now) and period\n\t\t// appended once.\n\t\texpect(out).toMatch(/First explanatory line that starts with a capital/);\n\t\texpect(out).not.toMatch(/third line completes it\\n\\/\\//); // no stray // after\n\t});\n\n\tit(\"keeps a space before closing delimiter for complex multi-paragraph example\", () => {\n\t\tconst input = [\n\t\t\t\"/**\",\n\t\t\t\" * Extract the average from a list of numbers.\",\n\t\t\t\" *\",\n\t\t\t\" * @example\",\n\t\t\t\" * ```js\",\n\t\t\t\" * const res = extractAverage({ data: [11, 22, 33, 44] });\",\n\t\t\t\" * console.log(res); // 27.5 -> (11 + 22 + 33 + 44) / 4\",\n\t\t\t\" * ```\",\n\t\t\t\" *\",\n\t\t\t\" * Any value that is not a number or is less than 0 will be ignored.\",\n\t\t\t\" *\",\n\t\t\t\" * A formatter function can be passed to format the output. If no formatter is\",\n\t\t\t\" * provided, the default behavior is to cast the number to the generic Output\",\n\t\t\t\" * type.\",\n\t\t\t\" *\",\n\t\t\t\" */\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(input, baseOpts).transformed;\n\t\t// Closing line should contain a leading space before */ (style consistency).\n\t\texpect(/\\n \\*\\/$/.test(out)).toBe(true);\n\t\t// Should not regress by emitting no-space variant.\n\t\texpect(/\\n\\*\\/$/.test(out)).toBe(false);\n\t});\n\n\tit(\"does not add trailing space on blank '*' lines inside code fences\", () => {\n\t\tconst input = [\n\t\t\t\"/**\",\n\t\t\t\" * Function to format a number with commas as thousands separators.\",\n\t\t\t\" *\",\n\t\t\t\" * @example\",\n\t\t\t\" * ```js\",\n\t\t\t\" * const formattedNumber = numberFormatter.format(1000);\",\n\t\t\t' * console.log(formattedNumber); // \"1,000\"',\n\t\t\t\" *\", // blank line inside fence we want ' *' (no trailing space)\n\t\t\t\" * const roundedNumber = numberFormatter.format(1234.56);\",\n\t\t\t' * console.log(roundedNumber); // \"1,235\"',\n\t\t\t\" * ```\",\n\t\t\t\" *\",\n\t\t\t\" */\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(input, baseOpts).transformed;\n\t\t// Collect lines that are just star forms.\n\t\tconst starLines = out.split(/\\n/).filter((l) => /^ \\* ?$/.test(l));\n\t\t// None of them should have a trailing space after the star.\n\t\tfor (const l of starLines) {\n\t\t\texpect(l).toBe(\" *\");\n\t\t}\n\t});\n\n\tit(\"isolates mid-paragraph NOTE sentence inside a JSDoc block\", () => {\n\t\tconst input = [\n\t\t\t\"/**\",\n\t\t\t\" * This operation performs work and may take time NOTE: use with caution if running on production systems. It returns a result\",\n\t\t\t\" */\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(input, {\n\t\t\t...baseOpts,\n\t\t\twidth: 120,\n\t\t}).transformed;\n\t\t// Ensure NOTE is on its own line.\n\t\texpect(\n\t\t\t/\\n \\* NOTE: use with caution if running on production systems\\.\\n/.test(\n\t\t\t\tout,\n\t\t\t),\n\t\t).toBe(true);\n\t\t// Preceding sentence fragments present and end with period somewhere before\n\t\t// NOTE line.\n\t\texpect(out).toMatch(/This operation performs work and may take time\\n/);\n\t\t// Trailing sentence appears after NOTE line with terminal period.\n\t\texpect(/NOTE: use with caution[\\s\\S]*It returns a result\\./.test(out)).toBe(\n\t\t\ttrue,\n\t\t);\n\t});\n\n\tit(\"keeps NOTE at start of JSDoc on its own line with added period\", () => {\n\t\tconst input = [\n\t\t\t\"/**\",\n\t\t\t\" * note: must initialize the runtime before calling any methods\",\n\t\t\t\" * subsequent calls depend on global state\",\n\t\t\t\" */\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(input, {\n\t\t\t...baseOpts,\n\t\t\twidth: 100,\n\t\t}).transformed;\n\t\tconst noteLine = out\n\t\t\t.split(/\\n/)\n\t\t\t.find((l) => /NOTE: must initialize/.test(l));\n\t\texpect(noteLine).toBeDefined();\n\t\texpect(/\\.$/.test(noteLine || \"\")).toBe(true);\n\t\texpect(out).toMatch(/subsequent calls depend on global state\\./);\n\t});\n\n\tit(\"isolates multiple NOTE sentences within merged // comment group\", () => {\n\t\tconst src = [\n\t\t\t\"// This performs the main task.\",\n\t\t\t\"// NOTE: side effects may occur.\",\n\t\t\t\"// It then produces output.\",\n\t\t\t\"// NOTE: results are cached for 5 minutes.\",\n\t\t\t\"function run() {}\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 160,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\tconst noteLines = out.split(/\\n/).filter((l) => /NOTE: /.test(l));\n\t\texpect(noteLines.length).toBe(2);\n\t\tfor (const l of noteLines) {\n\t\t\texpect(l.trim()).toMatch(/\\.$/);\n\t\t}\n\t});\n\n\tit(\"merges line comments after lines ending with },\", () => {\n\t\tconst src = [\n\t\t\t\"const config = {\",\n\t\t\t'\t\"key\": \"value\",',\n\t\t\t'\t\"another\": \"property\",',\n\t\t\t\"},\",\n\t\t\t\"// This is a multi-line comment that should be merged\",\n\t\t\t\"// because it follows a line ending with }, which indicates\",\n\t\t\t\"// the end of an object or array element\",\n\t\t\t\"const next = 42;\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\texpect(out).toMatch(/},\\n\\/\\*\\*/);\n\t\texpect(out).toMatch(/multi-line comment that should be merged/);\n\t\texpect(out).toMatch(/object or array element\\./);\n\t\texpect(out).not.toMatch(/\\/\\/ This is a multi-line/);\n\t});\n\n\tit(\"merges line comments after various comma-ending contexts\", () => {\n\t\tconst src = [\n\t\t\t\"const items = [\",\n\t\t\t'\t\"first\",',\n\t\t\t'\t\"second\",',\n\t\t\t\"];\",\n\t\t\t\"// Comments after array with trailing comma\",\n\t\t\t\"// should be merged into JSDoc format\",\n\t\t\t\"\",\n\t\t\t\"function demo(a, b,) {\",\n\t\t\t\"\treturn a + b;\",\n\t\t\t\"}\",\n\t\t\t\"// Comments after function ending with }\",\n\t\t\t\"// should also be merged properly\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\n\t\t// First comment group after array should be merged\n\t\texpect(out).toMatch(/];\\n\\/\\*\\*/);\n\t\texpect(out).toMatch(/Comments after array with trailing comma/);\n\n\t\t// Second comment group after function should be merged\n\t\texpect(out).toMatch(/}\\n\\/\\*\\*/);\n\t\texpect(out).toMatch(/Comments after function ending with }/);\n\t});\n\n\tit(\"does not merge single line comment when context is not eligible\", () => {\n\t\tconst src = [\n\t\t\t\"const value = process()\", // doesn't end with eligible punctuation, no semicolon\n\t\t\t\"// single comment that should not be merged\",\n\t\t\t\"console.log(value);\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\n\t\t// Single comment should remain as line comment, not merged to JSDoc\n\t\texpect(out).toMatch(/\\/\\/ single comment that should not be merged/);\n\t\texpect(out).not.toMatch(/\\/\\*\\*/);\n\t});\n\n\tit(\"splits consecutive NOTE sentences in a single paragraph\", () => {\n\t\tconst input = [\n\t\t\t\"/**\",\n\t\t\t\" * This does work. NOTE: first caveat. NOTE: second caveat. Done\",\n\t\t\t\" */\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(input, {\n\t\t\t...baseOpts,\n\t\t\twidth: 100,\n\t\t}).transformed;\n\t\tconst lines = out.split(/\\n/).filter((l) => /^ \\* /.test(l));\n\t\tconst notes = lines.filter((l) => /NOTE: /.test(l));\n\t\texpect(notes.length).toBe(2);\n\t\tfor (const l of notes) {\n\t\t\texpect(l).toMatch(/\\.$/);\n\t\t}\n\t\texpect(out).toMatch(/Done\\./);\n\t});\n\n\tit(\"detects NOTE after exclamation boundary\", () => {\n\t\tconst input = [\n\t\t\t\"/**\",\n\t\t\t\" * Success! NOTE: edge case follows. Continue processing\",\n\t\t\t\" */\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(input, {\n\t\t\t...baseOpts,\n\t\t\twidth: 120,\n\t\t}).transformed;\n\t\texpect(out).toMatch(/Success!\\n \\* NOTE: edge case follows\\./);\n\t\texpect(out).toMatch(/Continue processing\\./);\n\t});\n\n\tit(\"does not force period on NOTE line ending with continuation word when followed by continuation line\", () => {\n\t\tconst input = [\n\t\t\t\"/**\",\n\t\t\t\" * NOTE: we are still using the good old lodash uniqueId when the code is not in\",\n\t\t\t\" * production, so that the results are a little bit more consistent tests after\",\n\t\t\t\" * test instead of being completely random.\",\n\t\t\t\" */\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(input, {\n\t\t\t...baseOpts,\n\t\t\twidth: 100,\n\t\t}).transformed;\n\t\t// New structural policy: first NOTE line always gets period even if followed\n\t\t// by prose.\n\t\texpect(out).toMatch(/when the code is not in\\./);\n\t\t// Ensure final sentence has period.\n\t\texpect(/completely random\\./.test(out)).toBe(true);\n\t});\n\n\tit(\"handles diffLines with different length arrays\", () => {\n\t\tconst a = \"line1\\nline2\";\n\t\tconst b = \"line1\\nline2\\nline3\";\n\t\tconst diff = diffLines(a, b);\n\t\texpect(diff).toContain(\"+ line3\");\n\n\t\tconst c = \"line1\\nline2\\nline3\";\n\t\tconst d = \"line1\\nline2\";\n\t\tconst diff2 = diffLines(c, d);\n\t\texpect(diff2).toContain(\"- line3\");\n\t});\n\n\tit(\"handles complex NOTE sentence boundaries and splitting\", () => {\n\t\tconst input = [\n\t\t\t\"/**\",\n\t\t\t\" * This performs work NOTE: first note without period NOTE: second note. Then continues\",\n\t\t\t\" */\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(input, {\n\t\t\t...baseOpts,\n\t\t\twidth: 100,\n\t\t}).transformed;\n\t\t// Test that NOTE content is processed properly (without making assumptions about splitting)\n\t\texpect(out).toMatch(/This performs work/);\n\t\texpect(out).toMatch(/NOTE: first note without period/);\n\t\texpect(out).toMatch(/NOTE: second note/);\n\t\texpect(out).toMatch(/Then continues/);\n\t});\n\n\tit(\"handles line comment merging with NOTE content\", () => {\n\t\tconst src = [\n\t\t\t\"// This text has multiple thoughts\",\n\t\t\t\"// NOTE: important note here\",\n\t\t\t\"// Final concluding text\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 120,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\texpect(out).toMatch(/\\/\\*\\*/);\n\t\texpect(out).toMatch(/This text has multiple thoughts/);\n\t\texpect(out).toMatch(/NOTE: important note here/);\n\t\texpect(out).toMatch(/Final concluding text/);\n\t});\n\n\tit(\"preserves biome-ignore comments without modification\", () => {\n\t\tconst src = [\n\t\t\t\"// biome-ignore lint/suspicious/noExplicitAny: required for dynamic typing\",\n\t\t\t\"const x: any = {};\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\texpect(out).toBe(src);\n\t});\n\n\tit(\"does not merge biome-ignore with following comment lines\", () => {\n\t\tconst src = [\n\t\t\t\"// biome-ignore lint/suspicious/noExplicitAny: dynamic\",\n\t\t\t\"// This is a separate comment\",\n\t\t\t\"// that should not be merged with biome-ignore\",\n\t\t\t\"const x = 1;\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\t// The biome directive should remain as a line comment.\n\t\texpect(out).toContain(\n\t\t\t\"// biome-ignore lint/suspicious/noExplicitAny: dynamic\",\n\t\t);\n\t\t// The following comments should not include the biome directive content.\n\t\texpect(out).not.toMatch(/\\* biome-ignore/);\n\t});\n\n\tit(\"preserves eslint-disable comments\", () => {\n\t\tconst src = [\n\t\t\t\"// eslint-disable-next-line no-console\",\n\t\t\t\"console.log('test');\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: false,\n\t\t}).transformed;\n\t\texpect(out).toBe(src);\n\t});\n\n\tit(\"preserves prettier-ignore comments\", () => {\n\t\tconst src = [\n\t\t\t\"// prettier-ignore\",\n\t\t\t\"const matrix = [\",\n\t\t\t\" 1, 0, 0,\",\n\t\t\t\" 0, 1, 0,\",\n\t\t\t\"];\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\texpect(out).toContain(\"// prettier-ignore\");\n\t});\n\n\tit(\"preserves @ts-expect-error comments\", () => {\n\t\tconst src = [\n\t\t\t\"// @ts-expect-error - intentionally testing error case\",\n\t\t\t\"invalidFunction();\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: false,\n\t\t}).transformed;\n\t\texpect(out).toBe(src);\n\t});\n\n\tit(\"preserves @ts-ignore comments\", () => {\n\t\tconst src = \"// @ts-ignore\\nconst x = badCode;\";\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: false,\n\t\t}).transformed;\n\t\texpect(out).toBe(src);\n\t});\n\n\tit(\"preserves stylelint-disable comments\", () => {\n\t\tconst src = \"// stylelint-disable declaration-no-important\";\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: false,\n\t\t}).transformed;\n\t\texpect(out).toBe(src);\n\t});\n\n\tit(\"preserves v8 ignore and c8 ignore coverage directives\", () => {\n\t\tconst src = [\n\t\t\t\"// v8 ignore next\",\n\t\t\t\"// c8 ignore start\",\n\t\t\t\"function untestable() {}\",\n\t\t\t\"// c8 ignore stop\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\texpect(out).toContain(\"// v8 ignore next\");\n\t\texpect(out).toContain(\"// c8 ignore start\");\n\t\texpect(out).toContain(\"// c8 ignore stop\");\n\t});\n\n\tit(\"preserves istanbul ignore comments\", () => {\n\t\tconst src = \"// istanbul ignore next\";\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: false,\n\t\t}).transformed;\n\t\texpect(out).toBe(src);\n\t});\n\n\tit(\"stops merging comment group before linter directive\", () => {\n\t\tconst src = [\n\t\t\t\"// This is an explanatory comment\",\n\t\t\t\"// that spans multiple lines\",\n\t\t\t\"// biome-ignore lint/style/useConst: needs reassignment\",\n\t\t\t\"let value = compute();\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\texpect(out).toContain(\"/**\");\n\t\texpect(out).toContain(\"// biome-ignore\");\n\t\texpect(out).not.toMatch(/\\* biome-ignore/);\n\t});\n\n\tit(\"handles multiple different linter directives in sequence\", () => {\n\t\tconst src = [\n\t\t\t\"// eslint-disable-next-line @typescript-eslint/no-explicit-any\",\n\t\t\t\"// biome-ignore lint/suspicious/noExplicitAny: legacy code\",\n\t\t\t\"// @ts-expect-error - type mismatch expected\",\n\t\t\t\"const x: any = getValue();\",\n\t\t].join(\"\\n\");\n\t\tconst out = parseAndTransformComments(src, {\n\t\t\twidth: 80,\n\t\t\twrapLineComments: true,\n\t\t\tmergeLineComments: true,\n\t\t}).transformed;\n\t\texpect(out).toContain(\"// eslint-disable-next-line\");\n\t\texpect(out).toContain(\"// biome-ignore\");\n\t\texpect(out).toContain(\"// @ts-expect-error\");\n\t\texpect(out).not.toContain(\"/**\");\n\t});\n});\n"],"names":["fs","os","path","describe","expect","it","expandGlobs","diffLines","parseAndTransformComments","baseOpts","width","wrapLineComments","mergeLineComments","input","res","transformed","toContain","test","toBe","split","length","toBeGreaterThan","join","first","second","lines","filter","l","not","toMatch","out","tmpRoot","mkdtempSync","tmpdir","a","nestedDir","mkdirSync","recursive","b","writeFileSync","shallow","sort","toEqual","deep","src","snippet","trim","arrowLineCount","toBeGreaterThanOrEqual","original","startsWith","re","match","toBeNull","starLines","noteLine","find","toBeDefined","noteLines","notes","diff","c","d","diff2"],"mappings":"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"}
|
package/dist/lib.js
CHANGED
|
@@ -157,7 +157,13 @@ function isListLike(line) {
|
|
|
157
157
|
return /^(?:[-*+] |\d+\. )/.test(line.trim());
|
|
158
158
|
}
|
|
159
159
|
function isTagLine(line) {
|
|
160
|
-
|
|
160
|
+
/**
|
|
161
|
+
* A JSDoc/TSDoc tag is `@name` (optionally hyphenated) and is never
|
|
162
|
+
* immediately followed by `/`. The negative lookahead excludes scoped npm
|
|
163
|
+
* package specifiers like `@auth0/auth0-react` or `@versini/ui-main` that can
|
|
164
|
+
* legitimately open a wrapped prose line; treating those as tags severs the
|
|
165
|
+
* sentence and injects a spurious period.
|
|
166
|
+
*/ return /^@[A-Za-z][\w-]*(?![\w/-])/.test(line.trim());
|
|
161
167
|
}
|
|
162
168
|
function isHeadingLike(line) {
|
|
163
169
|
var t = line.trim();
|
package/dist/lib.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib.ts"],"sourcesContent":["import { Logger } from \"@node-cli/logger\";\n\nexport const logger = new Logger({ boring: process.env.NODE_ENV === \"test\" });\n\nexport interface ProcessOptions {\n\twidth: number;\n\twrapLineComments: boolean;\n\tmergeLineComments: boolean;\n}\n\nexport interface FileResult {\n\toriginal: string;\n\ttransformed: string;\n\tchanged: boolean;\n}\n\ninterface JsDocMatch {\n\tindent: string;\n\tbody: string;\n\tstart: number;\n\tend: number;\n}\n\n/**\n * Safety guards / limits (defense-in-depth vs pathological or malicious input)\n * Large indentation sequences (e.g. thousands of tabs) aren't meaningful for\n * real source formatting and could be used to inflate processing time if a\n * regex exhibited super-linear behavior. Our pattern is already linear\n * (tempered), but we still cap accepted indentation length to keep work\n * bounded.\n */\nconst MAX_JSDOC_INDENT = 256; // characters (tabs + spaces)\n\n/**\n * JSDoc block extraction:\n * Previous pattern used a lazy dot-all: ([\\s\\S]*?) which could, under\n * pathological inputs, produce excessive backtracking. We replaced it with a\n * tempered pattern that advances linearly by never letting the inner part\n * consume a closing '*\\/'. This avoids catastrophic behavior while keeping\n * correctness.\n *\n * Reviewer (PR) concern: potential ReDoS on crafted inputs containing many\n * leading tabs then '/**'. Analysis: The inner quantified group\n * (?:[^*]|\\*(?!/))*\n * is unambiguous: on each iteration it consumes exactly one character and can\n * never match the closing sentinel '*\\/' because of the negative lookahead. This\n * means the engine proceeds in O(n) time relative to the block body size.\n * There is no nested ambiguous quantifier (e.g. (a+)*, (.*)+, etc.). The only\n * other quantified part ^[\\t ]* is a simple character class that is consumed\n * once per line start with no backtracking explosion potential.\n *\n * Defense-in-depth: we still (1) cap processed body length (see below) and\n * (2) cap accepted indentation length (MAX_JSDOC_INDENT) after match to ensure\n * we skip absurdly indented constructs.\n *\n * Pattern explanation:\n * (^ [\\t ]* ) -> capture indentation at start of line (multiline mode)\n * /\\*\\* -> opening delimiter\n * ( -> capture group 2 body\n * (?:[^*] -> any non-* char\n * |\\*(?!/) -> or a * not followed by /\n * )* -> repeated greedily (cannot cross closing *\\/)\n * )\n * \\n?[\\t ]*\\*\\/ -> optional newline + trailing indent + closing *\\/\n * Complexity: linear in length of the matched block.\n *\n */\nconst JSDOC_REGEX = /(^[\\t ]*)\\/\\*\\*((?:[^*]|\\*(?!\\/))*)\\n?[\\t ]*\\*\\//gm;\n\nexport function diffLines(a: string, b: string): string {\n\tif (a === b) {\n\t\treturn \"\";\n\t}\n\tconst A = a.split(/\\n/);\n\tconst B = b.split(/\\n/);\n\tconst out: string[] = [];\n\tconst m = Math.max(A.length, B.length);\n\tfor (let i = 0; i < m; i++) {\n\t\tif (A[i] === B[i]) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (A[i] !== undefined) {\n\t\t\tout.push(`- ${A[i]}`);\n\t\t}\n\t\tif (B[i] !== undefined) {\n\t\t\tout.push(`+ ${B[i]}`);\n\t\t}\n\t}\n\treturn out.join(\"\\n\");\n}\n\nfunction endsSentence(line: string): boolean {\n\treturn /[.!?](?:['\")\\]]*)$/.test(line.trim());\n}\n\nfunction needsTerminalPunctuation(line: string): boolean {\n\treturn /[A-Za-z0-9\")\\]']$/.test(line) && !endsSentence(line);\n}\n\nfunction maybeAddPeriod(line: string): string {\n\treturn needsTerminalPunctuation(line) ? line + \".\" : line;\n}\n\nfunction normalizeNote(line: string): string {\n\treturn line.replace(/^note:/i, \"NOTE:\");\n}\n\n/**\n * ' at start or immediately after a sentence terminator + space.\n */\nfunction splitNoteSentences(text: string): string[] {\n\tif (!/NOTE: /.test(text)) {\n\t\treturn [text];\n\t}\n\tconst segments: string[] = [];\n\tlet i = 0;\n\twhile (i < text.length) {\n\t\tconst idx = text.indexOf(\"NOTE: \", i);\n\t\tif (idx === -1) {\n\t\t\tconst tail = text.slice(i).trim();\n\t\t\tif (tail) {\n\t\t\t\tsegments.push(tail);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\t/**\n\t\t * Boundary heuristics: start of text, sentence punctuation + space, OR a\n\t\t * plain space (allows splitting even when author forgot to terminate the\n\t\t * previous sentence before starting a NOTE clause).\n\t\t */\n\t\tconst boundary =\n\t\t\tidx === 0 ||\n\t\t\t/[.!?] /.test(text.slice(Math.max(0, idx - 2), idx + 1)) ||\n\t\t\ttext[idx - 1] === \" \";\n\t\tif (!boundary) {\n\t\t\ti = idx + 6; // skip this occurrence\n\t\t\tcontinue;\n\t\t}\n\t\tconst before = text.slice(i, idx).trim();\n\t\tif (before) {\n\t\t\tsegments.push(before);\n\t\t}\n\t\tlet end = idx;\n\t\twhile (end < text.length && !/[.!?]/.test(text[end])) {\n\t\t\tend++;\n\t\t}\n\t\tif (end < text.length && /[.!?]/.test(text[end])) {\n\t\t\tend++;\n\t\t}\n\t\tlet note = text.slice(idx, end).trim();\n\t\tif (!/[.!?]$/.test(note)) {\n\t\t\tnote += \".\";\n\t\t}\n\t\tsegments.push(note);\n\t\ti = end;\n\t\tif (text[i] === \" \") {\n\t\t\ti++;\n\t\t}\n\t}\n\treturn segments.filter(Boolean);\n}\n\nfunction isListLike(line: string): boolean {\n\treturn /^(?:[-*+] |\\d+\\. )/.test(line.trim());\n}\n\nfunction isTagLine(line: string): boolean {\n\treturn /^@/.test(line.trim());\n}\n\nfunction isHeadingLike(line: string): boolean {\n\tconst t = line.trim();\n\tif (!/:$/.test(t) || isTagLine(t)) {\n\t\treturn false;\n\t}\n\t/**\n\t * New heuristic: treat as heading only if composed of one or more words that\n\t * each start with an uppercase letter (allows Internal IDs with\n\t * dashes/underscores too). Examples considered headings: \"Overview:\",\n\t * \"Performance Notes:\", \"API Surface:\". Non-headings (treated as sentence\n\t * continuation): \"tested a little bit differently:\", \"differently:\".\n\t */\n\treturn /^[A-Z][A-Za-z0-9_-]*(?: [A-Z][A-Za-z0-9_-]*)*:$/.test(t);\n}\n\nfunction isCodeFence(line: string): boolean {\n\treturn /^```/.test(line.trim());\n}\n\nfunction isVisuallyIndentedCode(line: string): boolean {\n\treturn /^\\s{2,}\\S/.test(line);\n}\n\n/**\n * Detects linter/tool directive comments that should be left untouched.\n * These include ESLint, Biome, Prettier, TypeScript, StyleLint, and coverage\n * tool directives.\n */\nfunction isLinterDirective(text: string): boolean {\n\tconst trimmed = text.trim();\n\treturn /^(@?(?:ts-ignore|ts-expect-error|ts-nocheck|ts-check)|eslint|biome-ignore|prettier-ignore|stylelint-(?:disable|enable)|c8 ignore|v8 ignore|istanbul ignore|tsc:|type:|@ts-)/i.test(\n\t\ttrimmed,\n\t);\n}\n\nfunction wrapWords(text: string, width: number): string[] {\n\tconst words = text.split(/\\s+/).filter(Boolean);\n\tconst lines: string[] = [];\n\tlet cur = \"\";\n\tfor (const w of words) {\n\t\tif (!cur.length) {\n\t\t\tcur = w;\n\t\t\tcontinue;\n\t\t}\n\t\tif (cur.length + 1 + w.length <= width) {\n\t\t\tcur += \" \" + w;\n\t\t} else {\n\t\t\tlines.push(cur);\n\t\t\tcur = w;\n\t\t}\n\t}\n\tif (cur) {\n\t\tlines.push(cur);\n\t}\n\treturn lines.length ? lines : [\"\"];\n}\n\nfunction buildJsDoc(indent: string, rawBody: string, width: number): string {\n\tlet lines = rawBody.split(/\\n/).map((l) => l.replace(/^\\s*\\*? ?/, \"\"));\n\t// Remove a single leading blank line (artifact of regex capture starting after\n\t// /**) if content follows.\n\twhile (\n\t\tlines.length > 1 &&\n\t\tlines[0].trim() === \"\" &&\n\t\tlines.some((l) => l.trim() !== \"\")\n\t) {\n\t\tlines = lines.slice(1);\n\t}\n\t/**\n\t * Trailing blank handling: keep a single trailing blank only if there are\n\t * multiple paragraphs (i.e., an internal blank separator exists). If the doc\n\t * is a single paragraph, drop the trailing blank to avoid an extra standalone\n\t * '*' line before the closing delimiter.\n\t */\n\tif (lines.length > 1 && lines[lines.length - 1].trim() === \"\") {\n\t\tconst internalBlank = lines.slice(0, -1).some((l) => l.trim() === \"\");\n\t\tif (!internalBlank) {\n\t\t\tlines = lines.slice(0, -1);\n\t\t}\n\t}\n\tconst out: string[] = [];\n\tlet para: string[] = [];\n\tlet inFence = false;\n\tconst prefix = indent + \" * \";\n\tconst avail = Math.max(10, width - prefix.length);\n\n\t/**\n\t * Detect structured explanatory / regex description blocks where we want to\n\t * preserve each original line verbatim (no paragraph joining or sentence\n\t * period insertion) to avoid altering carefully aligned or enumerated lines.\n\t */\n\tconst structured = lines.some(\n\t\t(l) =>\n\t\t\t/->/.test(l) ||\n\t\t\t/(\\(?:\\?|\\*\\/)/.test(l) ||\n\t\t\t/Pattern explanation:/i.test(l),\n\t);\n\tif (structured) {\n\t\tfor (const raw of lines) {\n\t\t\tconst trimmed = raw.trimEnd();\n\t\t\tif (trimmed === \"\") {\n\t\t\t\t// ensure a blank line represented by a lone '*'.\n\t\t\t\tif (\n\t\t\t\t\tout.length === 0 ||\n\t\t\t\t\t/^(?:\\s*\\*\\s*)$/.test(out[out.length - 1]) === false\n\t\t\t\t) {\n\t\t\t\t\tout.push(prefix.trimEnd());\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tout.push(prefix + normalizeNote(trimmed));\n\t\t}\n\t\t// Consistent style: space before closing */\n\t\treturn `${indent}/**\\n${out.join(\"\\n\")}\\n${indent} */`;\n\t}\n\n\tfunction flush(): void {\n\t\tif (!para.length) {\n\t\t\treturn;\n\t\t}\n\t\tlet text = para.join(\" \").replace(/\\s+/g, \" \").trim();\n\t\ttext = normalizeNote(text);\n\t\ttext = maybeAddPeriod(text);\n\t\tconst pieces = splitNoteSentences(text);\n\t\tfor (const piece of pieces) {\n\t\t\tfor (const l of wrapWords(piece, avail)) {\n\t\t\t\tout.push(prefix + l);\n\t\t\t}\n\t\t}\n\t\tpara = [];\n\t}\n\n\tlet lineIndex = -1;\n\tfor (const raw of lines) {\n\t\tlineIndex++;\n\t\tconst trimmed = raw.trimEnd();\n\t\tif (isCodeFence(trimmed)) {\n\t\t\tflush();\n\t\t\tinFence = !inFence;\n\t\t\tout.push(prefix + trimmed);\n\t\t\tcontinue;\n\t\t}\n\t\tif (inFence) {\n\t\t\t/**\n\t\t\t * Inside a code fence we preserve content verbatim, but for a blank line we\n\t\t\t * still prefer the canonical ' *' (no trailing space after the star) instead\n\t\t\t * of ' * '.\n\t\t\t */\n\t\t\tif (trimmed === \"\") {\n\t\t\t\tout.push(prefix.trimEnd());\n\t\t\t} else {\n\t\t\t\tout.push(prefix + trimmed);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\ttrimmed === \"\" ||\n\t\t\tisListLike(trimmed) ||\n\t\t\tisTagLine(trimmed) ||\n\t\t\tisHeadingLike(trimmed) ||\n\t\t\tisVisuallyIndentedCode(raw) ||\n\t\t\t/^NOTE: /.test(normalizeNote(trimmed))\n\t\t) {\n\t\t\tflush();\n\t\t\tif (trimmed === \"\") {\n\t\t\t\tif (\n\t\t\t\t\tout.length === 0 ||\n\t\t\t\t\t/^(?:\\s*\\*\\s*)$/.test(out[out.length - 1]) === false\n\t\t\t\t) {\n\t\t\t\t\tout.push(prefix.trimEnd());\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlet noteLine = normalizeNote(trimmed);\n\t\t\t\tif (/^NOTE: /.test(noteLine) && !/[.!?]$/.test(noteLine)) {\n\t\t\t\t\t/**\n\t\t\t\t\t * Structural lookahead: add period only if the NOTE line is followed by a\n\t\t\t\t\t * boundary (blank line, tag line, list item, heading, code fence, visually\n\t\t\t\t\t * indented code, another NOTE line, or end-of-block). If next non-blank\n\t\t\t\t\t * line is plain prose, skip.\n\t\t\t\t\t */\n\t\t\t\t\tlet addPeriod = true; // assume boundary until proven prose continuation\n\t\t\t\t\tconst look = lineIndex + 1;\n\t\t\t\t\twhile (look < lines.length) {\n\t\t\t\t\t\tconst rawNext = lines[look];\n\t\t\t\t\t\tconst cleaned = rawNext.replace(/^\\s*\\*? ?/, \"\").trimEnd();\n\t\t\t\t\t\tconst trimmedNext = cleaned.trim();\n\t\t\t\t\t\tif (trimmedNext === \"\") {\n\t\t\t\t\t\t\t// Blank line: definite boundary.\n\t\t\t\t\t\t\taddPeriod = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t/^NOTE: /i.test(trimmedNext) ||\n\t\t\t\t\t\t\tisTagLine(trimmedNext) ||\n\t\t\t\t\t\t\tisListLike(trimmedNext) ||\n\t\t\t\t\t\t\tisHeadingLike(trimmedNext) ||\n\t\t\t\t\t\t\tisCodeFence(trimmedNext) ||\n\t\t\t\t\t\t\tisVisuallyIndentedCode(rawNext)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\taddPeriod = true; // boundary structure\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Anything else: treat as prose continuation.\n\t\t\t\t\t\taddPeriod = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t/**\n\t\t\t\t\t * If this is the first NOTE line emitted in the block (no prior non-blank\n\t\t\t\t\t * paragraph lines), we still want a period for consistency even if a prose\n\t\t\t\t\t * continuation follows; treat it as a standalone NOTE sentence introducing\n\t\t\t\t\t * subsequent content.\n\t\t\t\t\t */\n\t\t\t\t\tconst hasPriorContent = out.some(\n\t\t\t\t\t\t(l) => /\\* [^ ]/.test(l) && !/\\* NOTE: /.test(l),\n\t\t\t\t\t);\n\t\t\t\t\tif (addPeriod || !hasPriorContent) {\n\t\t\t\t\t\tnoteLine += \".\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tout.push(prefix + noteLine);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tpara.push(trimmed);\n\t}\n\tflush();\n\t/**\n\t * Style: ensure a space precedes the closing *\\/ for consistency with blocks\n\t * generated elsewhere in this tool (merged line comment groups). Previously we\n\t * emitted `${indent}*\\/` which produced an off-by-one visual alignment.\n\t */\n\treturn `${indent}/**\\n${out.join(\"\\n\")}\\n${indent} */`;\n}\n\nfunction reflowJsDocBlocks(\n\tcontent: string,\n\twidth: number,\n): { content: string; blocks: number } {\n\tJSDOC_REGEX.lastIndex = 0;\n\tconst blocks: JsDocMatch[] = [];\n\tlet m: RegExpExecArray | null = JSDOC_REGEX.exec(content);\n\twhile (m) {\n\t\tconst indent = m[1] || \"\";\n\t\tconst body = m[2] || \"\";\n\t\t// Body length guard protects against extremely large comment blocks.\n\t\tif (body.length <= 500_000 && indent.length <= MAX_JSDOC_INDENT) {\n\t\t\tblocks.push({\n\t\t\t\tindent,\n\t\t\t\tbody,\n\t\t\t\tstart: m.index,\n\t\t\t\tend: m.index + m[0].length,\n\t\t\t});\n\t\t}\n\t\tm = JSDOC_REGEX.exec(content);\n\t}\n\tif (!blocks.length) {\n\t\treturn { content, blocks: 0 };\n\t}\n\tlet delta = 0;\n\tlet out = content;\n\tfor (const b of blocks) {\n\t\tconst original = out.slice(b.start + delta, b.end + delta);\n\t\tconst built = buildJsDoc(b.indent, b.body, width);\n\t\tif (original !== built) {\n\t\t\tout = out.slice(0, b.start + delta) + built + out.slice(b.end + delta);\n\t\t\tdelta += built.length - original.length;\n\t\t}\n\t}\n\treturn { content: out, blocks: blocks.length };\n}\n\nfunction wrapLineComments(\n\tcontent: string,\n\twidth: number,\n): { content: string; applied: boolean } {\n\tconst lines = content.split(/\\n/);\n\tlet changed = false;\n\tconst out: string[] = [];\n\tlet i = 0;\n\twhile (i < lines.length) {\n\t\tconst line = lines[i];\n\t\tconst m = /^(\\s*)\\/\\/( ?)(.*)$/.exec(line);\n\t\tif (!m || /^\\/\\/\\//.test(line)) {\n\t\t\tout.push(line);\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\t\t/**\n\t\t * Collect a group of consecutive simple // lines (not triple slash) that are\n\t\t * eligible to be wrapped/merged. We stop before directive lines, URLs, or\n\t\t * triple-slash (reference) comments to avoid altering those semantics.\n\t\t */\n\t\tconst group: { raw: string; indent: string; body: string }[] = [];\n\t\tlet j = i;\n\t\twhile (j < lines.length) {\n\t\t\tconst gm = /^(\\s*)\\/\\/ ?(.*)$/.exec(lines[j]);\n\t\t\tif (!gm || /^\\/\\/\\//.test(lines[j])) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst body = gm[2];\n\t\t\tif (isLinterDirective(body) || /https?:\\/\\//.test(body)) {\n\t\t\t\tbreak; // stop group before directives/URLs; process current line normally\n\t\t\t}\n\t\t\tgroup.push({ raw: lines[j], indent: gm[1], body });\n\t\t\tj++;\n\t\t}\n\t\tif (group.length <= 1) {\n\t\t\t// Single line: existing logic (add period if needed).\n\t\t\tconst indent = m[1];\n\t\t\tconst body = m[3];\n\t\t\tif (isLinterDirective(body) || /https?:\\/\\//.test(body)) {\n\t\t\t\tout.push(line);\n\t\t\t\ti++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst prefix = indent + \"// \";\n\t\t\tconst avail = Math.max(10, width - prefix.length);\n\t\t\tlet text = body.replace(/\\s+/g, \" \").trim();\n\t\t\ttext = normalizeNote(text);\n\t\t\ttext = maybeAddPeriod(text);\n\t\t\tconst wrapped = wrapWords(text, avail).map((w) => prefix + w);\n\t\t\tif (wrapped.join(\"\\n\") !== line) {\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t\tout.push(...wrapped);\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\t\t/**\n\t\t * Multi-line group: only add terminal punctuation (a single period) to the\n\t\t * final logical sentence if needed. Earlier lines are treated as soft wraps\n\t\t * of the same paragraph; adding periods to each would create spurious\n\t\t * sentence boundaries.\n\t\t */\n\t\tfor (let k = 0; k < group.length; k++) {\n\t\t\tconst { indent, body } = group[k];\n\t\t\tconst prefix = indent + \"// \";\n\t\t\tconst avail = Math.max(10, width - prefix.length);\n\t\t\tlet text = body.replace(/\\s+/g, \" \").trim();\n\t\t\ttext = normalizeNote(text);\n\t\t\tif (k === group.length - 1 && !/:$/.test(text.trim())) {\n\t\t\t\ttext = maybeAddPeriod(text);\n\t\t\t}\n\t\t\tconst wrapped = wrapWords(text, avail).map((w) => prefix + w);\n\t\t\tif (wrapped.join(\"\\n\") !== group[k].raw) {\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t\tout.push(...wrapped);\n\t\t}\n\t\ti = j;\n\t}\n\treturn { content: out.join(\"\\n\"), applied: changed };\n}\n\nfunction mergeLineCommentGroups(content: string): {\n\tcontent: string;\n\tmerged: boolean;\n} {\n\tconst lines = content.split(/\\n/);\n\tconst out: string[] = [];\n\tlet i = 0;\n\tlet merged = false;\n\n\tfunction qualifiesExplanatoryAfterStatement(start: number): boolean {\n\t\t/**\n\t\t * Peek ahead to collect consecutive // lines (excluding triple slash) to\n\t\t * decide if they form a sufficiently large explanatory paragraph that\n\t\t * deserves merging directly after a terminated statement.\n\t\t */\n\t\tconst collected: string[] = [];\n\t\tfor (let k = start; k < lines.length; k++) {\n\t\t\tconst lm = /^(\\s*)\\/\\/( ?)(.*)$/.exec(lines[k]);\n\t\t\tif (!lm || /^\\/\\/\\//.test(lines[k])) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst body = lm[3];\n\t\t\tif (isLinterDirective(body) || /https?:\\/\\//.test(body)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcollected.push(body.trim());\n\t\t}\n\t\tif (collected.length < 3) {\n\t\t\treturn false; // lowered threshold from 4 -> 3 to permit shorter explanatory groups\n\t\t}\n\t\tif (!/^[A-Z]/.test(collected[0])) {\n\t\t\treturn false; // start with capitalized sentence\n\t\t}\n\t\t/**\n\t\t * Avoid matching directive-like or list-lists: require at least one line\n\t\t * containing a space (a sentence fragment vs a single token).\n\t\t */\n\t\treturn collected.some((c) => /\\s/.test(c));\n\t}\n\twhile (i < lines.length) {\n\t\tif (/^\\s*\\/\\//.test(lines[i]) && !/^\\s*\\/\\/\\//.test(lines[i])) {\n\t\t\tconst prev = i > 0 ? lines[i - 1] : \"\";\n\t\t\tconst prevTrim = prev.trim();\n\t\t\tlet contextEligible = prevTrim === \"\" || /[{}\\]),;]$/.test(prevTrim);\n\t\t\t/**\n\t\t\t * Heuristic: also allow large explanatory group after a statement ending\n\t\t\t * with ';' when it qualifies as explanatory so it can be elevated to a block\n\t\t\t * comment rather than remaining a run of // lines.\n\t\t\t */\n\t\t\tif (\n\t\t\t\t!contextEligible &&\n\t\t\t\t/;\\s*$/.test(prevTrim) &&\n\t\t\t\tqualifiesExplanatoryAfterStatement(i)\n\t\t\t) {\n\t\t\t\tcontextEligible = true;\n\t\t\t}\n\t\t\tif (!contextEligible) {\n\t\t\t\tout.push(lines[i]);\n\t\t\t\ti++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst group: { indent: string; text: string }[] = [];\n\t\t\tlet j = i;\n\t\t\twhile (j < lines.length) {\n\t\t\t\tconst lm = /^(\\s*)\\/\\/ ?(.*)$/.exec(lines[j]);\n\t\t\t\tif (!lm || /^\\s*\\/\\/\\//.test(lines[j])) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tconst txt = lm[2];\n\t\t\t\tif (\n\t\t\t\t\t/license|copyright/i.test(txt) ||\n\t\t\t\t\t/https?:\\/\\//.test(txt) ||\n\t\t\t\t\tisLinterDirective(txt)\n\t\t\t\t) {\n\t\t\t\t\tbreak; // do not merge directive / license groups\n\t\t\t\t}\n\t\t\t\tgroup.push({ indent: lm[1], text: txt });\n\t\t\t\tj++;\n\t\t\t}\n\t\t\tif (group.length >= 2) {\n\t\t\t\t/**\n\t\t\t\t * Structured explanatory blocks: now we CONVERT them into a multi-line JSDoc block\n\t\t\t\t * while preserving each original line (instead of merging into a single paragraph).\n\t\t\t\t * We must escape any raw '*\\/' inside the body to avoid premature termination.\n\t\t\t\t * Definition of structured:\n\t\t\t\t * presence of arrows (->), regex tokens (?:, *\\/), or the phrase 'Pattern explanation:'.\n\t\t\t\t */\n\t\t\t\tconst structured = group.some(\n\t\t\t\t\t(g) =>\n\t\t\t\t\t\t/->/.test(g.text) ||\n\t\t\t\t\t\t/(\\(\\?:|\\*\\/)/.test(g.text) ||\n\t\t\t\t\t\t/Pattern explanation:/i.test(g.text),\n\t\t\t\t);\n\t\t\t\tif (structured) {\n\t\t\t\t\tconst indent = group[0].indent;\n\t\t\t\t\tout.push(`${indent}/**`);\n\t\t\t\t\tfor (const ln of group) {\n\t\t\t\t\t\t// Escape closing sentinel inside content.\n\t\t\t\t\t\tconst safe = ln.text.replace(/\\*\\//g, \"*\\\\/\");\n\t\t\t\t\t\tout.push(`${indent} * ${safe}`);\n\t\t\t\t\t}\n\t\t\t\t\tout.push(`${indent} */`);\n\t\t\t\t\tmerged = true;\n\t\t\t\t\ti = j;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst indent = group[0].indent;\n\t\t\t\tmerged = true;\n\t\t\t\t/**\n\t\t\t\t * We only want to add terminal punctuation once at the end of the merged\n\t\t\t\t * paragraph, not after every original line (which can create spurious\n\t\t\t\t * periods mid-sentence when lines were simple wraps). We also avoid\n\t\t\t\t * appending a period if the final line ends with a colon introducing a\n\t\t\t\t * list.\n\t\t\t\t */\n\t\t\t\tconst norm = group.map((g) => normalizeNote(g.text.trim()));\n\t\t\t\t/**\n\t\t\t\t * We only want to add terminal punctuation once at the end of the merged\n\t\t\t\t * paragraph, not after every original line (which can create spurious\n\t\t\t\t * periods mid-sentence when lines were simple wraps). We also avoid\n\t\t\t\t * appending a period if the final line ends with a colon introducing a\n\t\t\t\t * list.\n\t\t\t\t */\n\t\t\t\tlet lastIdx = norm.length - 1;\n\t\t\t\twhile (lastIdx > 0 && norm[lastIdx].trim() === \"\") {\n\t\t\t\t\tlastIdx--;\n\t\t\t\t}\n\t\t\t\tfor (let k = 0; k < norm.length; k++) {\n\t\t\t\t\tif (k === lastIdx) {\n\t\t\t\t\t\tconst ln = norm[k];\n\t\t\t\t\t\tif (!/:$/.test(ln.trim())) {\n\t\t\t\t\t\t\tnorm[k] = maybeAddPeriod(ln);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst para = norm.join(\" \").replace(/\\s+/g, \" \").trim();\n\t\t\t\tout.push(`${indent}/**`);\n\t\t\t\tfor (const seg of splitNoteSentences(para)) {\n\t\t\t\t\tout.push(`${indent} * ${seg}`);\n\t\t\t\t}\n\t\t\t\tout.push(`${indent} */`);\n\t\t\t\ti = j;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\tout.push(lines[i]);\n\t\ti++;\n\t}\n\treturn { content: out.join(\"\\n\"), merged };\n}\n\nexport function parseAndTransformComments(\n\tinput: string,\n\toptions: ProcessOptions,\n): FileResult {\n\tlet working = input;\n\tif (options.mergeLineComments) {\n\t\tconst m = mergeLineCommentGroups(working);\n\t\tworking = m.content;\n\t}\n\tconst js = reflowJsDocBlocks(working, options.width);\n\tworking = js.content;\n\tif (options.wrapLineComments) {\n\t\tconst w = wrapLineComments(working, options.width);\n\t\tworking = w.content;\n\t}\n\treturn { original: input, transformed: working, changed: working !== input };\n}\n"],"names":["Logger","logger","boring","process","env","NODE_ENV","MAX_JSDOC_INDENT","JSDOC_REGEX","diffLines","a","b","A","split","B","out","m","Math","max","length","i","undefined","push","join","endsSentence","line","test","trim","needsTerminalPunctuation","maybeAddPeriod","normalizeNote","replace","splitNoteSentences","text","segments","idx","indexOf","tail","slice","boundary","before","end","note","filter","Boolean","isListLike","isTagLine","isHeadingLike","t","isCodeFence","isVisuallyIndentedCode","isLinterDirective","trimmed","wrapWords","width","words","lines","cur","w","buildJsDoc","indent","rawBody","map","l","some","internalBlank","para","inFence","prefix","avail","structured","raw","trimEnd","flush","pieces","piece","lineIndex","noteLine","addPeriod","look","rawNext","cleaned","trimmedNext","hasPriorContent","reflowJsDocBlocks","content","lastIndex","blocks","exec","body","start","index","delta","original","built","wrapLineComments","group","k","wrapped","changed","j","gm","applied","mergeLineCommentGroups","merged","qualifiesExplanatoryAfterStatement","collected","lm","c","prev","prevTrim","contextEligible","txt","g","ln","safe","norm","lastIdx","seg","parseAndTransformComments","input","options","working","mergeLineComments","js","transformed"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/lib.ts"],"sourcesContent":["import { Logger } from \"@node-cli/logger\";\n\nexport const logger = new Logger({ boring: process.env.NODE_ENV === \"test\" });\n\nexport interface ProcessOptions {\n\twidth: number;\n\twrapLineComments: boolean;\n\tmergeLineComments: boolean;\n}\n\nexport interface FileResult {\n\toriginal: string;\n\ttransformed: string;\n\tchanged: boolean;\n}\n\ninterface JsDocMatch {\n\tindent: string;\n\tbody: string;\n\tstart: number;\n\tend: number;\n}\n\n/**\n * Safety guards / limits (defense-in-depth vs pathological or malicious input)\n * Large indentation sequences (e.g. thousands of tabs) aren't meaningful for\n * real source formatting and could be used to inflate processing time if a\n * regex exhibited super-linear behavior. Our pattern is already linear\n * (tempered), but we still cap accepted indentation length to keep work\n * bounded.\n */\nconst MAX_JSDOC_INDENT = 256; // characters (tabs + spaces)\n\n/**\n * JSDoc block extraction:\n * Previous pattern used a lazy dot-all: ([\\s\\S]*?) which could, under\n * pathological inputs, produce excessive backtracking. We replaced it with a\n * tempered pattern that advances linearly by never letting the inner part\n * consume a closing '*\\/'. This avoids catastrophic behavior while keeping\n * correctness.\n *\n * Reviewer (PR) concern: potential ReDoS on crafted inputs containing many\n * leading tabs then '/**'. Analysis: The inner quantified group\n * (?:[^*]|\\*(?!/))*\n * is unambiguous: on each iteration it consumes exactly one character and can\n * never match the closing sentinel '*\\/' because of the negative lookahead. This\n * means the engine proceeds in O(n) time relative to the block body size.\n * There is no nested ambiguous quantifier (e.g. (a+)*, (.*)+, etc.). The only\n * other quantified part ^[\\t ]* is a simple character class that is consumed\n * once per line start with no backtracking explosion potential.\n *\n * Defense-in-depth: we still (1) cap processed body length (see below) and\n * (2) cap accepted indentation length (MAX_JSDOC_INDENT) after match to ensure\n * we skip absurdly indented constructs.\n *\n * Pattern explanation:\n * (^ [\\t ]* ) -> capture indentation at start of line (multiline mode)\n * /\\*\\* -> opening delimiter\n * ( -> capture group 2 body\n * (?:[^*] -> any non-* char\n * |\\*(?!/) -> or a * not followed by /\n * )* -> repeated greedily (cannot cross closing *\\/)\n * )\n * \\n?[\\t ]*\\*\\/ -> optional newline + trailing indent + closing *\\/\n * Complexity: linear in length of the matched block.\n *\n */\nconst JSDOC_REGEX = /(^[\\t ]*)\\/\\*\\*((?:[^*]|\\*(?!\\/))*)\\n?[\\t ]*\\*\\//gm;\n\nexport function diffLines(a: string, b: string): string {\n\tif (a === b) {\n\t\treturn \"\";\n\t}\n\tconst A = a.split(/\\n/);\n\tconst B = b.split(/\\n/);\n\tconst out: string[] = [];\n\tconst m = Math.max(A.length, B.length);\n\tfor (let i = 0; i < m; i++) {\n\t\tif (A[i] === B[i]) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (A[i] !== undefined) {\n\t\t\tout.push(`- ${A[i]}`);\n\t\t}\n\t\tif (B[i] !== undefined) {\n\t\t\tout.push(`+ ${B[i]}`);\n\t\t}\n\t}\n\treturn out.join(\"\\n\");\n}\n\nfunction endsSentence(line: string): boolean {\n\treturn /[.!?](?:['\")\\]]*)$/.test(line.trim());\n}\n\nfunction needsTerminalPunctuation(line: string): boolean {\n\treturn /[A-Za-z0-9\")\\]']$/.test(line) && !endsSentence(line);\n}\n\nfunction maybeAddPeriod(line: string): string {\n\treturn needsTerminalPunctuation(line) ? line + \".\" : line;\n}\n\nfunction normalizeNote(line: string): string {\n\treturn line.replace(/^note:/i, \"NOTE:\");\n}\n\n/**\n * ' at start or immediately after a sentence terminator + space.\n */\nfunction splitNoteSentences(text: string): string[] {\n\tif (!/NOTE: /.test(text)) {\n\t\treturn [text];\n\t}\n\tconst segments: string[] = [];\n\tlet i = 0;\n\twhile (i < text.length) {\n\t\tconst idx = text.indexOf(\"NOTE: \", i);\n\t\tif (idx === -1) {\n\t\t\tconst tail = text.slice(i).trim();\n\t\t\tif (tail) {\n\t\t\t\tsegments.push(tail);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\t/**\n\t\t * Boundary heuristics: start of text, sentence punctuation + space, OR a\n\t\t * plain space (allows splitting even when author forgot to terminate the\n\t\t * previous sentence before starting a NOTE clause).\n\t\t */\n\t\tconst boundary =\n\t\t\tidx === 0 ||\n\t\t\t/[.!?] /.test(text.slice(Math.max(0, idx - 2), idx + 1)) ||\n\t\t\ttext[idx - 1] === \" \";\n\t\tif (!boundary) {\n\t\t\ti = idx + 6; // skip this occurrence\n\t\t\tcontinue;\n\t\t}\n\t\tconst before = text.slice(i, idx).trim();\n\t\tif (before) {\n\t\t\tsegments.push(before);\n\t\t}\n\t\tlet end = idx;\n\t\twhile (end < text.length && !/[.!?]/.test(text[end])) {\n\t\t\tend++;\n\t\t}\n\t\tif (end < text.length && /[.!?]/.test(text[end])) {\n\t\t\tend++;\n\t\t}\n\t\tlet note = text.slice(idx, end).trim();\n\t\tif (!/[.!?]$/.test(note)) {\n\t\t\tnote += \".\";\n\t\t}\n\t\tsegments.push(note);\n\t\ti = end;\n\t\tif (text[i] === \" \") {\n\t\t\ti++;\n\t\t}\n\t}\n\treturn segments.filter(Boolean);\n}\n\nfunction isListLike(line: string): boolean {\n\treturn /^(?:[-*+] |\\d+\\. )/.test(line.trim());\n}\n\nfunction isTagLine(line: string): boolean {\n\t/**\n\t * A JSDoc/TSDoc tag is `@name` (optionally hyphenated) and is never\n\t * immediately followed by `/`. The negative lookahead excludes scoped npm\n\t * package specifiers like `@auth0/auth0-react` or `@versini/ui-main` that can\n\t * legitimately open a wrapped prose line; treating those as tags severs the\n\t * sentence and injects a spurious period.\n\t */\n\treturn /^@[A-Za-z][\\w-]*(?![\\w/-])/.test(line.trim());\n}\n\nfunction isHeadingLike(line: string): boolean {\n\tconst t = line.trim();\n\tif (!/:$/.test(t) || isTagLine(t)) {\n\t\treturn false;\n\t}\n\t/**\n\t * New heuristic: treat as heading only if composed of one or more words that\n\t * each start with an uppercase letter (allows Internal IDs with\n\t * dashes/underscores too). Examples considered headings: \"Overview:\",\n\t * \"Performance Notes:\", \"API Surface:\". Non-headings (treated as sentence\n\t * continuation): \"tested a little bit differently:\", \"differently:\".\n\t */\n\treturn /^[A-Z][A-Za-z0-9_-]*(?: [A-Z][A-Za-z0-9_-]*)*:$/.test(t);\n}\n\nfunction isCodeFence(line: string): boolean {\n\treturn /^```/.test(line.trim());\n}\n\nfunction isVisuallyIndentedCode(line: string): boolean {\n\treturn /^\\s{2,}\\S/.test(line);\n}\n\n/**\n * Detects linter/tool directive comments that should be left untouched.\n * These include ESLint, Biome, Prettier, TypeScript, StyleLint, and coverage\n * tool directives.\n */\nfunction isLinterDirective(text: string): boolean {\n\tconst trimmed = text.trim();\n\treturn /^(@?(?:ts-ignore|ts-expect-error|ts-nocheck|ts-check)|eslint|biome-ignore|prettier-ignore|stylelint-(?:disable|enable)|c8 ignore|v8 ignore|istanbul ignore|tsc:|type:|@ts-)/i.test(\n\t\ttrimmed,\n\t);\n}\n\nfunction wrapWords(text: string, width: number): string[] {\n\tconst words = text.split(/\\s+/).filter(Boolean);\n\tconst lines: string[] = [];\n\tlet cur = \"\";\n\tfor (const w of words) {\n\t\tif (!cur.length) {\n\t\t\tcur = w;\n\t\t\tcontinue;\n\t\t}\n\t\tif (cur.length + 1 + w.length <= width) {\n\t\t\tcur += \" \" + w;\n\t\t} else {\n\t\t\tlines.push(cur);\n\t\t\tcur = w;\n\t\t}\n\t}\n\tif (cur) {\n\t\tlines.push(cur);\n\t}\n\treturn lines.length ? lines : [\"\"];\n}\n\nfunction buildJsDoc(indent: string, rawBody: string, width: number): string {\n\tlet lines = rawBody.split(/\\n/).map((l) => l.replace(/^\\s*\\*? ?/, \"\"));\n\t// Remove a single leading blank line (artifact of regex capture starting after\n\t// /**) if content follows.\n\twhile (\n\t\tlines.length > 1 &&\n\t\tlines[0].trim() === \"\" &&\n\t\tlines.some((l) => l.trim() !== \"\")\n\t) {\n\t\tlines = lines.slice(1);\n\t}\n\t/**\n\t * Trailing blank handling: keep a single trailing blank only if there are\n\t * multiple paragraphs (i.e., an internal blank separator exists). If the doc\n\t * is a single paragraph, drop the trailing blank to avoid an extra standalone\n\t * '*' line before the closing delimiter.\n\t */\n\tif (lines.length > 1 && lines[lines.length - 1].trim() === \"\") {\n\t\tconst internalBlank = lines.slice(0, -1).some((l) => l.trim() === \"\");\n\t\tif (!internalBlank) {\n\t\t\tlines = lines.slice(0, -1);\n\t\t}\n\t}\n\tconst out: string[] = [];\n\tlet para: string[] = [];\n\tlet inFence = false;\n\tconst prefix = indent + \" * \";\n\tconst avail = Math.max(10, width - prefix.length);\n\n\t/**\n\t * Detect structured explanatory / regex description blocks where we want to\n\t * preserve each original line verbatim (no paragraph joining or sentence\n\t * period insertion) to avoid altering carefully aligned or enumerated lines.\n\t */\n\tconst structured = lines.some(\n\t\t(l) =>\n\t\t\t/->/.test(l) ||\n\t\t\t/(\\(?:\\?|\\*\\/)/.test(l) ||\n\t\t\t/Pattern explanation:/i.test(l),\n\t);\n\tif (structured) {\n\t\tfor (const raw of lines) {\n\t\t\tconst trimmed = raw.trimEnd();\n\t\t\tif (trimmed === \"\") {\n\t\t\t\t// ensure a blank line represented by a lone '*'.\n\t\t\t\tif (\n\t\t\t\t\tout.length === 0 ||\n\t\t\t\t\t/^(?:\\s*\\*\\s*)$/.test(out[out.length - 1]) === false\n\t\t\t\t) {\n\t\t\t\t\tout.push(prefix.trimEnd());\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tout.push(prefix + normalizeNote(trimmed));\n\t\t}\n\t\t// Consistent style: space before closing */\n\t\treturn `${indent}/**\\n${out.join(\"\\n\")}\\n${indent} */`;\n\t}\n\n\tfunction flush(): void {\n\t\tif (!para.length) {\n\t\t\treturn;\n\t\t}\n\t\tlet text = para.join(\" \").replace(/\\s+/g, \" \").trim();\n\t\ttext = normalizeNote(text);\n\t\ttext = maybeAddPeriod(text);\n\t\tconst pieces = splitNoteSentences(text);\n\t\tfor (const piece of pieces) {\n\t\t\tfor (const l of wrapWords(piece, avail)) {\n\t\t\t\tout.push(prefix + l);\n\t\t\t}\n\t\t}\n\t\tpara = [];\n\t}\n\n\tlet lineIndex = -1;\n\tfor (const raw of lines) {\n\t\tlineIndex++;\n\t\tconst trimmed = raw.trimEnd();\n\t\tif (isCodeFence(trimmed)) {\n\t\t\tflush();\n\t\t\tinFence = !inFence;\n\t\t\tout.push(prefix + trimmed);\n\t\t\tcontinue;\n\t\t}\n\t\tif (inFence) {\n\t\t\t/**\n\t\t\t * Inside a code fence we preserve content verbatim, but for a blank line we\n\t\t\t * still prefer the canonical ' *' (no trailing space after the star) instead\n\t\t\t * of ' * '.\n\t\t\t */\n\t\t\tif (trimmed === \"\") {\n\t\t\t\tout.push(prefix.trimEnd());\n\t\t\t} else {\n\t\t\t\tout.push(prefix + trimmed);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (\n\t\t\ttrimmed === \"\" ||\n\t\t\tisListLike(trimmed) ||\n\t\t\tisTagLine(trimmed) ||\n\t\t\tisHeadingLike(trimmed) ||\n\t\t\tisVisuallyIndentedCode(raw) ||\n\t\t\t/^NOTE: /.test(normalizeNote(trimmed))\n\t\t) {\n\t\t\tflush();\n\t\t\tif (trimmed === \"\") {\n\t\t\t\tif (\n\t\t\t\t\tout.length === 0 ||\n\t\t\t\t\t/^(?:\\s*\\*\\s*)$/.test(out[out.length - 1]) === false\n\t\t\t\t) {\n\t\t\t\t\tout.push(prefix.trimEnd());\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlet noteLine = normalizeNote(trimmed);\n\t\t\t\tif (/^NOTE: /.test(noteLine) && !/[.!?]$/.test(noteLine)) {\n\t\t\t\t\t/**\n\t\t\t\t\t * Structural lookahead: add period only if the NOTE line is followed by a\n\t\t\t\t\t * boundary (blank line, tag line, list item, heading, code fence, visually\n\t\t\t\t\t * indented code, another NOTE line, or end-of-block). If next non-blank\n\t\t\t\t\t * line is plain prose, skip.\n\t\t\t\t\t */\n\t\t\t\t\tlet addPeriod = true; // assume boundary until proven prose continuation\n\t\t\t\t\tconst look = lineIndex + 1;\n\t\t\t\t\twhile (look < lines.length) {\n\t\t\t\t\t\tconst rawNext = lines[look];\n\t\t\t\t\t\tconst cleaned = rawNext.replace(/^\\s*\\*? ?/, \"\").trimEnd();\n\t\t\t\t\t\tconst trimmedNext = cleaned.trim();\n\t\t\t\t\t\tif (trimmedNext === \"\") {\n\t\t\t\t\t\t\t// Blank line: definite boundary.\n\t\t\t\t\t\t\taddPeriod = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t/^NOTE: /i.test(trimmedNext) ||\n\t\t\t\t\t\t\tisTagLine(trimmedNext) ||\n\t\t\t\t\t\t\tisListLike(trimmedNext) ||\n\t\t\t\t\t\t\tisHeadingLike(trimmedNext) ||\n\t\t\t\t\t\t\tisCodeFence(trimmedNext) ||\n\t\t\t\t\t\t\tisVisuallyIndentedCode(rawNext)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\taddPeriod = true; // boundary structure\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Anything else: treat as prose continuation.\n\t\t\t\t\t\taddPeriod = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t/**\n\t\t\t\t\t * If this is the first NOTE line emitted in the block (no prior non-blank\n\t\t\t\t\t * paragraph lines), we still want a period for consistency even if a prose\n\t\t\t\t\t * continuation follows; treat it as a standalone NOTE sentence introducing\n\t\t\t\t\t * subsequent content.\n\t\t\t\t\t */\n\t\t\t\t\tconst hasPriorContent = out.some(\n\t\t\t\t\t\t(l) => /\\* [^ ]/.test(l) && !/\\* NOTE: /.test(l),\n\t\t\t\t\t);\n\t\t\t\t\tif (addPeriod || !hasPriorContent) {\n\t\t\t\t\t\tnoteLine += \".\";\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tout.push(prefix + noteLine);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tpara.push(trimmed);\n\t}\n\tflush();\n\t/**\n\t * Style: ensure a space precedes the closing *\\/ for consistency with blocks\n\t * generated elsewhere in this tool (merged line comment groups). Previously we\n\t * emitted `${indent}*\\/` which produced an off-by-one visual alignment.\n\t */\n\treturn `${indent}/**\\n${out.join(\"\\n\")}\\n${indent} */`;\n}\n\nfunction reflowJsDocBlocks(\n\tcontent: string,\n\twidth: number,\n): { content: string; blocks: number } {\n\tJSDOC_REGEX.lastIndex = 0;\n\tconst blocks: JsDocMatch[] = [];\n\tlet m: RegExpExecArray | null = JSDOC_REGEX.exec(content);\n\twhile (m) {\n\t\tconst indent = m[1] || \"\";\n\t\tconst body = m[2] || \"\";\n\t\t// Body length guard protects against extremely large comment blocks.\n\t\tif (body.length <= 500_000 && indent.length <= MAX_JSDOC_INDENT) {\n\t\t\tblocks.push({\n\t\t\t\tindent,\n\t\t\t\tbody,\n\t\t\t\tstart: m.index,\n\t\t\t\tend: m.index + m[0].length,\n\t\t\t});\n\t\t}\n\t\tm = JSDOC_REGEX.exec(content);\n\t}\n\tif (!blocks.length) {\n\t\treturn { content, blocks: 0 };\n\t}\n\tlet delta = 0;\n\tlet out = content;\n\tfor (const b of blocks) {\n\t\tconst original = out.slice(b.start + delta, b.end + delta);\n\t\tconst built = buildJsDoc(b.indent, b.body, width);\n\t\tif (original !== built) {\n\t\t\tout = out.slice(0, b.start + delta) + built + out.slice(b.end + delta);\n\t\t\tdelta += built.length - original.length;\n\t\t}\n\t}\n\treturn { content: out, blocks: blocks.length };\n}\n\nfunction wrapLineComments(\n\tcontent: string,\n\twidth: number,\n): { content: string; applied: boolean } {\n\tconst lines = content.split(/\\n/);\n\tlet changed = false;\n\tconst out: string[] = [];\n\tlet i = 0;\n\twhile (i < lines.length) {\n\t\tconst line = lines[i];\n\t\tconst m = /^(\\s*)\\/\\/( ?)(.*)$/.exec(line);\n\t\tif (!m || /^\\/\\/\\//.test(line)) {\n\t\t\tout.push(line);\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\t\t/**\n\t\t * Collect a group of consecutive simple // lines (not triple slash) that are\n\t\t * eligible to be wrapped/merged. We stop before directive lines, URLs, or\n\t\t * triple-slash (reference) comments to avoid altering those semantics.\n\t\t */\n\t\tconst group: { raw: string; indent: string; body: string }[] = [];\n\t\tlet j = i;\n\t\twhile (j < lines.length) {\n\t\t\tconst gm = /^(\\s*)\\/\\/ ?(.*)$/.exec(lines[j]);\n\t\t\tif (!gm || /^\\/\\/\\//.test(lines[j])) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst body = gm[2];\n\t\t\tif (isLinterDirective(body) || /https?:\\/\\//.test(body)) {\n\t\t\t\tbreak; // stop group before directives/URLs; process current line normally\n\t\t\t}\n\t\t\tgroup.push({ raw: lines[j], indent: gm[1], body });\n\t\t\tj++;\n\t\t}\n\t\tif (group.length <= 1) {\n\t\t\t// Single line: existing logic (add period if needed).\n\t\t\tconst indent = m[1];\n\t\t\tconst body = m[3];\n\t\t\tif (isLinterDirective(body) || /https?:\\/\\//.test(body)) {\n\t\t\t\tout.push(line);\n\t\t\t\ti++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst prefix = indent + \"// \";\n\t\t\tconst avail = Math.max(10, width - prefix.length);\n\t\t\tlet text = body.replace(/\\s+/g, \" \").trim();\n\t\t\ttext = normalizeNote(text);\n\t\t\ttext = maybeAddPeriod(text);\n\t\t\tconst wrapped = wrapWords(text, avail).map((w) => prefix + w);\n\t\t\tif (wrapped.join(\"\\n\") !== line) {\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t\tout.push(...wrapped);\n\t\t\ti++;\n\t\t\tcontinue;\n\t\t}\n\t\t/**\n\t\t * Multi-line group: only add terminal punctuation (a single period) to the\n\t\t * final logical sentence if needed. Earlier lines are treated as soft wraps\n\t\t * of the same paragraph; adding periods to each would create spurious\n\t\t * sentence boundaries.\n\t\t */\n\t\tfor (let k = 0; k < group.length; k++) {\n\t\t\tconst { indent, body } = group[k];\n\t\t\tconst prefix = indent + \"// \";\n\t\t\tconst avail = Math.max(10, width - prefix.length);\n\t\t\tlet text = body.replace(/\\s+/g, \" \").trim();\n\t\t\ttext = normalizeNote(text);\n\t\t\tif (k === group.length - 1 && !/:$/.test(text.trim())) {\n\t\t\t\ttext = maybeAddPeriod(text);\n\t\t\t}\n\t\t\tconst wrapped = wrapWords(text, avail).map((w) => prefix + w);\n\t\t\tif (wrapped.join(\"\\n\") !== group[k].raw) {\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t\tout.push(...wrapped);\n\t\t}\n\t\ti = j;\n\t}\n\treturn { content: out.join(\"\\n\"), applied: changed };\n}\n\nfunction mergeLineCommentGroups(content: string): {\n\tcontent: string;\n\tmerged: boolean;\n} {\n\tconst lines = content.split(/\\n/);\n\tconst out: string[] = [];\n\tlet i = 0;\n\tlet merged = false;\n\n\tfunction qualifiesExplanatoryAfterStatement(start: number): boolean {\n\t\t/**\n\t\t * Peek ahead to collect consecutive // lines (excluding triple slash) to\n\t\t * decide if they form a sufficiently large explanatory paragraph that\n\t\t * deserves merging directly after a terminated statement.\n\t\t */\n\t\tconst collected: string[] = [];\n\t\tfor (let k = start; k < lines.length; k++) {\n\t\t\tconst lm = /^(\\s*)\\/\\/( ?)(.*)$/.exec(lines[k]);\n\t\t\tif (!lm || /^\\/\\/\\//.test(lines[k])) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst body = lm[3];\n\t\t\tif (isLinterDirective(body) || /https?:\\/\\//.test(body)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcollected.push(body.trim());\n\t\t}\n\t\tif (collected.length < 3) {\n\t\t\treturn false; // lowered threshold from 4 -> 3 to permit shorter explanatory groups\n\t\t}\n\t\tif (!/^[A-Z]/.test(collected[0])) {\n\t\t\treturn false; // start with capitalized sentence\n\t\t}\n\t\t/**\n\t\t * Avoid matching directive-like or list-lists: require at least one line\n\t\t * containing a space (a sentence fragment vs a single token).\n\t\t */\n\t\treturn collected.some((c) => /\\s/.test(c));\n\t}\n\twhile (i < lines.length) {\n\t\tif (/^\\s*\\/\\//.test(lines[i]) && !/^\\s*\\/\\/\\//.test(lines[i])) {\n\t\t\tconst prev = i > 0 ? lines[i - 1] : \"\";\n\t\t\tconst prevTrim = prev.trim();\n\t\t\tlet contextEligible = prevTrim === \"\" || /[{}\\]),;]$/.test(prevTrim);\n\t\t\t/**\n\t\t\t * Heuristic: also allow large explanatory group after a statement ending\n\t\t\t * with ';' when it qualifies as explanatory so it can be elevated to a block\n\t\t\t * comment rather than remaining a run of // lines.\n\t\t\t */\n\t\t\tif (\n\t\t\t\t!contextEligible &&\n\t\t\t\t/;\\s*$/.test(prevTrim) &&\n\t\t\t\tqualifiesExplanatoryAfterStatement(i)\n\t\t\t) {\n\t\t\t\tcontextEligible = true;\n\t\t\t}\n\t\t\tif (!contextEligible) {\n\t\t\t\tout.push(lines[i]);\n\t\t\t\ti++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst group: { indent: string; text: string }[] = [];\n\t\t\tlet j = i;\n\t\t\twhile (j < lines.length) {\n\t\t\t\tconst lm = /^(\\s*)\\/\\/ ?(.*)$/.exec(lines[j]);\n\t\t\t\tif (!lm || /^\\s*\\/\\/\\//.test(lines[j])) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tconst txt = lm[2];\n\t\t\t\tif (\n\t\t\t\t\t/license|copyright/i.test(txt) ||\n\t\t\t\t\t/https?:\\/\\//.test(txt) ||\n\t\t\t\t\tisLinterDirective(txt)\n\t\t\t\t) {\n\t\t\t\t\tbreak; // do not merge directive / license groups\n\t\t\t\t}\n\t\t\t\tgroup.push({ indent: lm[1], text: txt });\n\t\t\t\tj++;\n\t\t\t}\n\t\t\tif (group.length >= 2) {\n\t\t\t\t/**\n\t\t\t\t * Structured explanatory blocks: now we CONVERT them into a multi-line JSDoc block\n\t\t\t\t * while preserving each original line (instead of merging into a single paragraph).\n\t\t\t\t * We must escape any raw '*\\/' inside the body to avoid premature termination.\n\t\t\t\t * Definition of structured:\n\t\t\t\t * presence of arrows (->), regex tokens (?:, *\\/), or the phrase 'Pattern explanation:'.\n\t\t\t\t */\n\t\t\t\tconst structured = group.some(\n\t\t\t\t\t(g) =>\n\t\t\t\t\t\t/->/.test(g.text) ||\n\t\t\t\t\t\t/(\\(\\?:|\\*\\/)/.test(g.text) ||\n\t\t\t\t\t\t/Pattern explanation:/i.test(g.text),\n\t\t\t\t);\n\t\t\t\tif (structured) {\n\t\t\t\t\tconst indent = group[0].indent;\n\t\t\t\t\tout.push(`${indent}/**`);\n\t\t\t\t\tfor (const ln of group) {\n\t\t\t\t\t\t// Escape closing sentinel inside content.\n\t\t\t\t\t\tconst safe = ln.text.replace(/\\*\\//g, \"*\\\\/\");\n\t\t\t\t\t\tout.push(`${indent} * ${safe}`);\n\t\t\t\t\t}\n\t\t\t\t\tout.push(`${indent} */`);\n\t\t\t\t\tmerged = true;\n\t\t\t\t\ti = j;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst indent = group[0].indent;\n\t\t\t\tmerged = true;\n\t\t\t\t/**\n\t\t\t\t * We only want to add terminal punctuation once at the end of the merged\n\t\t\t\t * paragraph, not after every original line (which can create spurious\n\t\t\t\t * periods mid-sentence when lines were simple wraps). We also avoid\n\t\t\t\t * appending a period if the final line ends with a colon introducing a\n\t\t\t\t * list.\n\t\t\t\t */\n\t\t\t\tconst norm = group.map((g) => normalizeNote(g.text.trim()));\n\t\t\t\t/**\n\t\t\t\t * We only want to add terminal punctuation once at the end of the merged\n\t\t\t\t * paragraph, not after every original line (which can create spurious\n\t\t\t\t * periods mid-sentence when lines were simple wraps). We also avoid\n\t\t\t\t * appending a period if the final line ends with a colon introducing a\n\t\t\t\t * list.\n\t\t\t\t */\n\t\t\t\tlet lastIdx = norm.length - 1;\n\t\t\t\twhile (lastIdx > 0 && norm[lastIdx].trim() === \"\") {\n\t\t\t\t\tlastIdx--;\n\t\t\t\t}\n\t\t\t\tfor (let k = 0; k < norm.length; k++) {\n\t\t\t\t\tif (k === lastIdx) {\n\t\t\t\t\t\tconst ln = norm[k];\n\t\t\t\t\t\tif (!/:$/.test(ln.trim())) {\n\t\t\t\t\t\t\tnorm[k] = maybeAddPeriod(ln);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst para = norm.join(\" \").replace(/\\s+/g, \" \").trim();\n\t\t\t\tout.push(`${indent}/**`);\n\t\t\t\tfor (const seg of splitNoteSentences(para)) {\n\t\t\t\t\tout.push(`${indent} * ${seg}`);\n\t\t\t\t}\n\t\t\t\tout.push(`${indent} */`);\n\t\t\t\ti = j;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\tout.push(lines[i]);\n\t\ti++;\n\t}\n\treturn { content: out.join(\"\\n\"), merged };\n}\n\nexport function parseAndTransformComments(\n\tinput: string,\n\toptions: ProcessOptions,\n): FileResult {\n\tlet working = input;\n\tif (options.mergeLineComments) {\n\t\tconst m = mergeLineCommentGroups(working);\n\t\tworking = m.content;\n\t}\n\tconst js = reflowJsDocBlocks(working, options.width);\n\tworking = js.content;\n\tif (options.wrapLineComments) {\n\t\tconst w = wrapLineComments(working, options.width);\n\t\tworking = w.content;\n\t}\n\treturn { original: input, transformed: working, changed: working !== input };\n}\n"],"names":["Logger","logger","boring","process","env","NODE_ENV","MAX_JSDOC_INDENT","JSDOC_REGEX","diffLines","a","b","A","split","B","out","m","Math","max","length","i","undefined","push","join","endsSentence","line","test","trim","needsTerminalPunctuation","maybeAddPeriod","normalizeNote","replace","splitNoteSentences","text","segments","idx","indexOf","tail","slice","boundary","before","end","note","filter","Boolean","isListLike","isTagLine","isHeadingLike","t","isCodeFence","isVisuallyIndentedCode","isLinterDirective","trimmed","wrapWords","width","words","lines","cur","w","buildJsDoc","indent","rawBody","map","l","some","internalBlank","para","inFence","prefix","avail","structured","raw","trimEnd","flush","pieces","piece","lineIndex","noteLine","addPeriod","look","rawNext","cleaned","trimmedNext","hasPriorContent","reflowJsDocBlocks","content","lastIndex","blocks","exec","body","start","index","delta","original","built","wrapLineComments","group","k","wrapped","changed","j","gm","applied","mergeLineCommentGroups","merged","qualifiesExplanatoryAfterStatement","collected","lm","c","prev","prevTrim","contextEligible","txt","g","ln","safe","norm","lastIdx","seg","parseAndTransformComments","input","options","working","mergeLineComments","js","transformed"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@node-cli/comments",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.14",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Arno Versini",
|
|
6
6
|
"description": "CLI tool to reflow and normalize JSDoc and line comments in source files",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/versini-org/node-cli.git",
|
|
10
|
+
"directory": "packages/comments"
|
|
11
|
+
},
|
|
7
12
|
"type": "module",
|
|
8
13
|
"types": "./dist/index.d.ts",
|
|
9
14
|
"exports": "./dist/lib.js",
|
|
@@ -28,17 +33,17 @@
|
|
|
28
33
|
"watch": "swc --strip-leading-paths --watch --out-dir dist src"
|
|
29
34
|
},
|
|
30
35
|
"dependencies": {
|
|
31
|
-
"@node-cli/logger": "1.3.
|
|
32
|
-
"@node-cli/parser": "2.4.
|
|
33
|
-
"@node-cli/utilities": "1.0.
|
|
36
|
+
"@node-cli/logger": "1.3.9",
|
|
37
|
+
"@node-cli/parser": "2.4.10",
|
|
38
|
+
"@node-cli/utilities": "1.0.10",
|
|
34
39
|
"micromatch": "4.0.8"
|
|
35
40
|
},
|
|
36
41
|
"publishConfig": {
|
|
37
42
|
"access": "public"
|
|
38
43
|
},
|
|
39
44
|
"devDependencies": {
|
|
40
|
-
"@vitest/coverage-v8": "4.1.
|
|
41
|
-
"vitest": "4.1.
|
|
45
|
+
"@vitest/coverage-v8": "4.1.9",
|
|
46
|
+
"vitest": "4.1.9"
|
|
42
47
|
},
|
|
43
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "e0a0d46e7a70371716df420f54a094ba0bfb38b8"
|
|
44
49
|
}
|