@node-cli/comments 0.2.4 → 0.2.5

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.
@@ -323,6 +323,26 @@ describe("parseAndTransformComments", function() {
323
323
  // already).
324
324
  expect(out.match(/merged\./)).toBeNull();
325
325
  });
326
+ it("merges a 3-line explanatory // group after a statement into JSDoc (threshold lowered)", function() {
327
+ var src = [
328
+ "const value = compute();",
329
+ "// First explanatory line that starts with a capital",
330
+ "// second line continues the explanation",
331
+ "// third line completes it",
332
+ "next();"
333
+ ].join("\n");
334
+ var out = parseAndTransformComments(src, {
335
+ width: 120,
336
+ wrapLineComments: true,
337
+ mergeLineComments: true
338
+ }).transformed;
339
+ // The 3-line group should have been converted to a JSDoc block.
340
+ expect(/compute\(\);\n\/\*\*/.test(out)).toBe(true);
341
+ // Ensure original lines no longer start with // (inside block now) and period
342
+ // appended once.
343
+ expect(out).toMatch(/First explanatory line that starts with a capital/);
344
+ expect(out).not.toMatch(/third line completes it\n\/\//); // no stray // after
345
+ });
326
346
  it("keeps a space before closing delimiter for complex multi-paragraph example", function() {
327
347
  var input = [
328
348
  "/**",
@@ -343,9 +363,9 @@ describe("parseAndTransformComments", function() {
343
363
  " */"
344
364
  ].join("\n");
345
365
  var out = parseAndTransformComments(input, baseOpts).transformed;
346
- // Closing line should contain a leading space before */ (style consistency)
366
+ // Closing line should contain a leading space before */ (style consistency).
347
367
  expect(/\n \*\/$/.test(out)).toBe(true);
348
- // Should not regress by emitting no-space variant
368
+ // Should not regress by emitting no-space variant.
349
369
  expect(/\n\*\/$/.test(out)).toBe(false);
350
370
  });
351
371
  it("does not add trailing space on blank '*' lines inside code fences", function() {
@@ -391,6 +411,145 @@ describe("parseAndTransformComments", function() {
391
411
  }
392
412
  }
393
413
  });
414
+ it("isolates mid-paragraph NOTE sentence inside a JSDoc block", function() {
415
+ var input = [
416
+ "/**",
417
+ " * This operation performs work and may take time NOTE: use with caution if running on production systems. It returns a result",
418
+ " */"
419
+ ].join("\n");
420
+ var out = parseAndTransformComments(input, _object_spread_props(_object_spread({}, baseOpts), {
421
+ width: 120
422
+ })).transformed;
423
+ // Ensure NOTE is on its own line.
424
+ expect(/\n \* NOTE: use with caution if running on production systems\.\n/.test(out)).toBe(true);
425
+ // Preceding sentence fragments present and end with period somewhere before
426
+ // NOTE line.
427
+ expect(out).toMatch(/This operation performs work and may take time\n/);
428
+ // Trailing sentence appears after NOTE line with terminal period.
429
+ expect(/NOTE: use with caution[\s\S]*It returns a result\./.test(out)).toBe(true);
430
+ });
431
+ it("keeps NOTE at start of JSDoc on its own line with added period", function() {
432
+ var input = [
433
+ "/**",
434
+ " * note: must initialize the runtime before calling any methods",
435
+ " * subsequent calls depend on global state",
436
+ " */"
437
+ ].join("\n");
438
+ var out = parseAndTransformComments(input, _object_spread_props(_object_spread({}, baseOpts), {
439
+ width: 100
440
+ })).transformed;
441
+ var noteLine = out.split(/\n/).find(function(l) {
442
+ return /NOTE: must initialize/.test(l);
443
+ });
444
+ expect(noteLine).toBeDefined();
445
+ expect(/\.$/.test(noteLine || "")).toBe(true);
446
+ expect(out).toMatch(/subsequent calls depend on global state\./);
447
+ });
448
+ it("isolates multiple NOTE sentences within merged // comment group", function() {
449
+ var src = [
450
+ "// This performs the main task.",
451
+ "// NOTE: side effects may occur.",
452
+ "// It then produces output.",
453
+ "// NOTE: results are cached for 5 minutes.",
454
+ "function run() {}"
455
+ ].join("\n");
456
+ var out = parseAndTransformComments(src, {
457
+ width: 160,
458
+ wrapLineComments: true,
459
+ mergeLineComments: true
460
+ }).transformed;
461
+ var noteLines = out.split(/\n/).filter(function(l) {
462
+ return /NOTE: /.test(l);
463
+ });
464
+ expect(noteLines.length).toBe(2);
465
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
466
+ try {
467
+ for(var _iterator = noteLines[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
468
+ var l = _step.value;
469
+ expect(l.trim()).toMatch(/\.$/);
470
+ }
471
+ } catch (err) {
472
+ _didIteratorError = true;
473
+ _iteratorError = err;
474
+ } finally{
475
+ try {
476
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
477
+ _iterator.return();
478
+ }
479
+ } finally{
480
+ if (_didIteratorError) {
481
+ throw _iteratorError;
482
+ }
483
+ }
484
+ }
485
+ });
486
+ it("splits consecutive NOTE sentences in a single paragraph", function() {
487
+ var input = [
488
+ "/**",
489
+ " * This does work. NOTE: first caveat. NOTE: second caveat. Done",
490
+ " */"
491
+ ].join("\n");
492
+ var out = parseAndTransformComments(input, _object_spread_props(_object_spread({}, baseOpts), {
493
+ width: 100
494
+ })).transformed;
495
+ var lines = out.split(/\n/).filter(function(l) {
496
+ return /^ \* /.test(l);
497
+ });
498
+ var notes = lines.filter(function(l) {
499
+ return /NOTE: /.test(l);
500
+ });
501
+ expect(notes.length).toBe(2);
502
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
503
+ try {
504
+ for(var _iterator = notes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
505
+ var l = _step.value;
506
+ expect(l).toMatch(/\.$/);
507
+ }
508
+ } catch (err) {
509
+ _didIteratorError = true;
510
+ _iteratorError = err;
511
+ } finally{
512
+ try {
513
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
514
+ _iterator.return();
515
+ }
516
+ } finally{
517
+ if (_didIteratorError) {
518
+ throw _iteratorError;
519
+ }
520
+ }
521
+ }
522
+ expect(out).toMatch(/Done\./);
523
+ });
524
+ it("detects NOTE after exclamation boundary", function() {
525
+ var input = [
526
+ "/**",
527
+ " * Success! NOTE: edge case follows. Continue processing",
528
+ " */"
529
+ ].join("\n");
530
+ var out = parseAndTransformComments(input, _object_spread_props(_object_spread({}, baseOpts), {
531
+ width: 120
532
+ })).transformed;
533
+ expect(out).toMatch(/Success!\n \* NOTE: edge case follows\./);
534
+ expect(out).toMatch(/Continue processing\./);
535
+ });
536
+ it("does not force period on NOTE line ending with continuation word when followed by continuation line", function() {
537
+ var input = [
538
+ "/**",
539
+ " * NOTE: we are still using the good old lodash uniqueId when the code is not in",
540
+ " * production, so that the results are a little bit more consistent tests after",
541
+ " * test instead of being completely random.",
542
+ " */"
543
+ ].join("\n");
544
+ var out = parseAndTransformComments(input, _object_spread_props(_object_spread({}, baseOpts), {
545
+ width: 100
546
+ })).transformed;
547
+ // New structural policy: first NOTE line always gets period even if followed
548
+ // by prose.
549
+ expect(out).toMatch(/when the code is not in\./);
550
+ // Ensure final sentence has period.
551
+ expect(/completely random\./.test(out)).toBe(true);
552
+ });
394
553
  });
395
554
 
396
555
  //# sourceMappingURL=lib.test.js.map
@@ -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(\"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"],"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"],"mappings":"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"}
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(\"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"],"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"],"mappings":"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"}
package/dist/lib.js CHANGED
@@ -102,6 +102,57 @@ function maybeAddPeriod(line) {
102
102
  function normalizeNote(line) {
103
103
  return line.replace(/^note:/i, "NOTE:");
104
104
  }
105
+ /**
106
+ * ' at start or immediately after a sentence terminator + space.
107
+ */ function splitNoteSentences(text) {
108
+ if (!/NOTE: /.test(text)) {
109
+ return [
110
+ text
111
+ ];
112
+ }
113
+ var segments = [];
114
+ var i = 0;
115
+ while(i < text.length){
116
+ var idx = text.indexOf("NOTE: ", i);
117
+ if (idx === -1) {
118
+ var tail = text.slice(i).trim();
119
+ if (tail) {
120
+ segments.push(tail);
121
+ }
122
+ break;
123
+ }
124
+ /**
125
+ * Boundary heuristics: start of text, sentence punctuation + space, OR a
126
+ * plain space (allows splitting even when author forgot to terminate the
127
+ * previous sentence before starting a NOTE clause).
128
+ */ var boundary = idx === 0 || /[.!?] /.test(text.slice(Math.max(0, idx - 2), idx + 1)) || text[idx - 1] === " ";
129
+ if (!boundary) {
130
+ i = idx + 6; // skip this occurrence
131
+ continue;
132
+ }
133
+ var before = text.slice(i, idx).trim();
134
+ if (before) {
135
+ segments.push(before);
136
+ }
137
+ var end = idx;
138
+ while(end < text.length && !/[.!?]/.test(text[end])){
139
+ end++;
140
+ }
141
+ if (end < text.length && /[.!?]/.test(text[end])) {
142
+ end++;
143
+ }
144
+ var note = text.slice(idx, end).trim();
145
+ if (!/[.!?]$/.test(note)) {
146
+ note += ".";
147
+ }
148
+ segments.push(note);
149
+ i = end;
150
+ if (text[i] === " ") {
151
+ i++;
152
+ }
153
+ }
154
+ return segments.filter(Boolean);
155
+ }
105
156
  function isListLike(line) {
106
157
  return /^(?:[-*+] |\d+\. )/.test(line.trim());
107
158
  }
@@ -201,7 +252,7 @@ function buildJsDoc(indent, rawBody, width) {
201
252
  * preserve each original line verbatim (no paragraph joining or sentence
202
253
  * period insertion) to avoid altering carefully aligned or enumerated lines.
203
254
  */ var structured = lines.some(function(l) {
204
- return /->/.test(l) || /(\(\?:|\*\/)/.test(l) || /Pattern explanation:/i.test(l);
255
+ return /->/.test(l) || /(\(?:\?|\*\/)/.test(l) || /Pattern explanation:/i.test(l);
205
256
  });
206
257
  if (structured) {
207
258
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
@@ -242,11 +293,31 @@ function buildJsDoc(indent, rawBody, width) {
242
293
  var text = para.join(" ").replace(/\s+/g, " ").trim();
243
294
  text = normalizeNote(text);
244
295
  text = maybeAddPeriod(text);
296
+ var pieces = splitNoteSentences(text);
245
297
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
246
298
  try {
247
- for(var _iterator = wrapWords(text, avail)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
248
- var l = _step.value;
249
- out.push(prefix + l);
299
+ for(var _iterator = pieces[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
300
+ var piece = _step.value;
301
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
302
+ try {
303
+ for(var _iterator1 = wrapWords(piece, avail)[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
304
+ var l = _step1.value;
305
+ out.push(prefix + l);
306
+ }
307
+ } catch (err) {
308
+ _didIteratorError1 = true;
309
+ _iteratorError1 = err;
310
+ } finally{
311
+ try {
312
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
313
+ _iterator1.return();
314
+ }
315
+ } finally{
316
+ if (_didIteratorError1) {
317
+ throw _iteratorError1;
318
+ }
319
+ }
320
+ }
250
321
  }
251
322
  } catch (err) {
252
323
  _didIteratorError = true;
@@ -264,10 +335,12 @@ function buildJsDoc(indent, rawBody, width) {
264
335
  }
265
336
  para = [];
266
337
  }
338
+ var lineIndex = -1;
267
339
  var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
268
340
  try {
269
341
  for(var _iterator1 = lines[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
270
342
  var raw1 = _step1.value;
343
+ lineIndex++;
271
344
  var trimmed1 = raw1.trimEnd();
272
345
  if (isCodeFence(trimmed1)) {
273
346
  flush();
@@ -276,24 +349,63 @@ function buildJsDoc(indent, rawBody, width) {
276
349
  continue;
277
350
  }
278
351
  if (inFence) {
279
- // Inside a code fence we preserve content verbatim, but for a blank line
280
- // we still prefer the canonical ' *' (no trailing space after the star)
281
- // instead of ' * '.
282
- if (trimmed1 === "") {
352
+ /**
353
+ * Inside a code fence we preserve content verbatim, but for a blank line we
354
+ * still prefer the canonical ' *' (no trailing space after the star) instead
355
+ * of ' * '.
356
+ */ if (trimmed1 === "") {
283
357
  out.push(prefix.trimEnd());
284
358
  } else {
285
359
  out.push(prefix + trimmed1);
286
360
  }
287
361
  continue;
288
362
  }
289
- if (trimmed1 === "" || isListLike(trimmed1) || isTagLine(trimmed1) || isHeadingLike(trimmed1) || isVisuallyIndentedCode(raw1)) {
363
+ if (trimmed1 === "" || isListLike(trimmed1) || isTagLine(trimmed1) || isHeadingLike(trimmed1) || isVisuallyIndentedCode(raw1) || /^NOTE: /.test(normalizeNote(trimmed1))) {
290
364
  flush();
291
365
  if (trimmed1 === "") {
292
366
  if (out.length === 0 || /^(?:\s*\*\s*)$/.test(out[out.length - 1]) === false) {
293
367
  out.push(prefix.trimEnd());
294
368
  }
295
369
  } else {
296
- out.push(prefix + normalizeNote(trimmed1));
370
+ var noteLine = normalizeNote(trimmed1);
371
+ if (/^NOTE: /.test(noteLine) && !/[.!?]$/.test(noteLine)) {
372
+ /**
373
+ * Structural lookahead: add period only if the NOTE line is followed by a
374
+ * boundary (blank line, tag line, list item, heading, code fence, visually
375
+ * indented code, another NOTE line, or end-of-block). If next non-blank
376
+ * line is plain prose, skip.
377
+ */ var addPeriod = true; // assume boundary until proven prose continuation
378
+ var look = lineIndex + 1;
379
+ while(look < lines.length){
380
+ var rawNext = lines[look];
381
+ var cleaned = rawNext.replace(/^\s*\*? ?/, "").trimEnd();
382
+ var trimmedNext = cleaned.trim();
383
+ if (trimmedNext === "") {
384
+ // Blank line: definite boundary.
385
+ addPeriod = true;
386
+ break;
387
+ }
388
+ if (/^NOTE: /i.test(trimmedNext) || isTagLine(trimmedNext) || isListLike(trimmedNext) || isHeadingLike(trimmedNext) || isCodeFence(trimmedNext) || isVisuallyIndentedCode(rawNext)) {
389
+ addPeriod = true; // boundary structure
390
+ break;
391
+ }
392
+ // Anything else: treat as prose continuation.
393
+ addPeriod = false;
394
+ break;
395
+ }
396
+ /**
397
+ * If this is the first NOTE line emitted in the block (no prior non-blank
398
+ * paragraph lines), we still want a period for consistency even if a prose
399
+ * continuation follows; treat it as a standalone NOTE sentence introducing
400
+ * subsequent content.
401
+ */ var hasPriorContent = out.some(function(l) {
402
+ return /\* [^ ]/.test(l) && !/\* NOTE: /.test(l);
403
+ });
404
+ if (addPeriod || !hasPriorContent) {
405
+ noteLine += ".";
406
+ }
407
+ }
408
+ out.push(prefix + noteLine);
297
409
  }
298
410
  continue;
299
411
  }
@@ -314,10 +426,11 @@ function buildJsDoc(indent, rawBody, width) {
314
426
  }
315
427
  }
316
428
  flush();
317
- // Style: ensure a space precedes the closing */ for consistency with blocks
318
- // generated elsewhere in this tool (merged line comment groups). Previously
319
- // we emitted `${indent}*/` which produced an off-by-one visual alignment.
320
- return "".concat(indent, "/**\n").concat(out.join("\n"), "\n").concat(indent, " */");
429
+ /**
430
+ * Style: ensure a space precedes the closing *\/ for consistency with blocks
431
+ * generated elsewhere in this tool (merged line comment groups). Previously we
432
+ * emitted `${indent}*\/` which produced an off-by-one visual alignment.
433
+ */ return "".concat(indent, "/**\n").concat(out.join("\n"), "\n").concat(indent, " */");
321
434
  }
322
435
  function reflowJsDocBlocks(content, width) {
323
436
  JSDOC_REGEX.lastIndex = 0;
@@ -404,7 +517,8 @@ function wrapLineComments(content, width) {
404
517
  }
405
518
  /**
406
519
  * Collect a group of consecutive simple // lines (not triple slash) that are
407
- * eligible.
520
+ * eligible to be wrapped/merged. We stop before directive lines, URLs, or
521
+ * triple-slash (reference) comments to avoid altering those semantics.
408
522
  */ var group = [];
409
523
  var j = i;
410
524
  while(j < lines.length){
@@ -449,9 +563,10 @@ function wrapLineComments(content, width) {
449
563
  return "continue";
450
564
  }
451
565
  /**
452
- * Multi-line group: only add terminal punctuation (period) to final line if
453
- * needed. Other lines are normalized for NOTE but left without forced
454
- * punctuation.
566
+ * Multi-line group: only add terminal punctuation (a single period) to the
567
+ * final logical sentence if needed. Earlier lines are treated as soft wraps
568
+ * of the same paragraph; adding periods to each would create spurious
569
+ * sentence boundaries.
455
570
  */ for(var k = 0; k < group.length; k++)_loop(k);
456
571
  i = j;
457
572
  };
@@ -471,8 +586,11 @@ function mergeLineCommentGroups(content) {
471
586
  var i = 0;
472
587
  var merged = false;
473
588
  function qualifiesExplanatoryAfterStatement(start) {
474
- // Peek ahead to collect consecutive // lines (excluding triple slash).
475
- var collected = [];
589
+ /**
590
+ * Peek ahead to collect consecutive // lines (excluding triple slash) to
591
+ * decide if they form a sufficiently large explanatory paragraph that
592
+ * deserves merging directly after a terminated statement.
593
+ */ var collected = [];
476
594
  for(var k = start; k < lines.length; k++){
477
595
  var lm = /^(\s*)\/\/( ?)(.*)$/.exec(lines[k]);
478
596
  if (!lm || /^\/\/\//.test(lines[k])) {
@@ -484,15 +602,15 @@ function mergeLineCommentGroups(content) {
484
602
  }
485
603
  collected.push(body.trim());
486
604
  }
487
- if (collected.length < 4) {
488
- return false; // require minimum size
605
+ if (collected.length < 3) {
606
+ return false; // lowered threshold from 4 -> 3 to permit shorter explanatory groups
489
607
  }
490
608
  if (!/^[A-Z]/.test(collected[0])) {
491
609
  return false; // start with capitalized sentence
492
610
  }
493
611
  /**
494
- * Avoid matching directive-like or list-lists: require at least one line with
495
- * a space (a sentence).
612
+ * Avoid matching directive-like or list-lists: require at least one line
613
+ * containing a space (a sentence fragment vs a single token).
496
614
  */ return collected.some(function(c) {
497
615
  return /\s/.test(c);
498
616
  });
@@ -503,9 +621,9 @@ function mergeLineCommentGroups(content) {
503
621
  var prevTrim = prev.trim();
504
622
  var contextEligible = prevTrim === "" || /[{}]$/.test(prevTrim);
505
623
  /**
506
- * Additional heuristic: allow large explanatory group after a statement
507
- * ending with ';' (but not inline trailing comment scenario) when it
508
- * qualifies as explanatory.
624
+ * Heuristic: also allow large explanatory group after a statement ending
625
+ * with ';' when it qualifies as explanatory so it can be elevated to a block
626
+ * comment rather than remaining a run of // lines.
509
627
  */ if (!contextEligible && /;\s*$/.test(prevTrim) && qualifiesExplanatoryAfterStatement(i)) {
510
628
  contextEligible = true;
511
629
  }
@@ -582,8 +700,13 @@ function mergeLineCommentGroups(content) {
582
700
  */ var norm = group.map(function(g) {
583
701
  return normalizeNote(g.text.trim());
584
702
  });
585
- // Determine index of last non-empty line.
586
- var lastIdx = norm.length - 1;
703
+ /**
704
+ * We only want to add terminal punctuation once at the end of the merged
705
+ * paragraph, not after every original line (which can create spurious
706
+ * periods mid-sentence when lines were simple wraps). We also avoid
707
+ * appending a period if the final line ends with a colon introducing a
708
+ * list.
709
+ */ var lastIdx = norm.length - 1;
587
710
  while(lastIdx > 0 && norm[lastIdx].trim() === ""){
588
711
  lastIdx--;
589
712
  }
@@ -597,7 +720,26 @@ function mergeLineCommentGroups(content) {
597
720
  }
598
721
  var para = norm.join(" ").replace(/\s+/g, " ").trim();
599
722
  out.push("".concat(indent1, "/**"));
600
- out.push("".concat(indent1, " * ").concat(para));
723
+ var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
724
+ try {
725
+ for(var _iterator1 = splitNoteSentences(para)[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
726
+ var seg = _step1.value;
727
+ out.push("".concat(indent1, " * ").concat(seg));
728
+ }
729
+ } catch (err) {
730
+ _didIteratorError1 = true;
731
+ _iteratorError1 = err;
732
+ } finally{
733
+ try {
734
+ if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
735
+ _iterator1.return();
736
+ }
737
+ } finally{
738
+ if (_didIteratorError1) {
739
+ throw _iteratorError1;
740
+ }
741
+ }
742
+ }
601
743
  out.push("".concat(indent1, " */"));
602
744
  i = j;
603
745
  continue;
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\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\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) || /(\\(\\?:|\\*\\/)/.test(l) || /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\tfor (const l of wrapWords(text, avail)) {\n\t\t\tout.push(prefix + l);\n\t\t}\n\t\tpara = [];\n\t}\n\n\tfor (const raw of lines) {\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// Inside a code fence we preserve content verbatim, but for a blank line\n\t\t\t// we still prefer the canonical ' *' (no trailing space after the star)\n\t\t\t// instead of ' * '.\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) {\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\tout.push(prefix + normalizeNote(trimmed));\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tpara.push(trimmed);\n\t}\n\tflush();\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\n\t// we emitted `${indent}*/` which produced an off-by-one visual alignment.\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.\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 (/^(@|eslint|ts-ignore)/.test(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 (/^(@|eslint|ts-ignore)/.test(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 (period) to final line if\n\t\t * needed. Other lines are normalized for NOTE but left without forced\n\t\t * punctuation.\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// Peek ahead to collect consecutive // lines (excluding triple slash).\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 (/^(@|eslint|ts-ignore)/.test(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 < 4) {\n\t\t\treturn false; // require minimum size\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 with\n\t\t * a space (a sentence).\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 * Additional heuristic: allow large explanatory group after a statement\n\t\t\t * ending with ';' (but not inline trailing comment scenario) when it\n\t\t\t * qualifies as explanatory.\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\t/eslint|ts-ignore/.test(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// Determine index of last non-empty line.\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\tout.push(`${indent} * ${para}`);\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","isListLike","isTagLine","isHeadingLike","t","isCodeFence","isVisuallyIndentedCode","wrapWords","text","width","words","filter","Boolean","lines","cur","w","buildJsDoc","indent","rawBody","map","l","some","slice","internalBlank","para","inFence","prefix","avail","structured","raw","trimmed","trimEnd","flush","reflowJsDocBlocks","content","lastIndex","blocks","exec","body","start","index","end","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","parseAndTransformComments","input","options","working","mergeLineComments","js","transformed"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAASA,MAAM,QAAQ,mBAAmB;AAE1C,OAAO,IAAMC,SAAS,IAAID,OAAO;IAAEE,QAAQC,QAAQC,GAAG,CAACC,QAAQ,KAAK;AAAO,GAAG;AAqB9E;;;;;;;CAOC,GACD,IAAMC,mBAAmB,KAAK,6BAA6B;AAE3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCC,GACD,IAAMC,cAAc;AAEpB,OAAO,SAASC,UAAUC,CAAS,EAAEC,CAAS;IAC7C,IAAID,MAAMC,GAAG;QACZ,OAAO;IACR;IACA,IAAMC,IAAIF,EAAEG,KAAK,CAAC;IAClB,IAAMC,IAAIH,EAAEE,KAAK,CAAC;IAClB,IAAME,MAAgB,EAAE;IACxB,IAAMC,IAAIC,KAAKC,GAAG,CAACN,EAAEO,MAAM,EAAEL,EAAEK,MAAM;IACrC,IAAK,IAAIC,IAAI,GAAGA,IAAIJ,GAAGI,IAAK;QAC3B,IAAIR,CAAC,CAACQ,EAAE,KAAKN,CAAC,CAACM,EAAE,EAAE;YAClB;QACD;QACA,IAAIR,CAAC,CAACQ,EAAE,KAAKC,WAAW;YACvBN,IAAIO,IAAI,CAAC,AAAC,KAAS,OAALV,CAAC,CAACQ,EAAE;QACnB;QACA,IAAIN,CAAC,CAACM,EAAE,KAAKC,WAAW;YACvBN,IAAIO,IAAI,CAAC,AAAC,KAAS,OAALR,CAAC,CAACM,EAAE;QACnB;IACD;IACA,OAAOL,IAAIQ,IAAI,CAAC;AACjB;AAEA,SAASC,aAAaC,IAAY;IACjC,OAAO,qBAAqBC,IAAI,CAACD,KAAKE,IAAI;AAC3C;AAEA,SAASC,yBAAyBH,IAAY;IAC7C,OAAO,oBAAoBC,IAAI,CAACD,SAAS,CAACD,aAAaC;AACxD;AAEA,SAASI,eAAeJ,IAAY;IACnC,OAAOG,yBAAyBH,QAAQA,OAAO,MAAMA;AACtD;AAEA,SAASK,cAAcL,IAAY;IAClC,OAAOA,KAAKM,OAAO,CAAC,WAAW;AAChC;AAEA,SAASC,WAAWP,IAAY;IAC/B,OAAO,qBAAqBC,IAAI,CAACD,KAAKE,IAAI;AAC3C;AAEA,SAASM,UAAUR,IAAY;IAC9B,OAAO,KAAKC,IAAI,CAACD,KAAKE,IAAI;AAC3B;AAEA,SAASO,cAAcT,IAAY;IAClC,IAAMU,IAAIV,KAAKE,IAAI;IACnB,IAAI,CAAC,KAAKD,IAAI,CAACS,MAAMF,UAAUE,IAAI;QAClC,OAAO;IACR;IACA;;;;;;EAMC,GACD,OAAO,kDAAkDT,IAAI,CAACS;AAC/D;AAEA,SAASC,YAAYX,IAAY;IAChC,OAAO,OAAOC,IAAI,CAACD,KAAKE,IAAI;AAC7B;AAEA,SAASU,uBAAuBZ,IAAY;IAC3C,OAAO,YAAYC,IAAI,CAACD;AACzB;AAEA,SAASa,UAAUC,IAAY,EAAEC,KAAa;IAC7C,IAAMC,QAAQF,KAAK1B,KAAK,CAAC,OAAO6B,MAAM,CAACC;IACvC,IAAMC,QAAkB,EAAE;IAC1B,IAAIC,MAAM;QACL,kCAAA,2BAAA;;QAAL,QAAK,YAAWJ,0BAAX,SAAA,6BAAA,QAAA,yBAAA,iCAAkB;YAAlB,IAAMK,IAAN;YACJ,IAAI,CAACD,IAAI1B,MAAM,EAAE;gBAChB0B,MAAMC;gBACN;YACD;YACA,IAAID,IAAI1B,MAAM,GAAG,IAAI2B,EAAE3B,MAAM,IAAIqB,OAAO;gBACvCK,OAAO,MAAMC;YACd,OAAO;gBACNF,MAAMtB,IAAI,CAACuB;gBACXA,MAAMC;YACP;QACD;;QAXK;QAAA;;;iBAAA,6BAAA;gBAAA;;;gBAAA;sBAAA;;;;IAYL,IAAID,KAAK;QACRD,MAAMtB,IAAI,CAACuB;IACZ;IACA,OAAOD,MAAMzB,MAAM,GAAGyB,QAAQ;QAAC;KAAG;AACnC;AAEA,SAASG,WAAWC,MAAc,EAAEC,OAAe,EAAET,KAAa;IACjE,IAAII,QAAQK,QAAQpC,KAAK,CAAC,MAAMqC,GAAG,CAAC,SAACC;eAAMA,EAAEpB,OAAO,CAAC,aAAa;;IAClE,+EAA+E;IAC/E,2BAA2B;IAC3B,MACCa,MAAMzB,MAAM,GAAG,KACfyB,KAAK,CAAC,EAAE,CAACjB,IAAI,OAAO,MACpBiB,MAAMQ,IAAI,CAAC,SAACD;eAAMA,EAAExB,IAAI,OAAO;OAC9B;QACDiB,QAAQA,MAAMS,KAAK,CAAC;IACrB;IACA;;;;;EAKC,GACD,IAAIT,MAAMzB,MAAM,GAAG,KAAKyB,KAAK,CAACA,MAAMzB,MAAM,GAAG,EAAE,CAACQ,IAAI,OAAO,IAAI;QAC9D,IAAM2B,gBAAgBV,MAAMS,KAAK,CAAC,GAAG,CAAC,GAAGD,IAAI,CAAC,SAACD;mBAAMA,EAAExB,IAAI,OAAO;;QAClE,IAAI,CAAC2B,eAAe;YACnBV,QAAQA,MAAMS,KAAK,CAAC,GAAG,CAAC;QACzB;IACD;IACA,IAAMtC,MAAgB,EAAE;IACxB,IAAIwC,OAAiB,EAAE;IACvB,IAAIC,UAAU;IACd,IAAMC,SAAST,SAAS;IACxB,IAAMU,QAAQzC,KAAKC,GAAG,CAAC,IAAIsB,QAAQiB,OAAOtC,MAAM;IAEhD;;;;EAIC,GACD,IAAMwC,aAAaf,MAAMQ,IAAI,CAC5B,SAACD;eACA,KAAKzB,IAAI,CAACyB,MAAM,eAAezB,IAAI,CAACyB,MAAM,wBAAwBzB,IAAI,CAACyB;;IAEzE,IAAIQ,YAAY;YACV,kCAAA,2BAAA;;YAAL,QAAK,YAAaf,0BAAb,SAAA,6BAAA,QAAA,yBAAA,iCAAoB;gBAApB,IAAMgB,MAAN;gBACJ,IAAMC,UAAUD,IAAIE,OAAO;gBAC3B,IAAID,YAAY,IAAI;oBACnB,iDAAiD;oBACjD,IACC9C,IAAII,MAAM,KAAK,KACf,iBAAiBO,IAAI,CAACX,GAAG,CAACA,IAAII,MAAM,GAAG,EAAE,MAAM,OAC9C;wBACDJ,IAAIO,IAAI,CAACmC,OAAOK,OAAO;oBACxB;oBACA;gBACD;gBACA/C,IAAIO,IAAI,CAACmC,SAAS3B,cAAc+B;YACjC;;YAbK;YAAA;;;qBAAA,6BAAA;oBAAA;;;oBAAA;0BAAA;;;;QAcL,4CAA4C;QAC5C,OAAO,AAAC,GAAgB9C,OAAdiC,QAAO,SAA0BA,OAAnBjC,IAAIQ,IAAI,CAAC,OAAM,MAAW,OAAPyB,QAAO;IACnD;IAEA,SAASe;QACR,IAAI,CAACR,KAAKpC,MAAM,EAAE;YACjB;QACD;QACA,IAAIoB,OAAOgB,KAAKhC,IAAI,CAAC,KAAKQ,OAAO,CAAC,QAAQ,KAAKJ,IAAI;QACnDY,OAAOT,cAAcS;QACrBA,OAAOV,eAAeU;YACjB,kCAAA,2BAAA;;YAAL,QAAK,YAAWD,UAAUC,MAAMmB,2BAA3B,SAAA,6BAAA,QAAA,yBAAA,iCAAmC;gBAAnC,IAAMP,IAAN;gBACJpC,IAAIO,IAAI,CAACmC,SAASN;YACnB;;YAFK;YAAA;;;qBAAA,6BAAA;oBAAA;;;oBAAA;0BAAA;;;;QAGLI,OAAO,EAAE;IACV;QAEK,mCAAA,4BAAA;;QAAL,QAAK,aAAaX,0BAAb,UAAA,8BAAA,SAAA,0BAAA,kCAAoB;YAApB,IAAMgB,OAAN;YACJ,IAAMC,WAAUD,KAAIE,OAAO;YAC3B,IAAI1B,YAAYyB,WAAU;gBACzBE;gBACAP,UAAU,CAACA;gBACXzC,IAAIO,IAAI,CAACmC,SAASI;gBAClB;YACD;YACA,IAAIL,SAAS;gBACZ,yEAAyE;gBACzE,wEAAwE;gBACxE,oBAAoB;gBACpB,IAAIK,aAAY,IAAI;oBACnB9C,IAAIO,IAAI,CAACmC,OAAOK,OAAO;gBACxB,OAAO;oBACN/C,IAAIO,IAAI,CAACmC,SAASI;gBACnB;gBACA;YACD;YACA,IACCA,aAAY,MACZ7B,WAAW6B,aACX5B,UAAU4B,aACV3B,cAAc2B,aACdxB,uBAAuBuB,OACtB;gBACDG;gBACA,IAAIF,aAAY,IAAI;oBACnB,IACC9C,IAAII,MAAM,KAAK,KACf,iBAAiBO,IAAI,CAACX,GAAG,CAACA,IAAII,MAAM,GAAG,EAAE,MAAM,OAC9C;wBACDJ,IAAIO,IAAI,CAACmC,OAAOK,OAAO;oBACxB;gBACD,OAAO;oBACN/C,IAAIO,IAAI,CAACmC,SAAS3B,cAAc+B;gBACjC;gBACA;YACD;YACAN,KAAKjC,IAAI,CAACuC;QACX;;QAxCK;QAAA;;;iBAAA,8BAAA;gBAAA;;;gBAAA;sBAAA;;;;IAyCLE;IACA,4EAA4E;IAC5E,4EAA4E;IAC5E,0EAA0E;IAC1E,OAAO,AAAC,GAAgBhD,OAAdiC,QAAO,SAA0BA,OAAnBjC,IAAIQ,IAAI,CAAC,OAAM,MAAW,OAAPyB,QAAO;AACnD;AAEA,SAASgB,kBACRC,OAAe,EACfzB,KAAa;IAEbhC,YAAY0D,SAAS,GAAG;IACxB,IAAMC,SAAuB,EAAE;IAC/B,IAAInD,IAA4BR,YAAY4D,IAAI,CAACH;IACjD,MAAOjD,EAAG;QACT,IAAMgC,SAAShC,CAAC,CAAC,EAAE,IAAI;QACvB,IAAMqD,OAAOrD,CAAC,CAAC,EAAE,IAAI;QACrB,qEAAqE;QACrE,IAAIqD,KAAKlD,MAAM,IAAI,UAAW6B,OAAO7B,MAAM,IAAIZ,kBAAkB;YAChE4D,OAAO7C,IAAI,CAAC;gBACX0B,QAAAA;gBACAqB,MAAAA;gBACAC,OAAOtD,EAAEuD,KAAK;gBACdC,KAAKxD,EAAEuD,KAAK,GAAGvD,CAAC,CAAC,EAAE,CAACG,MAAM;YAC3B;QACD;QACAH,IAAIR,YAAY4D,IAAI,CAACH;IACtB;IACA,IAAI,CAACE,OAAOhD,MAAM,EAAE;QACnB,OAAO;YAAE8C,SAAAA;YAASE,QAAQ;QAAE;IAC7B;IACA,IAAIM,QAAQ;IACZ,IAAI1D,MAAMkD;QACL,kCAAA,2BAAA;;QAAL,QAAK,YAAWE,2BAAX,SAAA,6BAAA,QAAA,yBAAA,iCAAmB;YAAnB,IAAMxD,IAAN;YACJ,IAAM+D,WAAW3D,IAAIsC,KAAK,CAAC1C,EAAE2D,KAAK,GAAGG,OAAO9D,EAAE6D,GAAG,GAAGC;YACpD,IAAME,QAAQ5B,WAAWpC,EAAEqC,MAAM,EAAErC,EAAE0D,IAAI,EAAE7B;YAC3C,IAAIkC,aAAaC,OAAO;gBACvB5D,MAAMA,IAAIsC,KAAK,CAAC,GAAG1C,EAAE2D,KAAK,GAAGG,SAASE,QAAQ5D,IAAIsC,KAAK,CAAC1C,EAAE6D,GAAG,GAAGC;gBAChEA,SAASE,MAAMxD,MAAM,GAAGuD,SAASvD,MAAM;YACxC;QACD;;QAPK;QAAA;;;iBAAA,6BAAA;gBAAA;;;gBAAA;sBAAA;;;;IAQL,OAAO;QAAE8C,SAASlD;QAAKoD,QAAQA,OAAOhD,MAAM;IAAC;AAC9C;AAEA,SAASyD,iBACRX,OAAe,EACfzB,KAAa;;;gBAwEXzB;YAZA,IAAyB8D,WAAAA,KAAK,CAACC,EAAE,EAAzB9B,SAAiB6B,SAAjB7B,QAAQqB,OAASQ,SAATR;YAChB,IAAMZ,SAAST,SAAS;YACxB,IAAMU,QAAQzC,KAAKC,GAAG,CAAC,IAAIsB,QAAQiB,OAAOtC,MAAM;YAChD,IAAIoB,OAAO8B,KAAKtC,OAAO,CAAC,QAAQ,KAAKJ,IAAI;YACzCY,OAAOT,cAAcS;YACrB,IAAIuC,MAAMD,MAAM1D,MAAM,GAAG,KAAK,CAAC,KAAKO,IAAI,CAACa,KAAKZ,IAAI,KAAK;gBACtDY,OAAOV,eAAeU;YACvB;YACA,IAAMwC,UAAUzC,UAAUC,MAAMmB,OAAOR,GAAG,CAAC,SAACJ;uBAAMW,SAASX;;YAC3D,IAAIiC,QAAQxD,IAAI,CAAC,UAAUsD,KAAK,CAACC,EAAE,CAAClB,GAAG,EAAE;gBACxCoB,UAAU;YACX;YACAjE,CAAAA,OAAAA,KAAIO,IAAI,OAARP,MAAS,qBAAGgE;QACb;QAlEA,IAAMtD,OAAOmB,KAAK,CAACxB,EAAE;QACrB,IAAMJ,IAAI,sBAAsBoD,IAAI,CAAC3C;QACrC,IAAI,CAACT,KAAK,UAAUU,IAAI,CAACD,OAAO;YAC/BV,IAAIO,IAAI,CAACG;YACTL;YACA,OAAA;QACD;QACA;;;GAGC,GACD,IAAMyD,QAAyD,EAAE;QACjE,IAAII,IAAI7D;QACR,MAAO6D,IAAIrC,MAAMzB,MAAM,CAAE;YACxB,IAAM+D,KAAK,oBAAoBd,IAAI,CAACxB,KAAK,CAACqC,EAAE;YAC5C,IAAI,CAACC,MAAM,UAAUxD,IAAI,CAACkB,KAAK,CAACqC,EAAE,GAAG;gBACpC;YACD;YACA,IAAMZ,OAAOa,EAAE,CAAC,EAAE;YAClB,IAAI,wBAAwBxD,IAAI,CAAC2C,SAAS,cAAc3C,IAAI,CAAC2C,OAAO;gBACnE,OAAO,mEAAmE;YAC3E;YACAQ,MAAMvD,IAAI,CAAC;gBAAEsC,KAAKhB,KAAK,CAACqC,EAAE;gBAAEjC,QAAQkC,EAAE,CAAC,EAAE;gBAAEb,MAAAA;YAAK;YAChDY;QACD;QACA,IAAIJ,MAAM1D,MAAM,IAAI,GAAG;gBAkBtBJ;YAjBA,sDAAsD;YACtD,IAAMiC,SAAShC,CAAC,CAAC,EAAE;YACnB,IAAMqD,QAAOrD,CAAC,CAAC,EAAE;YACjB,IAAI,wBAAwBU,IAAI,CAAC2C,UAAS,cAAc3C,IAAI,CAAC2C,QAAO;gBACnEtD,IAAIO,IAAI,CAACG;gBACTL;gBACA,OAAA;YACD;YACA,IAAMqC,SAAST,SAAS;YACxB,IAAMU,QAAQzC,KAAKC,GAAG,CAAC,IAAIsB,QAAQiB,OAAOtC,MAAM;YAChD,IAAIoB,OAAO8B,MAAKtC,OAAO,CAAC,QAAQ,KAAKJ,IAAI;YACzCY,OAAOT,cAAcS;YACrBA,OAAOV,eAAeU;YACtB,IAAMwC,UAAUzC,UAAUC,MAAMmB,OAAOR,GAAG,CAAC,SAACJ;uBAAMW,SAASX;;YAC3D,IAAIiC,QAAQxD,IAAI,CAAC,UAAUE,MAAM;gBAChCuD,UAAU;YACX;YACAjE,CAAAA,OAAAA,KAAIO,IAAI,OAARP,MAAS,qBAAGgE;YACZ3D;YACA,OAAA;QACD;QACA;;;;GAIC,GACD,IAAK,IAAI0D,IAAI,GAAGA,IAAID,MAAM1D,MAAM,EAAE2D;QAelC1D,IAAI6D;IACL;IAzEA,IAAMrC,QAAQqB,QAAQpD,KAAK,CAAC;IAC5B,IAAImE,UAAU;IACd,IAAMjE,MAAgB,EAAE;IACxB,IAAIK,IAAI;IACR,MAAOA,IAAIwB,MAAMzB,MAAM;IAsEvB,OAAO;QAAE8C,SAASlD,IAAIQ,IAAI,CAAC;QAAO4D,SAASH;IAAQ;AACpD;AAEA,SAASI,uBAAuBnB,OAAe;IAI9C,IAAMrB,QAAQqB,QAAQpD,KAAK,CAAC;IAC5B,IAAME,MAAgB,EAAE;IACxB,IAAIK,IAAI;IACR,IAAIiE,SAAS;IAEb,SAASC,mCAAmChB,KAAa;QACxD,uEAAuE;QACvE,IAAMiB,YAAsB,EAAE;QAC9B,IAAK,IAAIT,IAAIR,OAAOQ,IAAIlC,MAAMzB,MAAM,EAAE2D,IAAK;YAC1C,IAAMU,KAAK,sBAAsBpB,IAAI,CAACxB,KAAK,CAACkC,EAAE;YAC9C,IAAI,CAACU,MAAM,UAAU9D,IAAI,CAACkB,KAAK,CAACkC,EAAE,GAAG;gBACpC;YACD;YACA,IAAMT,OAAOmB,EAAE,CAAC,EAAE;YAClB,IAAI,wBAAwB9D,IAAI,CAAC2C,SAAS,cAAc3C,IAAI,CAAC2C,OAAO;gBACnE;YACD;YACAkB,UAAUjE,IAAI,CAAC+C,KAAK1C,IAAI;QACzB;QACA,IAAI4D,UAAUpE,MAAM,GAAG,GAAG;YACzB,OAAO,OAAO,uBAAuB;QACtC;QACA,IAAI,CAAC,SAASO,IAAI,CAAC6D,SAAS,CAAC,EAAE,GAAG;YACjC,OAAO,OAAO,kCAAkC;QACjD;QACA;;;GAGC,GACD,OAAOA,UAAUnC,IAAI,CAAC,SAACqC;mBAAM,KAAK/D,IAAI,CAAC+D;;IACxC;IACA,MAAOrE,IAAIwB,MAAMzB,MAAM,CAAE;QACxB,IAAI,WAAWO,IAAI,CAACkB,KAAK,CAACxB,EAAE,KAAK,CAAC,aAAaM,IAAI,CAACkB,KAAK,CAACxB,EAAE,GAAG;YAC9D,IAAMsE,OAAOtE,IAAI,IAAIwB,KAAK,CAACxB,IAAI,EAAE,GAAG;YACpC,IAAMuE,WAAWD,KAAK/D,IAAI;YAC1B,IAAIiE,kBAAkBD,aAAa,MAAM,QAAQjE,IAAI,CAACiE;YACtD;;;;IAIC,GACD,IACC,CAACC,mBACD,QAAQlE,IAAI,CAACiE,aACbL,mCAAmClE,IAClC;gBACDwE,kBAAkB;YACnB;YACA,IAAI,CAACA,iBAAiB;gBACrB7E,IAAIO,IAAI,CAACsB,KAAK,CAACxB,EAAE;gBACjBA;gBACA;YACD;YACA,IAAMyD,QAA4C,EAAE;YACpD,IAAII,IAAI7D;YACR,MAAO6D,IAAIrC,MAAMzB,MAAM,CAAE;gBACxB,IAAMqE,KAAK,oBAAoBpB,IAAI,CAACxB,KAAK,CAACqC,EAAE;gBAC5C,IAAI,CAACO,MAAM,aAAa9D,IAAI,CAACkB,KAAK,CAACqC,EAAE,GAAG;oBACvC;gBACD;gBACA,IAAMY,MAAML,EAAE,CAAC,EAAE;gBACjB,IACC,qBAAqB9D,IAAI,CAACmE,QAC1B,cAAcnE,IAAI,CAACmE,QACnB,mBAAmBnE,IAAI,CAACmE,MACvB;oBACD,OAAO,0CAA0C;gBAClD;gBACAhB,MAAMvD,IAAI,CAAC;oBAAE0B,QAAQwC,EAAE,CAAC,EAAE;oBAAEjD,MAAMsD;gBAAI;gBACtCZ;YACD;YACA,IAAIJ,MAAM1D,MAAM,IAAI,GAAG;gBACtB;;;;;;KAMC,GACD,IAAMwC,aAAakB,MAAMzB,IAAI,CAC5B,SAAC0C;2BACA,KAAKpE,IAAI,CAACoE,EAAEvD,IAAI,KAChB,eAAeb,IAAI,CAACoE,EAAEvD,IAAI,KAC1B,wBAAwBb,IAAI,CAACoE,EAAEvD,IAAI;;gBAErC,IAAIoB,YAAY;oBACf,IAAMX,SAAS6B,KAAK,CAAC,EAAE,CAAC7B,MAAM;oBAC9BjC,IAAIO,IAAI,CAAC,AAAC,GAAS,OAAP0B,QAAO;wBACd,kCAAA,2BAAA;;wBAAL,QAAK,YAAY6B,0BAAZ,SAAA,6BAAA,QAAA,yBAAA,iCAAmB;4BAAnB,IAAMkB,KAAN;4BACJ,0CAA0C;4BAC1C,IAAMC,OAAOD,GAAGxD,IAAI,CAACR,OAAO,CAAC,SAAS;4BACtChB,IAAIO,IAAI,CAAC,AAAC,GAAc0E,OAAZhD,QAAO,OAAU,OAALgD;wBACzB;;wBAJK;wBAAA;;;iCAAA,6BAAA;gCAAA;;;gCAAA;sCAAA;;;;oBAKLjF,IAAIO,IAAI,CAAC,AAAC,GAAS,OAAP0B,QAAO;oBACnBqC,SAAS;oBACTjE,IAAI6D;oBACJ;gBACD;gBACA,IAAMjC,UAAS6B,KAAK,CAAC,EAAE,CAAC7B,MAAM;gBAC9BqC,SAAS;gBACT;;;;;;KAMC,GACD,IAAMY,OAAOpB,MAAM3B,GAAG,CAAC,SAAC4C;2BAAMhE,cAAcgE,EAAEvD,IAAI,CAACZ,IAAI;;gBACvD,0CAA0C;gBAC1C,IAAIuE,UAAUD,KAAK9E,MAAM,GAAG;gBAC5B,MAAO+E,UAAU,KAAKD,IAAI,CAACC,QAAQ,CAACvE,IAAI,OAAO,GAAI;oBAClDuE;gBACD;gBACA,IAAK,IAAIpB,IAAI,GAAGA,IAAImB,KAAK9E,MAAM,EAAE2D,IAAK;oBACrC,IAAIA,MAAMoB,SAAS;wBAClB,IAAMH,MAAKE,IAAI,CAACnB,EAAE;wBAClB,IAAI,CAAC,KAAKpD,IAAI,CAACqE,IAAGpE,IAAI,KAAK;4BAC1BsE,IAAI,CAACnB,EAAE,GAAGjD,eAAekE;wBAC1B;oBACD;gBACD;gBACA,IAAMxC,OAAO0C,KAAK1E,IAAI,CAAC,KAAKQ,OAAO,CAAC,QAAQ,KAAKJ,IAAI;gBACrDZ,IAAIO,IAAI,CAAC,AAAC,GAAS,OAAP0B,SAAO;gBACnBjC,IAAIO,IAAI,CAAC,AAAC,GAAciC,OAAZP,SAAO,OAAU,OAALO;gBACxBxC,IAAIO,IAAI,CAAC,AAAC,GAAS,OAAP0B,SAAO;gBACnB5B,IAAI6D;gBACJ;YACD;QACD;QACAlE,IAAIO,IAAI,CAACsB,KAAK,CAACxB,EAAE;QACjBA;IACD;IACA,OAAO;QAAE6C,SAASlD,IAAIQ,IAAI,CAAC;QAAO8D,QAAAA;IAAO;AAC1C;AAEA,OAAO,SAASc,0BACfC,KAAa,EACbC,OAAuB;IAEvB,IAAIC,UAAUF;IACd,IAAIC,QAAQE,iBAAiB,EAAE;QAC9B,IAAMvF,IAAIoE,uBAAuBkB;QACjCA,UAAUtF,EAAEiD,OAAO;IACpB;IACA,IAAMuC,KAAKxC,kBAAkBsC,SAASD,QAAQ7D,KAAK;IACnD8D,UAAUE,GAAGvC,OAAO;IACpB,IAAIoC,QAAQzB,gBAAgB,EAAE;QAC7B,IAAM9B,IAAI8B,iBAAiB0B,SAASD,QAAQ7D,KAAK;QACjD8D,UAAUxD,EAAEmB,OAAO;IACpB;IACA,OAAO;QAAES,UAAU0B;QAAOK,aAAaH;QAAStB,SAASsB,YAAYF;IAAM;AAC5E"}
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\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 (/^(@|eslint|ts-ignore)/.test(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 (/^(@|eslint|ts-ignore)/.test(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 (/^(@|eslint|ts-ignore)/.test(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\t/eslint|ts-ignore/.test(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","wrapWords","width","words","lines","cur","w","buildJsDoc","indent","rawBody","map","l","some","internalBlank","para","inFence","prefix","avail","structured","raw","trimmed","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":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAASA,MAAM,QAAQ,mBAAmB;AAE1C,OAAO,IAAMC,SAAS,IAAID,OAAO;IAAEE,QAAQC,QAAQC,GAAG,CAACC,QAAQ,KAAK;AAAO,GAAG;AAqB9E;;;;;;;CAOC,GACD,IAAMC,mBAAmB,KAAK,6BAA6B;AAE3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiCC,GACD,IAAMC,cAAc;AAEpB,OAAO,SAASC,UAAUC,CAAS,EAAEC,CAAS;IAC7C,IAAID,MAAMC,GAAG;QACZ,OAAO;IACR;IACA,IAAMC,IAAIF,EAAEG,KAAK,CAAC;IAClB,IAAMC,IAAIH,EAAEE,KAAK,CAAC;IAClB,IAAME,MAAgB,EAAE;IACxB,IAAMC,IAAIC,KAAKC,GAAG,CAACN,EAAEO,MAAM,EAAEL,EAAEK,MAAM;IACrC,IAAK,IAAIC,IAAI,GAAGA,IAAIJ,GAAGI,IAAK;QAC3B,IAAIR,CAAC,CAACQ,EAAE,KAAKN,CAAC,CAACM,EAAE,EAAE;YAClB;QACD;QACA,IAAIR,CAAC,CAACQ,EAAE,KAAKC,WAAW;YACvBN,IAAIO,IAAI,CAAC,AAAC,KAAS,OAALV,CAAC,CAACQ,EAAE;QACnB;QACA,IAAIN,CAAC,CAACM,EAAE,KAAKC,WAAW;YACvBN,IAAIO,IAAI,CAAC,AAAC,KAAS,OAALR,CAAC,CAACM,EAAE;QACnB;IACD;IACA,OAAOL,IAAIQ,IAAI,CAAC;AACjB;AAEA,SAASC,aAAaC,IAAY;IACjC,OAAO,qBAAqBC,IAAI,CAACD,KAAKE,IAAI;AAC3C;AAEA,SAASC,yBAAyBH,IAAY;IAC7C,OAAO,oBAAoBC,IAAI,CAACD,SAAS,CAACD,aAAaC;AACxD;AAEA,SAASI,eAAeJ,IAAY;IACnC,OAAOG,yBAAyBH,QAAQA,OAAO,MAAMA;AACtD;AAEA,SAASK,cAAcL,IAAY;IAClC,OAAOA,KAAKM,OAAO,CAAC,WAAW;AAChC;AAEA;;CAEC,GACD,SAASC,mBAAmBC,IAAY;IACvC,IAAI,CAAC,SAASP,IAAI,CAACO,OAAO;QACzB,OAAO;YAACA;SAAK;IACd;IACA,IAAMC,WAAqB,EAAE;IAC7B,IAAId,IAAI;IACR,MAAOA,IAAIa,KAAKd,MAAM,CAAE;QACvB,IAAMgB,MAAMF,KAAKG,OAAO,CAAC,UAAUhB;QACnC,IAAIe,QAAQ,CAAC,GAAG;YACf,IAAME,OAAOJ,KAAKK,KAAK,CAAClB,GAAGO,IAAI;YAC/B,IAAIU,MAAM;gBACTH,SAASZ,IAAI,CAACe;YACf;YACA;QACD;QACA;;;;GAIC,GACD,IAAME,WACLJ,QAAQ,KACR,SAAST,IAAI,CAACO,KAAKK,KAAK,CAACrB,KAAKC,GAAG,CAAC,GAAGiB,MAAM,IAAIA,MAAM,OACrDF,IAAI,CAACE,MAAM,EAAE,KAAK;QACnB,IAAI,CAACI,UAAU;YACdnB,IAAIe,MAAM,GAAG,uBAAuB;YACpC;QACD;QACA,IAAMK,SAASP,KAAKK,KAAK,CAAClB,GAAGe,KAAKR,IAAI;QACtC,IAAIa,QAAQ;YACXN,SAASZ,IAAI,CAACkB;QACf;QACA,IAAIC,MAAMN;QACV,MAAOM,MAAMR,KAAKd,MAAM,IAAI,CAAC,QAAQO,IAAI,CAACO,IAAI,CAACQ,IAAI,EAAG;YACrDA;QACD;QACA,IAAIA,MAAMR,KAAKd,MAAM,IAAI,QAAQO,IAAI,CAACO,IAAI,CAACQ,IAAI,GAAG;YACjDA;QACD;QACA,IAAIC,OAAOT,KAAKK,KAAK,CAACH,KAAKM,KAAKd,IAAI;QACpC,IAAI,CAAC,SAASD,IAAI,CAACgB,OAAO;YACzBA,QAAQ;QACT;QACAR,SAASZ,IAAI,CAACoB;QACdtB,IAAIqB;QACJ,IAAIR,IAAI,CAACb,EAAE,KAAK,KAAK;YACpBA;QACD;IACD;IACA,OAAOc,SAASS,MAAM,CAACC;AACxB;AAEA,SAASC,WAAWpB,IAAY;IAC/B,OAAO,qBAAqBC,IAAI,CAACD,KAAKE,IAAI;AAC3C;AAEA,SAASmB,UAAUrB,IAAY;IAC9B,OAAO,KAAKC,IAAI,CAACD,KAAKE,IAAI;AAC3B;AAEA,SAASoB,cAActB,IAAY;IAClC,IAAMuB,IAAIvB,KAAKE,IAAI;IACnB,IAAI,CAAC,KAAKD,IAAI,CAACsB,MAAMF,UAAUE,IAAI;QAClC,OAAO;IACR;IACA;;;;;;EAMC,GACD,OAAO,kDAAkDtB,IAAI,CAACsB;AAC/D;AAEA,SAASC,YAAYxB,IAAY;IAChC,OAAO,OAAOC,IAAI,CAACD,KAAKE,IAAI;AAC7B;AAEA,SAASuB,uBAAuBzB,IAAY;IAC3C,OAAO,YAAYC,IAAI,CAACD;AACzB;AAEA,SAAS0B,UAAUlB,IAAY,EAAEmB,KAAa;IAC7C,IAAMC,QAAQpB,KAAKpB,KAAK,CAAC,OAAO8B,MAAM,CAACC;IACvC,IAAMU,QAAkB,EAAE;IAC1B,IAAIC,MAAM;QACL,kCAAA,2BAAA;;QAAL,QAAK,YAAWF,0BAAX,SAAA,6BAAA,QAAA,yBAAA,iCAAkB;YAAlB,IAAMG,IAAN;YACJ,IAAI,CAACD,IAAIpC,MAAM,EAAE;gBAChBoC,MAAMC;gBACN;YACD;YACA,IAAID,IAAIpC,MAAM,GAAG,IAAIqC,EAAErC,MAAM,IAAIiC,OAAO;gBACvCG,OAAO,MAAMC;YACd,OAAO;gBACNF,MAAMhC,IAAI,CAACiC;gBACXA,MAAMC;YACP;QACD;;QAXK;QAAA;;;iBAAA,6BAAA;gBAAA;;;gBAAA;sBAAA;;;;IAYL,IAAID,KAAK;QACRD,MAAMhC,IAAI,CAACiC;IACZ;IACA,OAAOD,MAAMnC,MAAM,GAAGmC,QAAQ;QAAC;KAAG;AACnC;AAEA,SAASG,WAAWC,MAAc,EAAEC,OAAe,EAAEP,KAAa;IACjE,IAAIE,QAAQK,QAAQ9C,KAAK,CAAC,MAAM+C,GAAG,CAAC,SAACC;eAAMA,EAAE9B,OAAO,CAAC,aAAa;;IAClE,+EAA+E;IAC/E,2BAA2B;IAC3B,MACCuB,MAAMnC,MAAM,GAAG,KACfmC,KAAK,CAAC,EAAE,CAAC3B,IAAI,OAAO,MACpB2B,MAAMQ,IAAI,CAAC,SAACD;eAAMA,EAAElC,IAAI,OAAO;OAC9B;QACD2B,QAAQA,MAAMhB,KAAK,CAAC;IACrB;IACA;;;;;EAKC,GACD,IAAIgB,MAAMnC,MAAM,GAAG,KAAKmC,KAAK,CAACA,MAAMnC,MAAM,GAAG,EAAE,CAACQ,IAAI,OAAO,IAAI;QAC9D,IAAMoC,gBAAgBT,MAAMhB,KAAK,CAAC,GAAG,CAAC,GAAGwB,IAAI,CAAC,SAACD;mBAAMA,EAAElC,IAAI,OAAO;;QAClE,IAAI,CAACoC,eAAe;YACnBT,QAAQA,MAAMhB,KAAK,CAAC,GAAG,CAAC;QACzB;IACD;IACA,IAAMvB,MAAgB,EAAE;IACxB,IAAIiD,OAAiB,EAAE;IACvB,IAAIC,UAAU;IACd,IAAMC,SAASR,SAAS;IACxB,IAAMS,QAAQlD,KAAKC,GAAG,CAAC,IAAIkC,QAAQc,OAAO/C,MAAM;IAEhD;;;;EAIC,GACD,IAAMiD,aAAad,MAAMQ,IAAI,CAC5B,SAACD;eACA,KAAKnC,IAAI,CAACmC,MACV,gBAAgBnC,IAAI,CAACmC,MACrB,wBAAwBnC,IAAI,CAACmC;;IAE/B,IAAIO,YAAY;YACV,kCAAA,2BAAA;;YAAL,QAAK,YAAad,0BAAb,SAAA,6BAAA,QAAA,yBAAA,iCAAoB;gBAApB,IAAMe,MAAN;gBACJ,IAAMC,UAAUD,IAAIE,OAAO;gBAC3B,IAAID,YAAY,IAAI;oBACnB,iDAAiD;oBACjD,IACCvD,IAAII,MAAM,KAAK,KACf,iBAAiBO,IAAI,CAACX,GAAG,CAACA,IAAII,MAAM,GAAG,EAAE,MAAM,OAC9C;wBACDJ,IAAIO,IAAI,CAAC4C,OAAOK,OAAO;oBACxB;oBACA;gBACD;gBACAxD,IAAIO,IAAI,CAAC4C,SAASpC,cAAcwC;YACjC;;YAbK;YAAA;;;qBAAA,6BAAA;oBAAA;;;oBAAA;0BAAA;;;;QAcL,4CAA4C;QAC5C,OAAO,AAAC,GAAgBvD,OAAd2C,QAAO,SAA0BA,OAAnB3C,IAAIQ,IAAI,CAAC,OAAM,MAAW,OAAPmC,QAAO;IACnD;IAEA,SAASc;QACR,IAAI,CAACR,KAAK7C,MAAM,EAAE;YACjB;QACD;QACA,IAAIc,OAAO+B,KAAKzC,IAAI,CAAC,KAAKQ,OAAO,CAAC,QAAQ,KAAKJ,IAAI;QACnDM,OAAOH,cAAcG;QACrBA,OAAOJ,eAAeI;QACtB,IAAMwC,SAASzC,mBAAmBC;YAC7B,kCAAA,2BAAA;;YAAL,QAAK,YAAewC,2BAAf,SAAA,6BAAA,QAAA,yBAAA,iCAAuB;gBAAvB,IAAMC,QAAN;oBACC,mCAAA,4BAAA;;oBAAL,QAAK,aAAWvB,UAAUuB,OAAOP,2BAA5B,UAAA,8BAAA,SAAA,0BAAA,kCAAoC;wBAApC,IAAMN,IAAN;wBACJ9C,IAAIO,IAAI,CAAC4C,SAASL;oBACnB;;oBAFK;oBAAA;;;6BAAA,8BAAA;4BAAA;;;4BAAA;kCAAA;;;;YAGN;;YAJK;YAAA;;;qBAAA,6BAAA;oBAAA;;;oBAAA;0BAAA;;;;QAKLG,OAAO,EAAE;IACV;IAEA,IAAIW,YAAY,CAAC;QACZ,mCAAA,4BAAA;;QAAL,QAAK,aAAarB,0BAAb,UAAA,8BAAA,SAAA,0BAAA,kCAAoB;YAApB,IAAMe,OAAN;YACJM;YACA,IAAML,WAAUD,KAAIE,OAAO;YAC3B,IAAItB,YAAYqB,WAAU;gBACzBE;gBACAP,UAAU,CAACA;gBACXlD,IAAIO,IAAI,CAAC4C,SAASI;gBAClB;YACD;YACA,IAAIL,SAAS;gBACZ;;;;IAIC,GACD,IAAIK,aAAY,IAAI;oBACnBvD,IAAIO,IAAI,CAAC4C,OAAOK,OAAO;gBACxB,OAAO;oBACNxD,IAAIO,IAAI,CAAC4C,SAASI;gBACnB;gBACA;YACD;YACA,IACCA,aAAY,MACZzB,WAAWyB,aACXxB,UAAUwB,aACVvB,cAAcuB,aACdpB,uBAAuBmB,SACvB,UAAU3C,IAAI,CAACI,cAAcwC,YAC5B;gBACDE;gBACA,IAAIF,aAAY,IAAI;oBACnB,IACCvD,IAAII,MAAM,KAAK,KACf,iBAAiBO,IAAI,CAACX,GAAG,CAACA,IAAII,MAAM,GAAG,EAAE,MAAM,OAC9C;wBACDJ,IAAIO,IAAI,CAAC4C,OAAOK,OAAO;oBACxB;gBACD,OAAO;oBACN,IAAIK,WAAW9C,cAAcwC;oBAC7B,IAAI,UAAU5C,IAAI,CAACkD,aAAa,CAAC,SAASlD,IAAI,CAACkD,WAAW;wBACzD;;;;;MAKC,GACD,IAAIC,YAAY,MAAM,kDAAkD;wBACxE,IAAMC,OAAOH,YAAY;wBACzB,MAAOG,OAAOxB,MAAMnC,MAAM,CAAE;4BAC3B,IAAM4D,UAAUzB,KAAK,CAACwB,KAAK;4BAC3B,IAAME,UAAUD,QAAQhD,OAAO,CAAC,aAAa,IAAIwC,OAAO;4BACxD,IAAMU,cAAcD,QAAQrD,IAAI;4BAChC,IAAIsD,gBAAgB,IAAI;gCACvB,iCAAiC;gCACjCJ,YAAY;gCACZ;4BACD;4BACA,IACC,WAAWnD,IAAI,CAACuD,gBAChBnC,UAAUmC,gBACVpC,WAAWoC,gBACXlC,cAAckC,gBACdhC,YAAYgC,gBACZ/B,uBAAuB6B,UACtB;gCACDF,YAAY,MAAM,qBAAqB;gCACvC;4BACD;4BACA,8CAA8C;4BAC9CA,YAAY;4BACZ;wBACD;wBACA;;;;;MAKC,GACD,IAAMK,kBAAkBnE,IAAI+C,IAAI,CAC/B,SAACD;mCAAM,UAAUnC,IAAI,CAACmC,MAAM,CAAC,YAAYnC,IAAI,CAACmC;;wBAE/C,IAAIgB,aAAa,CAACK,iBAAiB;4BAClCN,YAAY;wBACb;oBACD;oBACA7D,IAAIO,IAAI,CAAC4C,SAASU;gBACnB;gBACA;YACD;YACAZ,KAAK1C,IAAI,CAACgD;QACX;;QA3FK;QAAA;;;iBAAA,8BAAA;gBAAA;;;gBAAA;sBAAA;;;;IA4FLE;IACA;;;;EAIC,GACD,OAAO,AAAC,GAAgBzD,OAAd2C,QAAO,SAA0BA,OAAnB3C,IAAIQ,IAAI,CAAC,OAAM,MAAW,OAAPmC,QAAO;AACnD;AAEA,SAASyB,kBACRC,OAAe,EACfhC,KAAa;IAEb5C,YAAY6E,SAAS,GAAG;IACxB,IAAMC,SAAuB,EAAE;IAC/B,IAAItE,IAA4BR,YAAY+E,IAAI,CAACH;IACjD,MAAOpE,EAAG;QACT,IAAM0C,SAAS1C,CAAC,CAAC,EAAE,IAAI;QACvB,IAAMwE,OAAOxE,CAAC,CAAC,EAAE,IAAI;QACrB,qEAAqE;QACrE,IAAIwE,KAAKrE,MAAM,IAAI,UAAWuC,OAAOvC,MAAM,IAAIZ,kBAAkB;YAChE+E,OAAOhE,IAAI,CAAC;gBACXoC,QAAAA;gBACA8B,MAAAA;gBACAC,OAAOzE,EAAE0E,KAAK;gBACdjD,KAAKzB,EAAE0E,KAAK,GAAG1E,CAAC,CAAC,EAAE,CAACG,MAAM;YAC3B;QACD;QACAH,IAAIR,YAAY+E,IAAI,CAACH;IACtB;IACA,IAAI,CAACE,OAAOnE,MAAM,EAAE;QACnB,OAAO;YAAEiE,SAAAA;YAASE,QAAQ;QAAE;IAC7B;IACA,IAAIK,QAAQ;IACZ,IAAI5E,MAAMqE;QACL,kCAAA,2BAAA;;QAAL,QAAK,YAAWE,2BAAX,SAAA,6BAAA,QAAA,yBAAA,iCAAmB;YAAnB,IAAM3E,IAAN;YACJ,IAAMiF,WAAW7E,IAAIuB,KAAK,CAAC3B,EAAE8E,KAAK,GAAGE,OAAOhF,EAAE8B,GAAG,GAAGkD;YACpD,IAAME,QAAQpC,WAAW9C,EAAE+C,MAAM,EAAE/C,EAAE6E,IAAI,EAAEpC;YAC3C,IAAIwC,aAAaC,OAAO;gBACvB9E,MAAMA,IAAIuB,KAAK,CAAC,GAAG3B,EAAE8E,KAAK,GAAGE,SAASE,QAAQ9E,IAAIuB,KAAK,CAAC3B,EAAE8B,GAAG,GAAGkD;gBAChEA,SAASE,MAAM1E,MAAM,GAAGyE,SAASzE,MAAM;YACxC;QACD;;QAPK;QAAA;;;iBAAA,6BAAA;gBAAA;;;gBAAA;sBAAA;;;;IAQL,OAAO;QAAEiE,SAASrE;QAAKuE,QAAQA,OAAOnE,MAAM;IAAC;AAC9C;AAEA,SAAS2E,iBACRV,OAAe,EACfhC,KAAa;;;gBA0EXrC;YAZA,IAAyBgF,WAAAA,KAAK,CAACC,EAAE,EAAzBtC,SAAiBqC,SAAjBrC,QAAQ8B,OAASO,SAATP;YAChB,IAAMtB,SAASR,SAAS;YACxB,IAAMS,QAAQlD,KAAKC,GAAG,CAAC,IAAIkC,QAAQc,OAAO/C,MAAM;YAChD,IAAIc,OAAOuD,KAAKzD,OAAO,CAAC,QAAQ,KAAKJ,IAAI;YACzCM,OAAOH,cAAcG;YACrB,IAAI+D,MAAMD,MAAM5E,MAAM,GAAG,KAAK,CAAC,KAAKO,IAAI,CAACO,KAAKN,IAAI,KAAK;gBACtDM,OAAOJ,eAAeI;YACvB;YACA,IAAMgE,UAAU9C,UAAUlB,MAAMkC,OAAOP,GAAG,CAAC,SAACJ;uBAAMU,SAASV;;YAC3D,IAAIyC,QAAQ1E,IAAI,CAAC,UAAUwE,KAAK,CAACC,EAAE,CAAC3B,GAAG,EAAE;gBACxC6B,UAAU;YACX;YACAnF,CAAAA,OAAAA,KAAIO,IAAI,OAARP,MAAS,qBAAGkF;QACb;QApEA,IAAMxE,OAAO6B,KAAK,CAAClC,EAAE;QACrB,IAAMJ,IAAI,sBAAsBuE,IAAI,CAAC9D;QACrC,IAAI,CAACT,KAAK,UAAUU,IAAI,CAACD,OAAO;YAC/BV,IAAIO,IAAI,CAACG;YACTL;YACA,OAAA;QACD;QACA;;;;GAIC,GACD,IAAM2E,QAAyD,EAAE;QACjE,IAAII,IAAI/E;QACR,MAAO+E,IAAI7C,MAAMnC,MAAM,CAAE;YACxB,IAAMiF,KAAK,oBAAoBb,IAAI,CAACjC,KAAK,CAAC6C,EAAE;YAC5C,IAAI,CAACC,MAAM,UAAU1E,IAAI,CAAC4B,KAAK,CAAC6C,EAAE,GAAG;gBACpC;YACD;YACA,IAAMX,OAAOY,EAAE,CAAC,EAAE;YAClB,IAAI,wBAAwB1E,IAAI,CAAC8D,SAAS,cAAc9D,IAAI,CAAC8D,OAAO;gBACnE,OAAO,mEAAmE;YAC3E;YACAO,MAAMzE,IAAI,CAAC;gBAAE+C,KAAKf,KAAK,CAAC6C,EAAE;gBAAEzC,QAAQ0C,EAAE,CAAC,EAAE;gBAAEZ,MAAAA;YAAK;YAChDW;QACD;QACA,IAAIJ,MAAM5E,MAAM,IAAI,GAAG;gBAkBtBJ;YAjBA,sDAAsD;YACtD,IAAM2C,SAAS1C,CAAC,CAAC,EAAE;YACnB,IAAMwE,QAAOxE,CAAC,CAAC,EAAE;YACjB,IAAI,wBAAwBU,IAAI,CAAC8D,UAAS,cAAc9D,IAAI,CAAC8D,QAAO;gBACnEzE,IAAIO,IAAI,CAACG;gBACTL;gBACA,OAAA;YACD;YACA,IAAM8C,SAASR,SAAS;YACxB,IAAMS,QAAQlD,KAAKC,GAAG,CAAC,IAAIkC,QAAQc,OAAO/C,MAAM;YAChD,IAAIc,OAAOuD,MAAKzD,OAAO,CAAC,QAAQ,KAAKJ,IAAI;YACzCM,OAAOH,cAAcG;YACrBA,OAAOJ,eAAeI;YACtB,IAAMgE,UAAU9C,UAAUlB,MAAMkC,OAAOP,GAAG,CAAC,SAACJ;uBAAMU,SAASV;;YAC3D,IAAIyC,QAAQ1E,IAAI,CAAC,UAAUE,MAAM;gBAChCyE,UAAU;YACX;YACAnF,CAAAA,OAAAA,KAAIO,IAAI,OAARP,MAAS,qBAAGkF;YACZ7E;YACA,OAAA;QACD;QACA;;;;;GAKC,GACD,IAAK,IAAI4E,IAAI,GAAGA,IAAID,MAAM5E,MAAM,EAAE6E;QAelC5E,IAAI+E;IACL;IA3EA,IAAM7C,QAAQ8B,QAAQvE,KAAK,CAAC;IAC5B,IAAIqF,UAAU;IACd,IAAMnF,MAAgB,EAAE;IACxB,IAAIK,IAAI;IACR,MAAOA,IAAIkC,MAAMnC,MAAM;IAwEvB,OAAO;QAAEiE,SAASrE,IAAIQ,IAAI,CAAC;QAAO8E,SAASH;IAAQ;AACpD;AAEA,SAASI,uBAAuBlB,OAAe;IAI9C,IAAM9B,QAAQ8B,QAAQvE,KAAK,CAAC;IAC5B,IAAME,MAAgB,EAAE;IACxB,IAAIK,IAAI;IACR,IAAImF,SAAS;IAEb,SAASC,mCAAmCf,KAAa;QACxD;;;;GAIC,GACD,IAAMgB,YAAsB,EAAE;QAC9B,IAAK,IAAIT,IAAIP,OAAOO,IAAI1C,MAAMnC,MAAM,EAAE6E,IAAK;YAC1C,IAAMU,KAAK,sBAAsBnB,IAAI,CAACjC,KAAK,CAAC0C,EAAE;YAC9C,IAAI,CAACU,MAAM,UAAUhF,IAAI,CAAC4B,KAAK,CAAC0C,EAAE,GAAG;gBACpC;YACD;YACA,IAAMR,OAAOkB,EAAE,CAAC,EAAE;YAClB,IAAI,wBAAwBhF,IAAI,CAAC8D,SAAS,cAAc9D,IAAI,CAAC8D,OAAO;gBACnE;YACD;YACAiB,UAAUnF,IAAI,CAACkE,KAAK7D,IAAI;QACzB;QACA,IAAI8E,UAAUtF,MAAM,GAAG,GAAG;YACzB,OAAO,OAAO,qEAAqE;QACpF;QACA,IAAI,CAAC,SAASO,IAAI,CAAC+E,SAAS,CAAC,EAAE,GAAG;YACjC,OAAO,OAAO,kCAAkC;QACjD;QACA;;;GAGC,GACD,OAAOA,UAAU3C,IAAI,CAAC,SAAC6C;mBAAM,KAAKjF,IAAI,CAACiF;;IACxC;IACA,MAAOvF,IAAIkC,MAAMnC,MAAM,CAAE;QACxB,IAAI,WAAWO,IAAI,CAAC4B,KAAK,CAAClC,EAAE,KAAK,CAAC,aAAaM,IAAI,CAAC4B,KAAK,CAAClC,EAAE,GAAG;YAC9D,IAAMwF,OAAOxF,IAAI,IAAIkC,KAAK,CAAClC,IAAI,EAAE,GAAG;YACpC,IAAMyF,WAAWD,KAAKjF,IAAI;YAC1B,IAAImF,kBAAkBD,aAAa,MAAM,QAAQnF,IAAI,CAACmF;YACtD;;;;IAIC,GACD,IACC,CAACC,mBACD,QAAQpF,IAAI,CAACmF,aACbL,mCAAmCpF,IAClC;gBACD0F,kBAAkB;YACnB;YACA,IAAI,CAACA,iBAAiB;gBACrB/F,IAAIO,IAAI,CAACgC,KAAK,CAAClC,EAAE;gBACjBA;gBACA;YACD;YACA,IAAM2E,QAA4C,EAAE;YACpD,IAAII,IAAI/E;YACR,MAAO+E,IAAI7C,MAAMnC,MAAM,CAAE;gBACxB,IAAMuF,KAAK,oBAAoBnB,IAAI,CAACjC,KAAK,CAAC6C,EAAE;gBAC5C,IAAI,CAACO,MAAM,aAAahF,IAAI,CAAC4B,KAAK,CAAC6C,EAAE,GAAG;oBACvC;gBACD;gBACA,IAAMY,MAAML,EAAE,CAAC,EAAE;gBACjB,IACC,qBAAqBhF,IAAI,CAACqF,QAC1B,cAAcrF,IAAI,CAACqF,QACnB,mBAAmBrF,IAAI,CAACqF,MACvB;oBACD,OAAO,0CAA0C;gBAClD;gBACAhB,MAAMzE,IAAI,CAAC;oBAAEoC,QAAQgD,EAAE,CAAC,EAAE;oBAAEzE,MAAM8E;gBAAI;gBACtCZ;YACD;YACA,IAAIJ,MAAM5E,MAAM,IAAI,GAAG;gBACtB;;;;;;KAMC,GACD,IAAMiD,aAAa2B,MAAMjC,IAAI,CAC5B,SAACkD;2BACA,KAAKtF,IAAI,CAACsF,EAAE/E,IAAI,KAChB,eAAeP,IAAI,CAACsF,EAAE/E,IAAI,KAC1B,wBAAwBP,IAAI,CAACsF,EAAE/E,IAAI;;gBAErC,IAAImC,YAAY;oBACf,IAAMV,SAASqC,KAAK,CAAC,EAAE,CAACrC,MAAM;oBAC9B3C,IAAIO,IAAI,CAAC,AAAC,GAAS,OAAPoC,QAAO;wBACd,kCAAA,2BAAA;;wBAAL,QAAK,YAAYqC,0BAAZ,SAAA,6BAAA,QAAA,yBAAA,iCAAmB;4BAAnB,IAAMkB,KAAN;4BACJ,0CAA0C;4BAC1C,IAAMC,OAAOD,GAAGhF,IAAI,CAACF,OAAO,CAAC,SAAS;4BACtChB,IAAIO,IAAI,CAAC,AAAC,GAAc4F,OAAZxD,QAAO,OAAU,OAALwD;wBACzB;;wBAJK;wBAAA;;;iCAAA,6BAAA;gCAAA;;;gCAAA;sCAAA;;;;oBAKLnG,IAAIO,IAAI,CAAC,AAAC,GAAS,OAAPoC,QAAO;oBACnB6C,SAAS;oBACTnF,IAAI+E;oBACJ;gBACD;gBACA,IAAMzC,UAASqC,KAAK,CAAC,EAAE,CAACrC,MAAM;gBAC9B6C,SAAS;gBACT;;;;;;KAMC,GACD,IAAMY,OAAOpB,MAAMnC,GAAG,CAAC,SAACoD;2BAAMlF,cAAckF,EAAE/E,IAAI,CAACN,IAAI;;gBACvD;;;;;;KAMC,GACD,IAAIyF,UAAUD,KAAKhG,MAAM,GAAG;gBAC5B,MAAOiG,UAAU,KAAKD,IAAI,CAACC,QAAQ,CAACzF,IAAI,OAAO,GAAI;oBAClDyF;gBACD;gBACA,IAAK,IAAIpB,IAAI,GAAGA,IAAImB,KAAKhG,MAAM,EAAE6E,IAAK;oBACrC,IAAIA,MAAMoB,SAAS;wBAClB,IAAMH,MAAKE,IAAI,CAACnB,EAAE;wBAClB,IAAI,CAAC,KAAKtE,IAAI,CAACuF,IAAGtF,IAAI,KAAK;4BAC1BwF,IAAI,CAACnB,EAAE,GAAGnE,eAAeoF;wBAC1B;oBACD;gBACD;gBACA,IAAMjD,OAAOmD,KAAK5F,IAAI,CAAC,KAAKQ,OAAO,CAAC,QAAQ,KAAKJ,IAAI;gBACrDZ,IAAIO,IAAI,CAAC,AAAC,GAAS,OAAPoC,SAAO;oBACd,mCAAA,4BAAA;;oBAAL,QAAK,aAAa1B,mBAAmBgC,0BAAhC,UAAA,8BAAA,SAAA,0BAAA,kCAAuC;wBAAvC,IAAMqD,MAAN;wBACJtG,IAAIO,IAAI,CAAC,AAAC,GAAc+F,OAAZ3D,SAAO,OAAS,OAAJ2D;oBACzB;;oBAFK;oBAAA;;;6BAAA,8BAAA;4BAAA;;;4BAAA;kCAAA;;;;gBAGLtG,IAAIO,IAAI,CAAC,AAAC,GAAS,OAAPoC,SAAO;gBACnBtC,IAAI+E;gBACJ;YACD;QACD;QACApF,IAAIO,IAAI,CAACgC,KAAK,CAAClC,EAAE;QACjBA;IACD;IACA,OAAO;QAAEgE,SAASrE,IAAIQ,IAAI,CAAC;QAAOgF,QAAAA;IAAO;AAC1C;AAEA,OAAO,SAASe,0BACfC,KAAa,EACbC,OAAuB;IAEvB,IAAIC,UAAUF;IACd,IAAIC,QAAQE,iBAAiB,EAAE;QAC9B,IAAM1G,IAAIsF,uBAAuBmB;QACjCA,UAAUzG,EAAEoE,OAAO;IACpB;IACA,IAAMuC,KAAKxC,kBAAkBsC,SAASD,QAAQpE,KAAK;IACnDqE,UAAUE,GAAGvC,OAAO;IACpB,IAAIoC,QAAQ1B,gBAAgB,EAAE;QAC7B,IAAMtC,IAAIsC,iBAAiB2B,SAASD,QAAQpE,KAAK;QACjDqE,UAAUjE,EAAE4B,OAAO;IACpB;IACA,OAAO;QAAEQ,UAAU2B;QAAOK,aAAaH;QAASvB,SAASuB,YAAYF;IAAM;AAC5E"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node-cli/comments",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
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",
@@ -40,5 +40,5 @@
40
40
  "@vitest/coverage-v8": "3.2.4",
41
41
  "vitest": "3.2.4"
42
42
  },
43
- "gitHead": "10fc24a99720b72c177de243bc738b01b30e4815"
43
+ "gitHead": "786eceb6816c7927c27239a5cf585ccae16888a1"
44
44
  }