@d3lm/lint-preset 1.6.1 → 1.6.3

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.
@@ -2,11 +2,12 @@ type StyleIssueType = 'semicolon' | 'em-dash' | 'dash' | 'label-colon' | 'emphas
2
2
 
3
3
  interface WrapOptions {
4
4
  /**
5
- * Sets whether a line may not end with the first word of a sentence, clause, or parenthetical,
6
- * like `This`, `the` after a comma, or `(the`. Such a word moves to the next line instead.
7
- * It also sets whether a line avoids ending with the first two words of a sentence, and whether
8
- * the first of two lines ends with a sentence instead of the start of the next one, as long as
9
- * the second line is then no longer than the first.
5
+ * Sets whether a line may not end with the first word of a sentence or parenthetical, like
6
+ * `This` or `(the`, or with the first word after a semicolon or colon. Such a word moves to
7
+ * the next line instead. The word after a comma may end a line. It also sets whether a line
8
+ * avoids ending with the first two words of a sentence, and whether the first of two lines
9
+ * ends with a sentence instead of the start of the next one, as long as the second line is
10
+ * then no longer than the first.
10
11
  */
11
12
  readonly avoidSentenceOrphans: boolean;
12
13
  /**
@@ -19,7 +20,7 @@ interface WrapOptions {
19
20
  */
20
21
  readonly parentheticalOverflow?: number;
21
22
  }
22
- type LineIssueType = 'overflow' | 'underfill' | 'orphan' | 'widow' | 'unbalanced' | 'split-parenthetical';
23
+ type LineIssueType = 'overflow' | 'underfill' | 'orphan' | 'widow' | 'unbalanced' | 'wide' | 'split-parenthetical';
23
24
  /**
24
25
  * Splits text into words. JSDoc writes types and `{@link ...}` tags as `{...}` groups, so they stay
25
26
  * intact like code spans.
@@ -54,9 +55,9 @@ interface AnalyzeOptions extends WrapOptions {
54
55
  */
55
56
  readonly maxWidth?: number;
56
57
  /**
57
- * Sets the maximum length of the line that holds a comment whose whole text is one
58
- * prose paragraph. Such a comment stays on one line up to this length plus `tolerance`,
59
- * even past `width`, but never past `maxWidth`. It defaults to `width`.
58
+ * Sets the maximum length of the line that holds a comment whose whole text is one prose
59
+ * paragraph. Such a comment stays on one line up to this length plus `tolerance`, even past
60
+ * `width`, but never past `maxWidth`. It defaults to `width`.
60
61
  */
61
62
  readonly singleLineWidth?: number;
62
63
  readonly tabWidth: number;
@@ -228,26 +229,28 @@ interface CommentsConfig {
228
229
  * Sets the maximum length of the line that holds a comment whose whole text is one prose
229
230
  * paragraph. Such a comment stays on one line up to this length plus `tolerance`, even past
230
231
  * `width`, and is wrapped to `width` beyond it. Defaults to 120, and the line never exceeds
231
- * `maxWidth`.
232
+ * the `maxWidth` limit.
232
233
  */
233
234
  readonly singleLineWidth?: number;
234
235
  /**
235
236
  * Sets how many columns prose lines may go past `width` when that saves a line in a paragraph
236
- * of three or more lines. A paragraph that already has the layout for a wider `width`, up to
237
- * `width` plus this many columns, also passes as it is. So does a paragraph with as many lines
238
- * as the rewrap whose lines are each at most this many columns shorter or longer than in the
239
- * rewrap. It never goes past `maxWidth`. When `maxWidth` is omitted, it also sets a legacy hard
240
- * limit of `width + tolerance`.
237
+ * of three or more lines. A paragraph that already has the layout for a wider `width`, up
238
+ * to `width` plus this many columns, also passes as it is. So does a paragraph with as many
239
+ * lines as the rewrap whose lines, the last aside, are at most this many columns shorter
240
+ * than the shortest of them in the rewrap, and end at most this many columns past `width`.
241
+ * It never goes past `maxWidth`. When `maxWidth` is omitted, it also sets a legacy hard limit
242
+ * of `width + tolerance` columns.
241
243
  */
242
244
  readonly tolerance?: number;
243
245
  /**
244
246
  * Keep the first word of a new sentence or parenthetical off the end of a line, e.g.
245
- * `...the module. This` or `...reflows (the` followed by the rest on the next line.
246
- * A paragraph of two lines also ends its first line with a sentence when the rest fits
247
- * on the second line and is no longer than the first, instead of with the start of
248
- * the next sentence, like `...the module. This one`. Other lines avoid ending with the
249
- * first two words of a sentence, like `...opens. It allocates`, unless that makes them
250
- * much less even. Defaults to `true`.
247
+ * `...the module. This` or `...reflows (the` followed by the rest on the next line. The same
248
+ * goes for the first word after a semicolon or colon, but not after a comma, so a line may
249
+ * end with `...the paths, and`. A paragraph of two lines also ends its first line with a
250
+ * sentence when the rest fits on the second line and is no longer than the first, instead
251
+ * of with the start of the next sentence, like `...the module. This one`. Other lines avoid
252
+ * ending with the first two words of a sentence, like `...opens. It allocates`, unless that
253
+ * makes them much less even. Defaults to `true`.
251
254
  */
252
255
  readonly avoidSentenceOrphans?: boolean;
253
256
  /**
@@ -2,11 +2,12 @@ type StyleIssueType = 'semicolon' | 'em-dash' | 'dash' | 'label-colon' | 'emphas
2
2
 
3
3
  interface WrapOptions {
4
4
  /**
5
- * Sets whether a line may not end with the first word of a sentence, clause, or parenthetical,
6
- * like `This`, `the` after a comma, or `(the`. Such a word moves to the next line instead.
7
- * It also sets whether a line avoids ending with the first two words of a sentence, and whether
8
- * the first of two lines ends with a sentence instead of the start of the next one, as long as
9
- * the second line is then no longer than the first.
5
+ * Sets whether a line may not end with the first word of a sentence or parenthetical, like
6
+ * `This` or `(the`, or with the first word after a semicolon or colon. Such a word moves to
7
+ * the next line instead. The word after a comma may end a line. It also sets whether a line
8
+ * avoids ending with the first two words of a sentence, and whether the first of two lines
9
+ * ends with a sentence instead of the start of the next one, as long as the second line is
10
+ * then no longer than the first.
10
11
  */
11
12
  readonly avoidSentenceOrphans: boolean;
12
13
  /**
@@ -19,7 +20,7 @@ interface WrapOptions {
19
20
  */
20
21
  readonly parentheticalOverflow?: number;
21
22
  }
22
- type LineIssueType = 'overflow' | 'underfill' | 'orphan' | 'widow' | 'unbalanced' | 'split-parenthetical';
23
+ type LineIssueType = 'overflow' | 'underfill' | 'orphan' | 'widow' | 'unbalanced' | 'wide' | 'split-parenthetical';
23
24
  /**
24
25
  * Splits text into words. JSDoc writes types and `{@link ...}` tags as `{...}` groups, so they stay
25
26
  * intact like code spans.
@@ -54,9 +55,9 @@ interface AnalyzeOptions extends WrapOptions {
54
55
  */
55
56
  readonly maxWidth?: number;
56
57
  /**
57
- * Sets the maximum length of the line that holds a comment whose whole text is one
58
- * prose paragraph. Such a comment stays on one line up to this length plus `tolerance`,
59
- * even past `width`, but never past `maxWidth`. It defaults to `width`.
58
+ * Sets the maximum length of the line that holds a comment whose whole text is one prose
59
+ * paragraph. Such a comment stays on one line up to this length plus `tolerance`, even past
60
+ * `width`, but never past `maxWidth`. It defaults to `width`.
60
61
  */
61
62
  readonly singleLineWidth?: number;
62
63
  readonly tabWidth: number;
@@ -228,26 +229,28 @@ interface CommentsConfig {
228
229
  * Sets the maximum length of the line that holds a comment whose whole text is one prose
229
230
  * paragraph. Such a comment stays on one line up to this length plus `tolerance`, even past
230
231
  * `width`, and is wrapped to `width` beyond it. Defaults to 120, and the line never exceeds
231
- * `maxWidth`.
232
+ * the `maxWidth` limit.
232
233
  */
233
234
  readonly singleLineWidth?: number;
234
235
  /**
235
236
  * Sets how many columns prose lines may go past `width` when that saves a line in a paragraph
236
- * of three or more lines. A paragraph that already has the layout for a wider `width`, up to
237
- * `width` plus this many columns, also passes as it is. So does a paragraph with as many lines
238
- * as the rewrap whose lines are each at most this many columns shorter or longer than in the
239
- * rewrap. It never goes past `maxWidth`. When `maxWidth` is omitted, it also sets a legacy hard
240
- * limit of `width + tolerance`.
237
+ * of three or more lines. A paragraph that already has the layout for a wider `width`, up
238
+ * to `width` plus this many columns, also passes as it is. So does a paragraph with as many
239
+ * lines as the rewrap whose lines, the last aside, are at most this many columns shorter
240
+ * than the shortest of them in the rewrap, and end at most this many columns past `width`.
241
+ * It never goes past `maxWidth`. When `maxWidth` is omitted, it also sets a legacy hard limit
242
+ * of `width + tolerance` columns.
241
243
  */
242
244
  readonly tolerance?: number;
243
245
  /**
244
246
  * Keep the first word of a new sentence or parenthetical off the end of a line, e.g.
245
- * `...the module. This` or `...reflows (the` followed by the rest on the next line.
246
- * A paragraph of two lines also ends its first line with a sentence when the rest fits
247
- * on the second line and is no longer than the first, instead of with the start of
248
- * the next sentence, like `...the module. This one`. Other lines avoid ending with the
249
- * first two words of a sentence, like `...opens. It allocates`, unless that makes them
250
- * much less even. Defaults to `true`.
247
+ * `...the module. This` or `...reflows (the` followed by the rest on the next line. The same
248
+ * goes for the first word after a semicolon or colon, but not after a comma, so a line may
249
+ * end with `...the paths, and`. A paragraph of two lines also ends its first line with a
250
+ * sentence when the rest fits on the second line and is no longer than the first, instead
251
+ * of with the start of the next sentence, like `...the module. This one`. Other lines avoid
252
+ * ending with the first two words of a sentence, like `...opens. It allocates`, unless that
253
+ * makes them much less even. Defaults to `true`.
251
254
  */
252
255
  readonly avoidSentenceOrphans?: boolean;
253
256
  /**
package/dist/comments.js CHANGED
@@ -128,6 +128,7 @@ function findStyleIssues(lines) {
128
128
  // src/comments/wrap.ts
129
129
  var CLAUSE_END = /[.!?,;:]["')\]*_]*$/;
130
130
  var SENTENCE_END = /[.!?]["')\]*_]*$/;
131
+ var STATEMENT_END = /[.!?;:]["')\]*_]*$/;
131
132
  var ABBREVIATIONS = /* @__PURE__ */ new Set([
132
133
  "e.g.",
133
134
  "i.e.",
@@ -359,8 +360,8 @@ function bindParentheticals(tokens, limit) {
359
360
  }
360
361
  return units;
361
362
  }
362
- function endsClause(token) {
363
- return CLAUSE_END.test(token) && !isAbbreviation(token);
363
+ function endsStatement(token) {
364
+ return STATEMENT_END.test(token) && !isAbbreviation(token);
364
365
  }
365
366
  function endsSentence(token) {
366
367
  return SENTENCE_END.test(token) && !isAbbreviation(token);
@@ -369,7 +370,7 @@ function opensAside(token) {
369
370
  return /^[([]/.test(token) && !/[)\]]["'`.,;:!?]*$/.test(token);
370
371
  }
371
372
  function isOrphan(previous, token) {
372
- return opensAside(token) || endsClause(previous) && !CLAUSE_END.test(token);
373
+ return opensAside(token) || endsStatement(previous) && !CLAUSE_END.test(token);
373
374
  }
374
375
  function startsBlock(token) {
375
376
  return /^(?:\+|-+|=+|\*+|_{3,}|\d+[.)]|#{1,6})$/.test(token) || /^(?:>|@[A-Za-z]|`{3}|~{3}|\||<(?:\/?[A-Za-z]|[!?]))/.test(token);
@@ -770,6 +771,7 @@ var ISSUE_TIERS = {
770
771
  underfill: "verdict",
771
772
  widow: "verdict",
772
773
  unbalanced: "verdict",
774
+ wide: "verdict",
773
775
  orphan: "hint",
774
776
  "split-parenthetical": "hint",
775
777
  banner: "hint",
@@ -1356,6 +1358,14 @@ function analyzeParagraph(paragraph, options, language) {
1356
1358
  const restLines = layoutTokens(rest, restLimit, restLimit, restOptions);
1357
1359
  return sameLayout(breakAfterSentence(restLines, restLimit, restLimit, restOptions), currentLines.slice(line + 1));
1358
1360
  };
1361
+ const differenceAt = (line) => {
1362
+ const longest = Math.max(...wrapped.map((words) => words.join(" ").length));
1363
+ const wide = currentLines.flatMap((words, position) => {
1364
+ const limit = (position === 0 ? firstLimit : restLimit) + layoutOptions.tolerance;
1365
+ return words.join(" ").length > Math.max(limit, longest) ? [{ type: "wide", line: position }] : [];
1366
+ });
1367
+ return wide.length > 0 ? wide : [{ type: "unbalanced", line }];
1368
+ };
1359
1369
  if (overflow.length === 0 && (currentLines.length === wrapped.length || options.maxWidth !== void 0)) {
1360
1370
  const line = Math.max(
1361
1371
  wrapped.findIndex((words, position) => words.join(" ") !== currentLines[position]?.join(" ")),
@@ -1364,9 +1374,11 @@ function analyzeParagraph(paragraph, options, language) {
1364
1374
  if (lineIssues.length === 0 && (sameLayout(even, currentLines) || keepsOnlySentenceStarts())) {
1365
1375
  lineIssues.push({ type: "orphan", line });
1366
1376
  } else if (lineIssues.length === 0) {
1367
- lineIssues.push({ type: splitsOnlyParenthetical(line) ? "split-parenthetical" : "unbalanced", line });
1377
+ lineIssues.push(
1378
+ ...splitsOnlyParenthetical(line) ? [{ type: "split-parenthetical", line }] : differenceAt(line)
1379
+ );
1368
1380
  } else if (lineIssues.every((issue) => issue.type === "orphan") && !sameLayout(even, currentLines) && !keepsOnlyOrphans()) {
1369
- lineIssues.push({ type: "unbalanced", line });
1381
+ lineIssues.push(...differenceAt(line));
1370
1382
  }
1371
1383
  }
1372
1384
  const splitLine = splitTokenLine(currentLines, tokens);
@@ -1384,14 +1396,15 @@ function analyzeParagraph(paragraph, options, language) {
1384
1396
  return false;
1385
1397
  };
1386
1398
  const staysNearLayout = () => {
1387
- if (currentLines.length !== wrapped.length || splitTokenLine(currentLines, units) !== -1) {
1399
+ if (layoutOptions.tolerance === 0 || currentLines.length !== wrapped.length || splitTokenLine(currentLines, units) !== -1) {
1388
1400
  return false;
1389
1401
  }
1402
+ const shortest = Math.min(...wrapped.slice(0, -1).map((words) => words.join(" ").length));
1390
1403
  return currentLines.every((words, position) => {
1391
1404
  const length = words.join(" ").length;
1392
- const suggestedLength = wrapped[position].join(" ").length;
1393
1405
  const limit = (position === 0 ? firstLimit : restLimit) + layoutOptions.tolerance;
1394
- return Math.abs(length - suggestedLength) <= layoutOptions.tolerance && length <= Math.max(suggestedLength, limit);
1406
+ const isLast = position === currentLines.length - 1;
1407
+ return (isLast || length >= shortest - layoutOptions.tolerance) && length <= Math.max(wrapped[position].join(" ").length, limit);
1395
1408
  });
1396
1409
  };
1397
1410
  const hasVerdict = lineIssues.some((issue) => isVerdict(issue));
@@ -1743,7 +1756,7 @@ When rules pull in different directions, the earlier one wins.
1743
1756
  ## Layout
1744
1757
 
1745
1758
  - After you finish, the tool rewraps prose paragraphs, list items, and JSDoc tag descriptions. The width is a preferred target. A parenthetical may extend a line up to the configured maximum so it stays together, and lines may go up to the configured tolerance past the width when that saves a line. In longer paragraphs, balanced lines take priority over keeping every parenthetical on one line. The tool also avoids short last lines where possible. Leave these line breaks to the tool, except for the sentence-orphan case below.
1746
- - Don't end a line with the first word of a new sentence, clause, or parenthetical, like \`This\` after a period, \`the\` after a comma, or \`(the\`. Move it to the next line instead. The same goes for the first two words of a sentence, like \`It allocates\` after a period, when the note points at them. A long word, like an identifier or a code span, may stay at the end of a line when moving it would leave that line far shorter than the lines around it. Then leave the line breaks as they are.
1759
+ - Don't end a line with the first word of a new sentence or parenthetical, like \`This\` after a period or \`(the\`, or with the first word after a semicolon or colon. Move it to the next line instead. The same goes for the first two words of a sentence, like \`It allocates\` after a period, when the note points at them. A long word, like an identifier or a code span, may stay at the end of a line when moving it would leave that line far shorter than the lines around it. Then leave the line breaks as they are. The word after a comma is no such word. A line may end with it, like \`and\` in \`...the teardown paths, and\`.
1747
1760
  - In a paragraph of two lines, the first line ends with a sentence whenever the rest fits on the second line and is no longer than the first. Don't end it with the start of the next sentence, like \`A wrap\` in \`...lay out differently. A wrap\`. Move those words to the second line instead.
1748
1761
  - A comment whose whole text is one paragraph stays on a single line when that line fits a separate, larger single-line width, even past the width. Only a longer comment wraps to the width.
1749
1762
  - Separate paragraphs with an empty comment line.