pickier 0.1.24 → 0.1.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/cli.js CHANGED
@@ -16536,6 +16536,7 @@ ${lines.slice(bodyRange.from + 1, bodyRange.to + 1).join(`
16536
16536
  if (openParenIdx !== -1) {
16537
16537
  let isTypeSignature = false;
16538
16538
  let angleDepthBack = 0;
16539
+ let parenDepthBack = 0;
16539
16540
  for (let k = openParenIdx - 1;k >= 0; k--) {
16540
16541
  const ch = line[k];
16541
16542
  if (ch === ">") {
@@ -16547,10 +16548,13 @@ ${lines.slice(bodyRange.from + 1, bodyRange.to + 1).join(`
16547
16548
  angleDepthBack--;
16548
16549
  continue;
16549
16550
  }
16550
- isTypeSignature = true;
16551
- break;
16551
+ if (parenDepthBack === 0) {
16552
+ isTypeSignature = true;
16553
+ break;
16554
+ }
16555
+ continue;
16552
16556
  }
16553
- if (ch === ":" && angleDepthBack === 0) {
16557
+ if (ch === ":" && angleDepthBack === 0 && parenDepthBack === 0) {
16554
16558
  isTypeSignature = true;
16555
16559
  break;
16556
16560
  }
@@ -16558,11 +16562,34 @@ ${lines.slice(bodyRange.from + 1, bodyRange.to + 1).join(`
16558
16562
  continue;
16559
16563
  if (ch === ",")
16560
16564
  continue;
16561
- if (ch === "=" || ch === "(" || ch === "{" || ch === "[") {
16565
+ if (ch === ")") {
16566
+ parenDepthBack++;
16567
+ continue;
16568
+ }
16569
+ if (ch === "(") {
16570
+ parenDepthBack--;
16571
+ continue;
16572
+ }
16573
+ if (ch === "|" || ch === "&") {
16574
+ isTypeSignature = true;
16562
16575
  break;
16563
16576
  }
16577
+ if (ch === "=" || ch === "{" || ch === "[") {
16578
+ if (parenDepthBack >= 0)
16579
+ break;
16580
+ continue;
16581
+ }
16564
16582
  if (ch !== " " && ch !== "\t" && !/[\w.]/.test(ch)) {
16565
- break;
16583
+ if (parenDepthBack >= 0)
16584
+ break;
16585
+ }
16586
+ }
16587
+ if (!isTypeSignature) {
16588
+ const beforeParen = line.slice(0, openParenIdx);
16589
+ if (/^\s*(?:export\s+)?(?:declare\s+)?type\s+\w[\w$]*\s*(?:<[^>]*>)?\s*=\s*$/.test(beforeParen)) {
16590
+ isTypeSignature = true;
16591
+ } else if (/\bas\s+$/.test(beforeParen)) {
16592
+ isTypeSignature = true;
16566
16593
  }
16567
16594
  }
16568
16595
  if (isTypeSignature) {
@@ -19392,6 +19419,42 @@ var init_link_image_reference_definitions = __esm(() => {
19392
19419
  }
19393
19420
  }
19394
19421
  return issues;
19422
+ },
19423
+ fix: (text) => {
19424
+ const lines = text.split(/\r?\n/);
19425
+ const inCode = getCodeBlockLines(lines);
19426
+ const defLines = new Map;
19427
+ for (let i = 0;i < lines.length; i++) {
19428
+ if (inCode.has(i))
19429
+ continue;
19430
+ const m = lines[i].match(/^\s*\[([^\]]+)\]:\s*\S+/);
19431
+ if (m)
19432
+ defLines.set(i, m[1].toLowerCase());
19433
+ }
19434
+ if (defLines.size === 0)
19435
+ return text;
19436
+ const usages = new Set;
19437
+ for (let i = 0;i < lines.length; i++) {
19438
+ if (inCode.has(i))
19439
+ continue;
19440
+ if (defLines.has(i))
19441
+ continue;
19442
+ const line = lines[i];
19443
+ const refMatches = line.matchAll(/\[([^\]]+)\](?:\[([^\]]*)\])?(?!\()/g);
19444
+ for (const m of refMatches) {
19445
+ const label = (m[2] && m[2].length > 0 ? m[2] : m[1]).toLowerCase();
19446
+ usages.add(label);
19447
+ }
19448
+ }
19449
+ const toRemove = new Set;
19450
+ for (const [idx, label] of defLines) {
19451
+ if (!usages.has(label))
19452
+ toRemove.add(idx);
19453
+ }
19454
+ if (toRemove.size === 0)
19455
+ return text;
19456
+ return lines.filter((_, idx) => !toRemove.has(idx)).join(`
19457
+ `);
19395
19458
  }
19396
19459
  };
19397
19460
  });
@@ -19409,19 +19472,39 @@ var init_link_image_style = __esm(() => {
19409
19472
  check: (text, ctx) => {
19410
19473
  const issues = [];
19411
19474
  const lines = text.split(/\r?\n/);
19475
+ const inCode = getCodeBlockLines(lines);
19412
19476
  const options = ctx.options || {};
19413
19477
  const style = options.style || "consistent";
19414
- let detectedStyle = null;
19415
- let inFence = false;
19478
+ let target = style === "consistent" ? null : style;
19479
+ if (target === null) {
19480
+ let inlineCount = 0;
19481
+ let refCount = 0;
19482
+ let inHtmlCommentScan = false;
19483
+ for (let i = 0;i < lines.length; i++) {
19484
+ if (inCode.has(i))
19485
+ continue;
19486
+ const line = lines[i];
19487
+ if (line.includes("<!--"))
19488
+ inHtmlCommentScan = true;
19489
+ if (line.includes("-->")) {
19490
+ inHtmlCommentScan = false;
19491
+ continue;
19492
+ }
19493
+ if (inHtmlCommentScan)
19494
+ continue;
19495
+ if (/^\s*\[(?:[^\]]+)\]:\s*\S+/.test(line))
19496
+ continue;
19497
+ const scrubbed = stripInlineCode(line);
19498
+ inlineCount += (scrubbed.match(/\[[^\]]+\]\([^)]+\)/g) || []).length;
19499
+ refCount += (scrubbed.match(/\[[^\]]+\]\[(?:[^\]]*)\]/g) || []).length;
19500
+ }
19501
+ target = refCount > inlineCount ? "reference" : "inline";
19502
+ }
19416
19503
  let inHtmlComment = false;
19417
19504
  for (let i = 0;i < lines.length; i++) {
19418
- const line = lines[i];
19419
- if (/^(?:`{3,}|~{3,})/.test(line.trim())) {
19420
- inFence = !inFence;
19421
- continue;
19422
- }
19423
- if (inFence)
19505
+ if (inCode.has(i))
19424
19506
  continue;
19507
+ const line = lines[i];
19425
19508
  if (line.includes("<!--"))
19426
19509
  inHtmlComment = true;
19427
19510
  if (line.includes("-->")) {
@@ -19430,64 +19513,104 @@ var init_link_image_style = __esm(() => {
19430
19513
  }
19431
19514
  if (inHtmlComment)
19432
19515
  continue;
19433
- if (line.match(/^\[(?:[^\]]+)\]:\s*\S+/)) {
19516
+ if (line.match(/^\[(?:[^\]]+)\]:\s*\S+/))
19434
19517
  continue;
19435
- }
19436
19518
  const scrubbed = stripInlineCode(line);
19437
19519
  const inlineMatches = scrubbed.matchAll(/\[[^\]]+\]\([^)]+\)/g);
19438
19520
  for (const match of inlineMatches) {
19439
- if (style === "reference") {
19521
+ if (target === "reference") {
19440
19522
  issues.push({
19441
19523
  filePath: ctx.filePath,
19442
19524
  line: i + 1,
19443
19525
  column: match.index + 1,
19444
19526
  ruleId: "markdown/link-image-style",
19445
- message: "Expected reference style link",
19446
- severity: "error"
19527
+ message: style === "consistent" ? "Link style should be consistent throughout document" : "Expected reference style link",
19528
+ severity: style === "consistent" ? "warning" : "error"
19447
19529
  });
19448
- } else if (style === "consistent") {
19449
- if (detectedStyle === null) {
19450
- detectedStyle = "inline";
19451
- } else if (detectedStyle === "reference") {
19452
- issues.push({
19453
- filePath: ctx.filePath,
19454
- line: i + 1,
19455
- column: match.index + 1,
19456
- ruleId: "markdown/link-image-style",
19457
- message: "Link style should be consistent throughout document",
19458
- severity: "warning"
19459
- });
19460
- }
19461
19530
  }
19462
19531
  }
19463
19532
  const refMatches = scrubbed.matchAll(/\[[^\]]+\]\[(?:[^\]]+)\]/g);
19464
19533
  for (const match of refMatches) {
19465
- if (style === "inline") {
19534
+ if (target === "inline") {
19466
19535
  issues.push({
19467
19536
  filePath: ctx.filePath,
19468
19537
  line: i + 1,
19469
19538
  column: match.index + 1,
19470
19539
  ruleId: "markdown/link-image-style",
19471
- message: "Expected inline style link",
19472
- severity: "error"
19540
+ message: style === "consistent" ? "Link style should be consistent throughout document" : "Expected inline style link",
19541
+ severity: style === "consistent" ? "warning" : "error"
19473
19542
  });
19474
- } else if (style === "consistent") {
19475
- if (detectedStyle === null) {
19476
- detectedStyle = "reference";
19477
- } else if (detectedStyle === "inline") {
19478
- issues.push({
19479
- filePath: ctx.filePath,
19480
- line: i + 1,
19481
- column: match.index + 1,
19482
- ruleId: "markdown/link-image-style",
19483
- message: "Link style should be consistent throughout document",
19484
- severity: "warning"
19485
- });
19486
- }
19487
19543
  }
19488
19544
  }
19489
19545
  }
19490
19546
  return issues;
19547
+ },
19548
+ fix: (text, ctx) => {
19549
+ const options = ctx.options || {};
19550
+ const style = options.style || "consistent";
19551
+ const lines = text.split(/\r?\n/);
19552
+ const inCode = getCodeBlockLines(lines);
19553
+ const defs = new Map;
19554
+ for (let i = 0;i < lines.length; i++) {
19555
+ if (inCode.has(i))
19556
+ continue;
19557
+ const m = lines[i].match(/^\s*\[([^\]]+)\]:\s*(\S+)(?:\s+(?:"([^"]*)"|'([^']*)'|\(([^)]*)\)))?\s*$/);
19558
+ if (m) {
19559
+ const label = m[1].toLowerCase();
19560
+ const url = m[2];
19561
+ const title = m[3] ?? m[4] ?? m[5];
19562
+ if (!defs.has(label))
19563
+ defs.set(label, { url, title });
19564
+ }
19565
+ }
19566
+ if (defs.size === 0)
19567
+ return text;
19568
+ let target = style === "reference" ? "reference" : "inline";
19569
+ if (style === "consistent") {
19570
+ let inlineCount = 0;
19571
+ let refCount = 0;
19572
+ for (let i = 0;i < lines.length; i++) {
19573
+ if (inCode.has(i))
19574
+ continue;
19575
+ const line = lines[i];
19576
+ if (/^\s*\[(?:[^\]]+)\]:\s*\S+/.test(line))
19577
+ continue;
19578
+ const scrubbed = stripInlineCode(line);
19579
+ inlineCount += (scrubbed.match(/\[[^\]]+\]\([^)]+\)/g) || []).length;
19580
+ refCount += (scrubbed.match(/\[[^\]]+\]\[(?:[^\]]*)\]/g) || []).length;
19581
+ }
19582
+ target = refCount > inlineCount ? "reference" : "inline";
19583
+ }
19584
+ if (target !== "inline")
19585
+ return text;
19586
+ let changed = false;
19587
+ for (let i = 0;i < lines.length; i++) {
19588
+ if (inCode.has(i))
19589
+ continue;
19590
+ const original = lines[i];
19591
+ if (/^\s*\[(?:[^\]]+)\]:\s*\S+/.test(original))
19592
+ continue;
19593
+ let rewritten = original;
19594
+ for (let pass = 0;pass < 8; pass++) {
19595
+ const next = rewritten.replace(/(!?)\[((?:[^[\]]|\[[^\]]*\]\([^)]*\))+)\]\[([^\]]*)\]/g, (whole, bang, textPart, labelPart) => {
19596
+ const labelKey = (labelPart.trim() === "" ? textPart : labelPart).toLowerCase();
19597
+ const def = defs.get(labelKey);
19598
+ if (!def)
19599
+ return whole;
19600
+ const titlePart = def.title ? ` "${def.title}"` : "";
19601
+ return `${bang}[${textPart}](${def.url}${titlePart})`;
19602
+ });
19603
+ if (next === rewritten)
19604
+ break;
19605
+ rewritten = next;
19606
+ }
19607
+ if (rewritten !== original) {
19608
+ lines[i] = rewritten;
19609
+ changed = true;
19610
+ }
19611
+ }
19612
+ return changed ? lines.join(`
19613
+ `) : text;
19491
19614
  }
19492
19615
  };
19493
19616
  });
@@ -20891,24 +21014,18 @@ var init_single_title = __esm(() => {
20891
21014
  check: (text, ctx) => {
20892
21015
  const issues = [];
20893
21016
  const lines = text.split(/\r?\n/);
21017
+ const inCode = getCodeBlockLines(lines);
20894
21018
  let firstH1Line = -1;
20895
- let inFencedCodeBlock = false;
20896
21019
  for (let i = 0;i < lines.length; i++) {
21020
+ if (inCode.has(i))
21021
+ continue;
20897
21022
  const line = lines[i];
20898
21023
  const nextLine = i + 1 < lines.length ? lines[i + 1] : "";
20899
- if (/^(?:`{3,}|~{3,})/.test(line.trim())) {
20900
- inFencedCodeBlock = !inFencedCodeBlock;
20901
- continue;
20902
- }
20903
- if (inFencedCodeBlock)
20904
- continue;
20905
21024
  let isH1 = false;
20906
- if (/^#\s/.test(line)) {
21025
+ if (/^#\s/.test(line))
20907
21026
  isH1 = true;
20908
- }
20909
- if (/^=+\s*$/.test(nextLine) && line.trim().length > 0) {
21027
+ if (/^=+\s*$/.test(nextLine) && line.trim().length > 0 && !inCode.has(i + 1))
20910
21028
  isH1 = true;
20911
- }
20912
21029
  if (isH1) {
20913
21030
  if (firstH1Line === -1) {
20914
21031
  firstH1Line = i + 1;
@@ -20925,6 +21042,47 @@ var init_single_title = __esm(() => {
20925
21042
  }
20926
21043
  }
20927
21044
  return issues;
21045
+ },
21046
+ fix: (text) => {
21047
+ const lines = text.split(/\r?\n/);
21048
+ const inCode = getCodeBlockLines(lines);
21049
+ const result = [];
21050
+ let seenH1 = false;
21051
+ let changed = false;
21052
+ for (let i = 0;i < lines.length; i++) {
21053
+ if (inCode.has(i)) {
21054
+ result.push(lines[i]);
21055
+ continue;
21056
+ }
21057
+ const line = lines[i];
21058
+ const nextLine = i + 1 < lines.length ? lines[i + 1] : "";
21059
+ const atxH1 = /^#\s/.test(line);
21060
+ const setextH1 = /^=+\s*$/.test(nextLine) && line.trim().length > 0 && !inCode.has(i + 1);
21061
+ if (atxH1) {
21062
+ if (!seenH1) {
21063
+ seenH1 = true;
21064
+ result.push(line);
21065
+ } else {
21066
+ result.push(`#${line}`);
21067
+ changed = true;
21068
+ }
21069
+ continue;
21070
+ }
21071
+ if (setextH1) {
21072
+ if (!seenH1) {
21073
+ seenH1 = true;
21074
+ result.push(line);
21075
+ continue;
21076
+ }
21077
+ result.push(`## ${line.trim()}`);
21078
+ i++;
21079
+ changed = true;
21080
+ continue;
21081
+ }
21082
+ result.push(line);
21083
+ }
21084
+ return changed ? result.join(`
21085
+ `) : text;
20928
21086
  }
20929
21087
  };
20930
21088
  });
@@ -21525,6 +21683,13 @@ function splitFrontmatter(content) {
21525
21683
  }
21526
21684
  return { header: null, body: content };
21527
21685
  }
21686
+ function markdownOnlyWholeFile(rule) {
21687
+ return {
21688
+ meta: rule.meta,
21689
+ check: (content, context) => context.filePath.endsWith(".md") ? rule.check(content, context) : [],
21690
+ fix: rule.fix ? (content, context) => context.filePath.endsWith(".md") ? rule.fix(content, context) : content : undefined
21691
+ };
21692
+ }
21528
21693
  function markdownOnly(rule) {
21529
21694
  return {
21530
21695
  meta: rule.meta,
@@ -21632,7 +21797,7 @@ var init_markdown = __esm(() => {
21632
21797
  "no-multiple-space-blockquote": markdownOnly(noMultipleSpaceBlockquoteRule),
21633
21798
  "no-blanks-blockquote": markdownOnly(noBlanksBlockquoteRule),
21634
21799
  "blanks-around-fences": markdownOnly(blanksAroundFencesRule),
21635
- "single-trailing-newline": markdownOnly(singleTrailingNewlineRule),
21800
+ "single-trailing-newline": markdownOnlyWholeFile(singleTrailingNewlineRule),
21636
21801
  "blanks-around-tables": markdownOnly(blanksAroundTablesRule),
21637
21802
  "no-reversed-links": markdownOnly(noReversedLinksRule),
21638
21803
  "no-bare-urls": markdownOnly(noBareUrlsRule),
@@ -37920,7 +38085,7 @@ var require_package = __commonJS((exports, module) => {
37920
38085
  module.exports = {
37921
38086
  name: "pickier",
37922
38087
  type: "module",
37923
- version: "0.1.24",
38088
+ version: "0.1.25",
37924
38089
  description: "Format, lint and more in a fraction of seconds.",
37925
38090
  author: "Chris Breuer <chris@stacksjs.org>",
37926
38091
  license: "MIT",
package/dist/src/index.js CHANGED
@@ -16153,6 +16153,7 @@ ${lines.slice(bodyRange.from + 1, bodyRange.to + 1).join(`
16153
16153
  if (openParenIdx !== -1) {
16154
16154
  let isTypeSignature = false;
16155
16155
  let angleDepthBack = 0;
16156
+ let parenDepthBack = 0;
16156
16157
  for (let k = openParenIdx - 1;k >= 0; k--) {
16157
16158
  const ch = line[k];
16158
16159
  if (ch === ">") {
@@ -16164,10 +16165,13 @@ ${lines.slice(bodyRange.from + 1, bodyRange.to + 1).join(`
16164
16165
  angleDepthBack--;
16165
16166
  continue;
16166
16167
  }
16167
- isTypeSignature = true;
16168
- break;
16168
+ if (parenDepthBack === 0) {
16169
+ isTypeSignature = true;
16170
+ break;
16171
+ }
16172
+ continue;
16169
16173
  }
16170
- if (ch === ":" && angleDepthBack === 0) {
16174
+ if (ch === ":" && angleDepthBack === 0 && parenDepthBack === 0) {
16171
16175
  isTypeSignature = true;
16172
16176
  break;
16173
16177
  }
@@ -16175,11 +16179,34 @@ ${lines.slice(bodyRange.from + 1, bodyRange.to + 1).join(`
16175
16179
  continue;
16176
16180
  if (ch === ",")
16177
16181
  continue;
16178
- if (ch === "=" || ch === "(" || ch === "{" || ch === "[") {
16182
+ if (ch === ")") {
16183
+ parenDepthBack++;
16184
+ continue;
16185
+ }
16186
+ if (ch === "(") {
16187
+ parenDepthBack--;
16188
+ continue;
16189
+ }
16190
+ if (ch === "|" || ch === "&") {
16191
+ isTypeSignature = true;
16179
16192
  break;
16180
16193
  }
16194
+ if (ch === "=" || ch === "{" || ch === "[") {
16195
+ if (parenDepthBack >= 0)
16196
+ break;
16197
+ continue;
16198
+ }
16181
16199
  if (ch !== " " && ch !== "\t" && !/[\w.]/.test(ch)) {
16182
- break;
16200
+ if (parenDepthBack >= 0)
16201
+ break;
16202
+ }
16203
+ }
16204
+ if (!isTypeSignature) {
16205
+ const beforeParen = line.slice(0, openParenIdx);
16206
+ if (/^\s*(?:export\s+)?(?:declare\s+)?type\s+\w[\w$]*\s*(?:<[^>]*>)?\s*=\s*$/.test(beforeParen)) {
16207
+ isTypeSignature = true;
16208
+ } else if (/\bas\s+$/.test(beforeParen)) {
16209
+ isTypeSignature = true;
16183
16210
  }
16184
16211
  }
16185
16212
  if (isTypeSignature) {
@@ -19009,6 +19036,42 @@ var init_link_image_reference_definitions = __esm(() => {
19009
19036
  }
19010
19037
  }
19011
19038
  return issues;
19039
+ },
19040
+ fix: (text) => {
19041
+ const lines = text.split(/\r?\n/);
19042
+ const inCode = getCodeBlockLines(lines);
19043
+ const defLines = new Map;
19044
+ for (let i = 0;i < lines.length; i++) {
19045
+ if (inCode.has(i))
19046
+ continue;
19047
+ const m = lines[i].match(/^\s*\[([^\]]+)\]:\s*\S+/);
19048
+ if (m)
19049
+ defLines.set(i, m[1].toLowerCase());
19050
+ }
19051
+ if (defLines.size === 0)
19052
+ return text;
19053
+ const usages = new Set;
19054
+ for (let i = 0;i < lines.length; i++) {
19055
+ if (inCode.has(i))
19056
+ continue;
19057
+ if (defLines.has(i))
19058
+ continue;
19059
+ const line = lines[i];
19060
+ const refMatches = line.matchAll(/\[([^\]]+)\](?:\[([^\]]*)\])?(?!\()/g);
19061
+ for (const m of refMatches) {
19062
+ const label = (m[2] && m[2].length > 0 ? m[2] : m[1]).toLowerCase();
19063
+ usages.add(label);
19064
+ }
19065
+ }
19066
+ const toRemove = new Set;
19067
+ for (const [idx, label] of defLines) {
19068
+ if (!usages.has(label))
19069
+ toRemove.add(idx);
19070
+ }
19071
+ if (toRemove.size === 0)
19072
+ return text;
19073
+ return lines.filter((_, idx) => !toRemove.has(idx)).join(`
19074
+ `);
19012
19075
  }
19013
19076
  };
19014
19077
  });
@@ -19026,19 +19089,39 @@ var init_link_image_style = __esm(() => {
19026
19089
  check: (text, ctx) => {
19027
19090
  const issues = [];
19028
19091
  const lines = text.split(/\r?\n/);
19092
+ const inCode = getCodeBlockLines(lines);
19029
19093
  const options = ctx.options || {};
19030
19094
  const style = options.style || "consistent";
19031
- let detectedStyle = null;
19032
- let inFence = false;
19095
+ let target = style === "consistent" ? null : style;
19096
+ if (target === null) {
19097
+ let inlineCount = 0;
19098
+ let refCount = 0;
19099
+ let inHtmlCommentScan = false;
19100
+ for (let i = 0;i < lines.length; i++) {
19101
+ if (inCode.has(i))
19102
+ continue;
19103
+ const line = lines[i];
19104
+ if (line.includes("<!--"))
19105
+ inHtmlCommentScan = true;
19106
+ if (line.includes("-->")) {
19107
+ inHtmlCommentScan = false;
19108
+ continue;
19109
+ }
19110
+ if (inHtmlCommentScan)
19111
+ continue;
19112
+ if (/^\s*\[(?:[^\]]+)\]:\s*\S+/.test(line))
19113
+ continue;
19114
+ const scrubbed = stripInlineCode(line);
19115
+ inlineCount += (scrubbed.match(/\[[^\]]+\]\([^)]+\)/g) || []).length;
19116
+ refCount += (scrubbed.match(/\[[^\]]+\]\[(?:[^\]]*)\]/g) || []).length;
19117
+ }
19118
+ target = refCount > inlineCount ? "reference" : "inline";
19119
+ }
19033
19120
  let inHtmlComment = false;
19034
19121
  for (let i = 0;i < lines.length; i++) {
19035
- const line = lines[i];
19036
- if (/^(?:`{3,}|~{3,})/.test(line.trim())) {
19037
- inFence = !inFence;
19038
- continue;
19039
- }
19040
- if (inFence)
19122
+ if (inCode.has(i))
19041
19123
  continue;
19124
+ const line = lines[i];
19042
19125
  if (line.includes("<!--"))
19043
19126
  inHtmlComment = true;
19044
19127
  if (line.includes("-->")) {
@@ -19047,64 +19130,104 @@ var init_link_image_style = __esm(() => {
19047
19130
  }
19048
19131
  if (inHtmlComment)
19049
19132
  continue;
19050
- if (line.match(/^\[(?:[^\]]+)\]:\s*\S+/)) {
19133
+ if (line.match(/^\[(?:[^\]]+)\]:\s*\S+/))
19051
19134
  continue;
19052
- }
19053
19135
  const scrubbed = stripInlineCode(line);
19054
19136
  const inlineMatches = scrubbed.matchAll(/\[[^\]]+\]\([^)]+\)/g);
19055
19137
  for (const match of inlineMatches) {
19056
- if (style === "reference") {
19138
+ if (target === "reference") {
19057
19139
  issues.push({
19058
19140
  filePath: ctx.filePath,
19059
19141
  line: i + 1,
19060
19142
  column: match.index + 1,
19061
19143
  ruleId: "markdown/link-image-style",
19062
- message: "Expected reference style link",
19063
- severity: "error"
19144
+ message: style === "consistent" ? "Link style should be consistent throughout document" : "Expected reference style link",
19145
+ severity: style === "consistent" ? "warning" : "error"
19064
19146
  });
19065
- } else if (style === "consistent") {
19066
- if (detectedStyle === null) {
19067
- detectedStyle = "inline";
19068
- } else if (detectedStyle === "reference") {
19069
- issues.push({
19070
- filePath: ctx.filePath,
19071
- line: i + 1,
19072
- column: match.index + 1,
19073
- ruleId: "markdown/link-image-style",
19074
- message: "Link style should be consistent throughout document",
19075
- severity: "warning"
19076
- });
19077
- }
19078
19147
  }
19079
19148
  }
19080
19149
  const refMatches = scrubbed.matchAll(/\[[^\]]+\]\[(?:[^\]]+)\]/g);
19081
19150
  for (const match of refMatches) {
19082
- if (style === "inline") {
19151
+ if (target === "inline") {
19083
19152
  issues.push({
19084
19153
  filePath: ctx.filePath,
19085
19154
  line: i + 1,
19086
19155
  column: match.index + 1,
19087
19156
  ruleId: "markdown/link-image-style",
19088
- message: "Expected inline style link",
19089
- severity: "error"
19157
+ message: style === "consistent" ? "Link style should be consistent throughout document" : "Expected inline style link",
19158
+ severity: style === "consistent" ? "warning" : "error"
19090
19159
  });
19091
- } else if (style === "consistent") {
19092
- if (detectedStyle === null) {
19093
- detectedStyle = "reference";
19094
- } else if (detectedStyle === "inline") {
19095
- issues.push({
19096
- filePath: ctx.filePath,
19097
- line: i + 1,
19098
- column: match.index + 1,
19099
- ruleId: "markdown/link-image-style",
19100
- message: "Link style should be consistent throughout document",
19101
- severity: "warning"
19102
- });
19103
- }
19104
19160
  }
19105
19161
  }
19106
19162
  }
19107
19163
  return issues;
19164
+ },
19165
+ fix: (text, ctx) => {
19166
+ const options = ctx.options || {};
19167
+ const style = options.style || "consistent";
19168
+ const lines = text.split(/\r?\n/);
19169
+ const inCode = getCodeBlockLines(lines);
19170
+ const defs = new Map;
19171
+ for (let i = 0;i < lines.length; i++) {
19172
+ if (inCode.has(i))
19173
+ continue;
19174
+ const m = lines[i].match(/^\s*\[([^\]]+)\]:\s*(\S+)(?:\s+(?:"([^"]*)"|'([^']*)'|\(([^)]*)\)))?\s*$/);
19175
+ if (m) {
19176
+ const label = m[1].toLowerCase();
19177
+ const url = m[2];
19178
+ const title = m[3] ?? m[4] ?? m[5];
19179
+ if (!defs.has(label))
19180
+ defs.set(label, { url, title });
19181
+ }
19182
+ }
19183
+ if (defs.size === 0)
19184
+ return text;
19185
+ let target = style === "reference" ? "reference" : "inline";
19186
+ if (style === "consistent") {
19187
+ let inlineCount = 0;
19188
+ let refCount = 0;
19189
+ for (let i = 0;i < lines.length; i++) {
19190
+ if (inCode.has(i))
19191
+ continue;
19192
+ const line = lines[i];
19193
+ if (/^\s*\[(?:[^\]]+)\]:\s*\S+/.test(line))
19194
+ continue;
19195
+ const scrubbed = stripInlineCode(line);
19196
+ inlineCount += (scrubbed.match(/\[[^\]]+\]\([^)]+\)/g) || []).length;
19197
+ refCount += (scrubbed.match(/\[[^\]]+\]\[(?:[^\]]*)\]/g) || []).length;
19198
+ }
19199
+ target = refCount > inlineCount ? "reference" : "inline";
19200
+ }
19201
+ if (target !== "inline")
19202
+ return text;
19203
+ let changed = false;
19204
+ for (let i = 0;i < lines.length; i++) {
19205
+ if (inCode.has(i))
19206
+ continue;
19207
+ const original = lines[i];
19208
+ if (/^\s*\[(?:[^\]]+)\]:\s*\S+/.test(original))
19209
+ continue;
19210
+ let rewritten = original;
19211
+ for (let pass = 0;pass < 8; pass++) {
19212
+ const next = rewritten.replace(/(!?)\[((?:[^[\]]|\[[^\]]*\]\([^)]*\))+)\]\[([^\]]*)\]/g, (whole, bang, textPart, labelPart) => {
19213
+ const labelKey = (labelPart.trim() === "" ? textPart : labelPart).toLowerCase();
19214
+ const def = defs.get(labelKey);
19215
+ if (!def)
19216
+ return whole;
19217
+ const titlePart = def.title ? ` "${def.title}"` : "";
19218
+ return `${bang}[${textPart}](${def.url}${titlePart})`;
19219
+ });
19220
+ if (next === rewritten)
19221
+ break;
19222
+ rewritten = next;
19223
+ }
19224
+ if (rewritten !== original) {
19225
+ lines[i] = rewritten;
19226
+ changed = true;
19227
+ }
19228
+ }
19229
+ return changed ? lines.join(`
19230
+ `) : text;
19108
19231
  }
19109
19232
  };
19110
19233
  });
@@ -20508,24 +20631,18 @@ var init_single_title = __esm(() => {
20508
20631
  check: (text, ctx) => {
20509
20632
  const issues = [];
20510
20633
  const lines = text.split(/\r?\n/);
20634
+ const inCode = getCodeBlockLines(lines);
20511
20635
  let firstH1Line = -1;
20512
- let inFencedCodeBlock = false;
20513
20636
  for (let i = 0;i < lines.length; i++) {
20637
+ if (inCode.has(i))
20638
+ continue;
20514
20639
  const line = lines[i];
20515
20640
  const nextLine = i + 1 < lines.length ? lines[i + 1] : "";
20516
- if (/^(?:`{3,}|~{3,})/.test(line.trim())) {
20517
- inFencedCodeBlock = !inFencedCodeBlock;
20518
- continue;
20519
- }
20520
- if (inFencedCodeBlock)
20521
- continue;
20522
20641
  let isH1 = false;
20523
- if (/^#\s/.test(line)) {
20642
+ if (/^#\s/.test(line))
20524
20643
  isH1 = true;
20525
- }
20526
- if (/^=+\s*$/.test(nextLine) && line.trim().length > 0) {
20644
+ if (/^=+\s*$/.test(nextLine) && line.trim().length > 0 && !inCode.has(i + 1))
20527
20645
  isH1 = true;
20528
- }
20529
20646
  if (isH1) {
20530
20647
  if (firstH1Line === -1) {
20531
20648
  firstH1Line = i + 1;
@@ -20542,6 +20659,47 @@ var init_single_title = __esm(() => {
20542
20659
  }
20543
20660
  }
20544
20661
  return issues;
20662
+ },
20663
+ fix: (text) => {
20664
+ const lines = text.split(/\r?\n/);
20665
+ const inCode = getCodeBlockLines(lines);
20666
+ const result = [];
20667
+ let seenH1 = false;
20668
+ let changed = false;
20669
+ for (let i = 0;i < lines.length; i++) {
20670
+ if (inCode.has(i)) {
20671
+ result.push(lines[i]);
20672
+ continue;
20673
+ }
20674
+ const line = lines[i];
20675
+ const nextLine = i + 1 < lines.length ? lines[i + 1] : "";
20676
+ const atxH1 = /^#\s/.test(line);
20677
+ const setextH1 = /^=+\s*$/.test(nextLine) && line.trim().length > 0 && !inCode.has(i + 1);
20678
+ if (atxH1) {
20679
+ if (!seenH1) {
20680
+ seenH1 = true;
20681
+ result.push(line);
20682
+ } else {
20683
+ result.push(`#${line}`);
20684
+ changed = true;
20685
+ }
20686
+ continue;
20687
+ }
20688
+ if (setextH1) {
20689
+ if (!seenH1) {
20690
+ seenH1 = true;
20691
+ result.push(line);
20692
+ continue;
20693
+ }
20694
+ result.push(`## ${line.trim()}`);
20695
+ i++;
20696
+ changed = true;
20697
+ continue;
20698
+ }
20699
+ result.push(line);
20700
+ }
20701
+ return changed ? result.join(`
20702
+ `) : text;
20545
20703
  }
20546
20704
  };
20547
20705
  });
@@ -21142,6 +21300,13 @@ function splitFrontmatter(content) {
21142
21300
  }
21143
21301
  return { header: null, body: content };
21144
21302
  }
21303
+ function markdownOnlyWholeFile(rule) {
21304
+ return {
21305
+ meta: rule.meta,
21306
+ check: (content, context) => context.filePath.endsWith(".md") ? rule.check(content, context) : [],
21307
+ fix: rule.fix ? (content, context) => context.filePath.endsWith(".md") ? rule.fix(content, context) : content : undefined
21308
+ };
21309
+ }
21145
21310
  function markdownOnly(rule) {
21146
21311
  return {
21147
21312
  meta: rule.meta,
@@ -21249,7 +21414,7 @@ var init_markdown = __esm(() => {
21249
21414
  "no-multiple-space-blockquote": markdownOnly(noMultipleSpaceBlockquoteRule),
21250
21415
  "no-blanks-blockquote": markdownOnly(noBlanksBlockquoteRule),
21251
21416
  "blanks-around-fences": markdownOnly(blanksAroundFencesRule),
21252
- "single-trailing-newline": markdownOnly(singleTrailingNewlineRule),
21417
+ "single-trailing-newline": markdownOnlyWholeFile(singleTrailingNewlineRule),
21253
21418
  "blanks-around-tables": markdownOnly(blanksAroundTablesRule),
21254
21419
  "no-reversed-links": markdownOnly(noReversedLinksRule),
21255
21420
  "no-bare-urls": markdownOnly(noBareUrlsRule),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pickier",
3
3
  "type": "module",
4
- "version": "0.1.24",
4
+ "version": "0.1.25",
5
5
  "description": "Format, lint and more in a fraction of seconds.",
6
6
  "author": "Chris Breuer <chris@stacksjs.org>",
7
7
  "license": "MIT",