@codacy/tools-markdownlint-0 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Codacy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,56 @@
1
+ # @codacy/tools-markdownlint-0
2
+
3
+ ## Table of Contents
4
+ - [Overview](#overview)
5
+ - [Updating patterns](#updating-patterns)
6
+ - [Updating the markdownlint version](#updating-the-markdownlint-version)
7
+ - [Development](#development)
8
+ - [Notes for maintainers](#notes-for-maintainers)
9
+
10
+ ---
11
+
12
+ ## Overview
13
+
14
+ Markdown linter using the [markdownlint](https://github.com/DavidAnson/markdownlint) Node.js library. Uses the Library execution strategy — calls the markdownlint API directly rather than spawning a subprocess.
15
+
16
+ | Property | Value |
17
+ |----------|-------|
18
+ | Tool ID | `markdownlint` |
19
+ | Codacy UUID | `547ff16b-d57c-4d75-8067-5ccf3ea88a00` |
20
+ | Strategy | Library |
21
+ | Languages | Markdown |
22
+ | Dependency | `markdownlint` npm package (v0.x) |
23
+ | File patterns | `**/*.md` |
24
+
25
+ ## Updating patterns
26
+
27
+ ```bash
28
+ # Re-fetch pattern metadata from the Codacy API
29
+ pnpm prefetch
30
+
31
+ # Commit the result
32
+ git add src/patterns.json
33
+ ```
34
+
35
+ Pattern IDs follow the format `markdownlint_MD001`, `markdownlint_MD013`, etc.
36
+
37
+ ## Updating the markdownlint version
38
+
39
+ 1. Update the `markdownlint` version in `package.json`
40
+ 2. Run `pnpm install`
41
+ 3. Run `pnpm prefetch` to check for new/removed rules
42
+ 4. Run `pnpm test` to verify compatibility
43
+ 5. If the major version changes, create a new adapter package (`markdownlint-1/`)
44
+
45
+ ## Development
46
+
47
+ ```bash
48
+ pnpm build # Build with tsup
49
+ pnpm test # Run tests
50
+ ```
51
+
52
+ ## Notes for maintainers
53
+
54
+ - markdownlint v0.37+ is **pure ESM**. The adapter uses `dynamic import()` at runtime to stay CJS-compatible with the tsup build.
55
+ - `checkAvailability` dynamically imports markdownlint and checks its version.
56
+ - `install` is a no-op — the npm dependency handles installation.
@@ -0,0 +1,5 @@
1
+ import * as _codacy_tooling from '@codacy/tooling';
2
+
3
+ declare const _default: Readonly<_codacy_tooling.ToolAdapter>;
4
+
5
+ export { _default as default };
package/dist/index.js ADDED
@@ -0,0 +1,1001 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ default: () => index_default
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
36
+ var import_tooling = require("@codacy/tooling");
37
+
38
+ // src/adapter.ts
39
+ var import_path = __toESM(require("path"));
40
+ var import_fs = __toESM(require("fs"));
41
+
42
+ // src/patterns.json
43
+ var patterns_default = [
44
+ {
45
+ id: "markdownlint_MD001",
46
+ category: "BestPractice",
47
+ severityLevel: "Info",
48
+ title: "Enforce Incremental Heading Levels",
49
+ enabled: true,
50
+ parameters: []
51
+ },
52
+ {
53
+ id: "markdownlint_MD003",
54
+ category: "CodeStyle",
55
+ severityLevel: "Info",
56
+ title: "Enforce Consistent Heading Style",
57
+ enabled: true,
58
+ parameters: [
59
+ {
60
+ name: "style",
61
+ default: "consistent",
62
+ description: "Heading style"
63
+ }
64
+ ]
65
+ },
66
+ {
67
+ id: "markdownlint_MD004",
68
+ category: "CodeStyle",
69
+ severityLevel: "Info",
70
+ title: "Enforce Consistent Unordered List Style",
71
+ enabled: true,
72
+ parameters: [
73
+ {
74
+ name: "style",
75
+ default: "consistent",
76
+ description: "List style"
77
+ }
78
+ ]
79
+ },
80
+ {
81
+ id: "markdownlint_MD005",
82
+ category: "CodeStyle",
83
+ severityLevel: "Info",
84
+ title: "Enforce consistent indentation for list items at the same level",
85
+ enabled: true,
86
+ parameters: []
87
+ },
88
+ {
89
+ id: "markdownlint_MD007",
90
+ category: "CodeStyle",
91
+ severityLevel: "Info",
92
+ title: "Enforce Unordered List Indentation",
93
+ enabled: true,
94
+ parameters: [
95
+ {
96
+ name: "indent",
97
+ default: "2",
98
+ description: "Spaces for indent"
99
+ },
100
+ {
101
+ name: "start_indent",
102
+ default: "2",
103
+ description: "Spaces for first level indent (when start_indented is set)"
104
+ },
105
+ {
106
+ name: "start_indented",
107
+ default: "false",
108
+ description: "Whether to indent the first level of the list"
109
+ }
110
+ ]
111
+ },
112
+ {
113
+ id: "markdownlint_MD009",
114
+ category: "CodeStyle",
115
+ severityLevel: "Info",
116
+ title: "Avoid Trailing Spaces",
117
+ enabled: false,
118
+ parameters: [
119
+ {
120
+ name: "br_spaces",
121
+ default: "2",
122
+ description: "Spaces for line break"
123
+ },
124
+ {
125
+ name: "list_item_empty_lines",
126
+ default: "false",
127
+ description: "Allow spaces for empty lines in list items"
128
+ },
129
+ {
130
+ name: "strict",
131
+ default: "false",
132
+ description: "Include unnecessary breaks"
133
+ }
134
+ ]
135
+ },
136
+ {
137
+ id: "markdownlint_MD010",
138
+ category: "CodeStyle",
139
+ severityLevel: "Info",
140
+ title: "Avoid Hard Tabs",
141
+ enabled: true,
142
+ parameters: [
143
+ {
144
+ name: "code_blocks",
145
+ default: "true",
146
+ description: "Include code blocks"
147
+ },
148
+ {
149
+ name: "ignore_code_languages",
150
+ default: "[]",
151
+ description: "Fenced code languages to ignore"
152
+ },
153
+ {
154
+ name: "spaces_per_tab",
155
+ default: "1",
156
+ description: "Number of spaces for each hard tab"
157
+ }
158
+ ]
159
+ },
160
+ {
161
+ id: "markdownlint_MD011",
162
+ category: "ErrorProne",
163
+ severityLevel: "Warning",
164
+ title: "Avoid Reversed Link Syntax",
165
+ enabled: true,
166
+ parameters: []
167
+ },
168
+ {
169
+ id: "markdownlint_MD012",
170
+ category: "CodeStyle",
171
+ severityLevel: "Info",
172
+ title: "Disallow Multiple Consecutive Blank Lines",
173
+ enabled: true,
174
+ parameters: [
175
+ {
176
+ name: "maximum",
177
+ default: "1",
178
+ description: "Consecutive blank lines"
179
+ }
180
+ ]
181
+ },
182
+ {
183
+ id: "markdownlint_MD013",
184
+ category: "CodeStyle",
185
+ severityLevel: "Info",
186
+ title: "Enforce Maximum Line Length",
187
+ enabled: false,
188
+ parameters: [
189
+ {
190
+ name: "code_block_line_length",
191
+ default: "80",
192
+ description: "Number of characters for code blocks"
193
+ },
194
+ {
195
+ name: "code_blocks",
196
+ default: "true",
197
+ description: "Include code blocks"
198
+ },
199
+ {
200
+ name: "heading_line_length",
201
+ default: "80",
202
+ description: "Number of characters for headings"
203
+ },
204
+ {
205
+ name: "headings",
206
+ default: "true",
207
+ description: "Include headings"
208
+ },
209
+ {
210
+ name: "line_length",
211
+ default: "80",
212
+ description: "Number of characters"
213
+ },
214
+ {
215
+ name: "stern",
216
+ default: "false",
217
+ description: "Stern length checking"
218
+ },
219
+ {
220
+ name: "strict",
221
+ default: "false",
222
+ description: "Strict length checking"
223
+ },
224
+ {
225
+ name: "tables",
226
+ default: "true",
227
+ description: "Include tables"
228
+ }
229
+ ]
230
+ },
231
+ {
232
+ id: "markdownlint_MD014",
233
+ category: "CodeStyle",
234
+ severityLevel: "Info",
235
+ title: "Avoid Dollar Signs Before Commands Without Showing Output",
236
+ enabled: true,
237
+ parameters: []
238
+ },
239
+ {
240
+ id: "markdownlint_MD018",
241
+ category: "CodeStyle",
242
+ severityLevel: "Info",
243
+ title: "Enforce space after hash in ATX style heading",
244
+ enabled: true,
245
+ parameters: []
246
+ },
247
+ {
248
+ id: "markdownlint_MD019",
249
+ category: "CodeStyle",
250
+ severityLevel: "Info",
251
+ title: "Avoid Multiple Spaces After Hash in ATX Style Heading",
252
+ enabled: true,
253
+ parameters: []
254
+ },
255
+ {
256
+ id: "markdownlint_MD020",
257
+ category: "CodeStyle",
258
+ severityLevel: "Info",
259
+ title: "Enforce Space Inside Hashes on Closed Atx Style Headings",
260
+ enabled: true,
261
+ parameters: []
262
+ },
263
+ {
264
+ id: "markdownlint_MD021",
265
+ category: "CodeStyle",
266
+ severityLevel: "Info",
267
+ title: "Avoid Multiple Spaces Inside Hashes on Closed ATX Style Headings",
268
+ enabled: true,
269
+ parameters: []
270
+ },
271
+ {
272
+ id: "markdownlint_MD022",
273
+ category: "CodeStyle",
274
+ severityLevel: "Info",
275
+ title: "Enforce Headings Surrounded by Blank Lines",
276
+ enabled: true,
277
+ parameters: [
278
+ {
279
+ name: "lines_above",
280
+ default: "1",
281
+ description: "Blank lines above heading"
282
+ },
283
+ {
284
+ name: "lines_below",
285
+ default: "1",
286
+ description: "Blank lines below heading"
287
+ }
288
+ ]
289
+ },
290
+ {
291
+ id: "markdownlint_MD023",
292
+ category: "CodeStyle",
293
+ severityLevel: "Info",
294
+ title: "Enforce Headings Start at Beginning of Line",
295
+ enabled: true,
296
+ parameters: []
297
+ },
298
+ {
299
+ id: "markdownlint_MD024",
300
+ category: "BestPractice",
301
+ severityLevel: "Warning",
302
+ title: "Avoid Multiple Headings with the Same Content",
303
+ enabled: true,
304
+ parameters: [
305
+ {
306
+ name: "siblings_only",
307
+ default: "false",
308
+ description: "Only check sibling headings"
309
+ }
310
+ ]
311
+ },
312
+ {
313
+ id: "markdownlint_MD025",
314
+ category: "BestPractice",
315
+ severityLevel: "Info",
316
+ title: "Enforce Single Top-Level Heading in Markdown Document",
317
+ enabled: true,
318
+ parameters: [
319
+ {
320
+ name: "front_matter_title",
321
+ default: "^\\s*title\\s*[:=]",
322
+ description: "RegExp for matching title in front matter"
323
+ },
324
+ {
325
+ name: "level",
326
+ default: "1",
327
+ description: "Heading level"
328
+ }
329
+ ]
330
+ },
331
+ {
332
+ id: "markdownlint_MD026",
333
+ category: "CodeStyle",
334
+ severityLevel: "Info",
335
+ title: "Avoid Trailing Punctuation in Headings",
336
+ enabled: true,
337
+ parameters: [
338
+ {
339
+ name: "punctuation",
340
+ default: ".,;:!\u3002\uFF0C\uFF1B\uFF1A\uFF01",
341
+ description: "Punctuation characters"
342
+ }
343
+ ]
344
+ },
345
+ {
346
+ id: "markdownlint_MD027",
347
+ category: "CodeStyle",
348
+ severityLevel: "Info",
349
+ title: "Avoid Multiple Spaces After Blockquote Symbol",
350
+ enabled: true,
351
+ parameters: []
352
+ },
353
+ {
354
+ id: "markdownlint_MD028",
355
+ category: "Comprehensibility",
356
+ severityLevel: "Info",
357
+ title: "Avoid Blank Line Inside Blockquote",
358
+ enabled: true,
359
+ parameters: []
360
+ },
361
+ {
362
+ id: "markdownlint_MD029",
363
+ category: "CodeStyle",
364
+ severityLevel: "Info",
365
+ title: "Enforce Ordered List Item Prefix Consistency",
366
+ enabled: true,
367
+ parameters: [
368
+ {
369
+ name: "style",
370
+ default: "one_or_ordered",
371
+ description: "List style"
372
+ }
373
+ ]
374
+ },
375
+ {
376
+ id: "markdownlint_MD030",
377
+ category: "CodeStyle",
378
+ severityLevel: "Info",
379
+ title: "Enforce Spaces After List Markers",
380
+ enabled: true,
381
+ parameters: [
382
+ {
383
+ name: "ol_multi",
384
+ default: "1",
385
+ description: "Spaces for multi-line ordered list items"
386
+ },
387
+ {
388
+ name: "ol_single",
389
+ default: "1",
390
+ description: "Spaces for single-line ordered list items"
391
+ },
392
+ {
393
+ name: "ul_multi",
394
+ default: "1",
395
+ description: "Spaces for multi-line unordered list items"
396
+ },
397
+ {
398
+ name: "ul_single",
399
+ default: "1",
400
+ description: "Spaces for single-line unordered list items"
401
+ }
402
+ ]
403
+ },
404
+ {
405
+ id: "markdownlint_MD031",
406
+ category: "CodeStyle",
407
+ severityLevel: "Info",
408
+ title: "Enforce blank lines surrounding fenced code blocks",
409
+ enabled: false,
410
+ parameters: [
411
+ {
412
+ name: "list_items",
413
+ default: "true",
414
+ description: "Include list items"
415
+ }
416
+ ]
417
+ },
418
+ {
419
+ id: "markdownlint_MD032",
420
+ category: "CodeStyle",
421
+ severityLevel: "Info",
422
+ title: "Enforce Lists Surrounded by Blank Lines",
423
+ enabled: true,
424
+ parameters: []
425
+ },
426
+ {
427
+ id: "markdownlint_MD033",
428
+ category: "BestPractice",
429
+ severityLevel: "Info",
430
+ title: "Disallow Inline HTML in Markdown",
431
+ enabled: true,
432
+ parameters: [
433
+ {
434
+ name: "allowed_elements",
435
+ default: "[]",
436
+ description: "Allowed elements"
437
+ }
438
+ ]
439
+ },
440
+ {
441
+ id: "markdownlint_MD034",
442
+ category: "BestPractice",
443
+ severityLevel: "Info",
444
+ title: "Enforce Angle Brackets Around Bare URLs",
445
+ enabled: true,
446
+ parameters: []
447
+ },
448
+ {
449
+ id: "markdownlint_MD035",
450
+ category: "CodeStyle",
451
+ severityLevel: "Info",
452
+ title: "Enforce Consistent Horizontal Rule Style",
453
+ enabled: true,
454
+ parameters: [
455
+ {
456
+ name: "style",
457
+ default: "consistent",
458
+ description: "Horizontal rule style"
459
+ }
460
+ ]
461
+ },
462
+ {
463
+ id: "markdownlint_MD036",
464
+ category: "BestPractice",
465
+ severityLevel: "Info",
466
+ title: "Avoid Using Emphasis Instead of Headings",
467
+ enabled: true,
468
+ parameters: [
469
+ {
470
+ name: "punctuation",
471
+ default: ".,;:!?\u3002\uFF0C\uFF1B\uFF1A\uFF01\uFF1F",
472
+ description: "Punctuation characters"
473
+ }
474
+ ]
475
+ },
476
+ {
477
+ id: "markdownlint_MD037",
478
+ category: "CodeStyle",
479
+ severityLevel: "Info",
480
+ title: "Disallow Spaces Inside Emphasis Markers",
481
+ enabled: true,
482
+ parameters: []
483
+ },
484
+ {
485
+ id: "markdownlint_MD038",
486
+ category: "CodeStyle",
487
+ severityLevel: "Info",
488
+ title: "Disallow Spaces Inside Code Span Elements",
489
+ enabled: true,
490
+ parameters: []
491
+ },
492
+ {
493
+ id: "markdownlint_MD039",
494
+ category: "CodeStyle",
495
+ severityLevel: "Info",
496
+ title: "Avoid Spaces Inside Link Text",
497
+ enabled: true,
498
+ parameters: []
499
+ },
500
+ {
501
+ id: "markdownlint_MD040",
502
+ category: "CodeStyle",
503
+ severityLevel: "Info",
504
+ title: "Enforce language specification in fenced code blocks",
505
+ enabled: false,
506
+ parameters: [
507
+ {
508
+ name: "allowed_languages",
509
+ default: "[]",
510
+ description: "List of languages"
511
+ },
512
+ {
513
+ name: "language_only",
514
+ default: "false",
515
+ description: "Require language only"
516
+ }
517
+ ]
518
+ },
519
+ {
520
+ id: "markdownlint_MD041",
521
+ category: "BestPractice",
522
+ severityLevel: "Info",
523
+ title: "Enforce First Line as Top-Level Heading",
524
+ enabled: false,
525
+ parameters: [
526
+ {
527
+ name: "front_matter_title",
528
+ default: "^\\s*title\\s*[:=]",
529
+ description: "RegExp for matching title in front matter"
530
+ },
531
+ {
532
+ name: "level",
533
+ default: "1",
534
+ description: "Heading level"
535
+ }
536
+ ]
537
+ },
538
+ {
539
+ id: "markdownlint_MD042",
540
+ category: "BestPractice",
541
+ severityLevel: "Info",
542
+ title: "Disallow Empty Links",
543
+ enabled: true,
544
+ parameters: []
545
+ },
546
+ {
547
+ id: "markdownlint_MD043",
548
+ category: "BestPractice",
549
+ severityLevel: "Info",
550
+ title: "Enforce Required Heading Structure",
551
+ enabled: false,
552
+ parameters: [
553
+ {
554
+ name: "headings",
555
+ default: "[]",
556
+ description: "List of headings"
557
+ },
558
+ {
559
+ name: "match_case",
560
+ default: "false",
561
+ description: "Match case of headings"
562
+ }
563
+ ]
564
+ },
565
+ {
566
+ id: "markdownlint_MD044",
567
+ category: "CodeStyle",
568
+ severityLevel: "Info",
569
+ title: "Enforce Proper Capitalization of Proper Names",
570
+ enabled: true,
571
+ parameters: [
572
+ {
573
+ name: "code_blocks",
574
+ default: "true",
575
+ description: "Include code blocks"
576
+ },
577
+ {
578
+ name: "html_elements",
579
+ default: "true",
580
+ description: "Include HTML elements"
581
+ },
582
+ {
583
+ name: "names",
584
+ default: "[]",
585
+ description: "List of proper names"
586
+ }
587
+ ]
588
+ },
589
+ {
590
+ id: "markdownlint_MD045",
591
+ category: "BestPractice",
592
+ severityLevel: "Info",
593
+ title: "Enforce Images to Have Alternate Text (alt text)",
594
+ enabled: true,
595
+ parameters: []
596
+ },
597
+ {
598
+ id: "markdownlint_MD046",
599
+ category: "CodeStyle",
600
+ severityLevel: "Info",
601
+ title: "Enforce consistent code block style",
602
+ enabled: true,
603
+ parameters: [
604
+ {
605
+ name: "style",
606
+ default: "consistent",
607
+ description: "Block style"
608
+ }
609
+ ]
610
+ },
611
+ {
612
+ id: "markdownlint_MD047",
613
+ category: "CodeStyle",
614
+ severityLevel: "Info",
615
+ title: "Enforce Single Trailing Newline at End of File",
616
+ enabled: false,
617
+ parameters: []
618
+ },
619
+ {
620
+ id: "markdownlint_MD048",
621
+ category: "CodeStyle",
622
+ severityLevel: "Info",
623
+ title: "Enforce Consistent Code Fence Style",
624
+ enabled: true,
625
+ parameters: [
626
+ {
627
+ name: "style",
628
+ default: "consistent",
629
+ description: "Code fence style"
630
+ }
631
+ ]
632
+ },
633
+ {
634
+ id: "markdownlint_MD049",
635
+ category: "CodeStyle",
636
+ severityLevel: "Info",
637
+ title: "Enforce Consistent Emphasis Style",
638
+ enabled: true,
639
+ parameters: [
640
+ {
641
+ name: "style",
642
+ default: "consistent",
643
+ description: "Emphasis style"
644
+ }
645
+ ]
646
+ },
647
+ {
648
+ id: "markdownlint_MD050",
649
+ category: "CodeStyle",
650
+ severityLevel: "Info",
651
+ title: "Enforce Consistent Strong Style",
652
+ enabled: true,
653
+ parameters: [
654
+ {
655
+ name: "style",
656
+ default: "consistent",
657
+ description: "Strong style"
658
+ }
659
+ ]
660
+ },
661
+ {
662
+ id: "markdownlint_MD051",
663
+ category: "ErrorProne",
664
+ severityLevel: "Warning",
665
+ title: "Enforce Valid Link Fragments in Markdown",
666
+ enabled: true,
667
+ parameters: []
668
+ },
669
+ {
670
+ id: "markdownlint_MD052",
671
+ category: "ErrorProne",
672
+ severityLevel: "Warning",
673
+ title: "Enforce Defined Labels for Reference Links and Images",
674
+ enabled: true,
675
+ parameters: [
676
+ {
677
+ name: "shortcut_syntax",
678
+ default: "false",
679
+ description: "Include shortcut syntax"
680
+ }
681
+ ]
682
+ },
683
+ {
684
+ id: "markdownlint_MD053",
685
+ category: "BestPractice",
686
+ severityLevel: "Warning",
687
+ title: "Enforce Link and Image Reference Definitions Are Needed",
688
+ enabled: true,
689
+ parameters: [
690
+ {
691
+ name: "ignored_definitions",
692
+ default: '["//"]',
693
+ description: "Ignored definitions"
694
+ }
695
+ ]
696
+ },
697
+ {
698
+ id: "markdownlint_MD054",
699
+ category: "BestPractice",
700
+ severityLevel: "Info",
701
+ title: "Enforce Consistent Link and Image Style in Markdown",
702
+ enabled: true,
703
+ parameters: [
704
+ {
705
+ name: "autolink",
706
+ default: "true",
707
+ description: "Allow autolinks"
708
+ },
709
+ {
710
+ name: "collapsed",
711
+ default: "true",
712
+ description: "Allow collapsed reference links and images"
713
+ },
714
+ {
715
+ name: "full",
716
+ default: "true",
717
+ description: "Allow full reference links and images"
718
+ },
719
+ {
720
+ name: "inline",
721
+ default: "true",
722
+ description: "Allow inline links and images"
723
+ },
724
+ {
725
+ name: "shortcut",
726
+ default: "true",
727
+ description: "Allow shortcut reference links and images"
728
+ },
729
+ {
730
+ name: "url_inline",
731
+ default: "true",
732
+ description: "Allow URLs as inline links"
733
+ }
734
+ ]
735
+ },
736
+ {
737
+ id: "markdownlint_MD055",
738
+ category: "CodeStyle",
739
+ severityLevel: "Info",
740
+ title: "Enforce Table Pipe Style Consistency",
741
+ enabled: true,
742
+ parameters: [
743
+ {
744
+ name: "style",
745
+ default: "consistent",
746
+ description: "Table pipe style"
747
+ }
748
+ ]
749
+ },
750
+ {
751
+ id: "markdownlint_MD056",
752
+ category: "CodeStyle",
753
+ severityLevel: "Info",
754
+ title: "Enforce Consistent Table Column Count",
755
+ enabled: true,
756
+ parameters: []
757
+ }
758
+ ];
759
+
760
+ // src/adapter.ts
761
+ var TOOL_ID = "markdownlint";
762
+ var LOCAL_CONFIG_FILES = [
763
+ ".markdownlint.json",
764
+ ".markdownlint.yaml",
765
+ ".markdownlint.yml",
766
+ ".markdownlintrc"
767
+ ];
768
+ var PATTERN_META = new Map(
769
+ patterns_default.map((p) => [
770
+ p.id,
771
+ {
772
+ category: p.category,
773
+ severity: p.severityLevel ?? "Info"
774
+ }
775
+ ])
776
+ );
777
+ function ruleMetadata(ruleId) {
778
+ const patternId = `${TOOL_ID}_${ruleId}`;
779
+ return PATTERN_META.get(patternId) ?? { category: "Documentation", severity: "Info" };
780
+ }
781
+ function buildMarkdownlintConfig(patterns) {
782
+ const config = { default: false };
783
+ const prefix = `${TOOL_ID}_`;
784
+ for (const p of patterns) {
785
+ const ruleId = p.patternId.startsWith(prefix) ? p.patternId.slice(prefix.length) : p.patternId;
786
+ config[ruleId] = true;
787
+ }
788
+ return config;
789
+ }
790
+ function readLine(filePath, lineNumber) {
791
+ try {
792
+ const content = import_fs.default.readFileSync(filePath, "utf-8");
793
+ const lines = content.split("\n");
794
+ return lines[lineNumber - 1] ?? "";
795
+ } catch {
796
+ return "";
797
+ }
798
+ }
799
+ async function importMarkdownlintSync() {
800
+ return import("markdownlint/sync");
801
+ }
802
+ var adapter = {
803
+ id: TOOL_ID,
804
+ displayName: "markdownlint",
805
+ preferredVersion: "0.37.4",
806
+ compatibleVersions: ">=0.30.0 <1.0.0",
807
+ website: "https://github.com/DavidAnson/markdownlint",
808
+ languages: ["Markdown"],
809
+ filePatterns: ["**/*.md", "**/*.markdown"],
810
+ supportedOS: ["linux", "darwin", "win32"],
811
+ supportedArch: ["x64", "arm64"],
812
+ supportedRunners: ["local", "container"],
813
+ prerequisites: [],
814
+ /**
815
+ * Verifies that the `markdownlint` npm package is loadable and returns its
816
+ * installed version via the `getVersion()` function it exports.
817
+ *
818
+ * Because markdownlint is declared as a direct runtime dependency, it is
819
+ * always present after installation — this check primarily surfaces the
820
+ * version for logging and capability reports.
821
+ */
822
+ async checkAvailability(ctx) {
823
+ ctx.logger.debug("Checking availability", { toolId: TOOL_ID });
824
+ try {
825
+ const mod = await import("markdownlint");
826
+ const version = mod.getVersion();
827
+ ctx.logger.debug("Availability check result", { toolId: TOOL_ID, available: true, version });
828
+ return { available: true, version, installation: "bundled" };
829
+ } catch (err) {
830
+ const reason = `markdownlint package not loadable: ${err instanceof Error ? err.message : String(err)}`;
831
+ ctx.logger.debug("Availability check result", { toolId: TOOL_ID, available: false, reason });
832
+ return { available: false, reason };
833
+ }
834
+ },
835
+ /**
836
+ * No-op — markdownlint is an npm dependency and requires no runtime
837
+ * installation step.
838
+ */
839
+ async install(ctx) {
840
+ ctx.logger.info("Starting install", { toolId: TOOL_ID });
841
+ ctx.logger.info("Install not needed \u2014 npm dependency", { toolId: TOOL_ID });
842
+ return { success: true, installedVersion: adapter.preferredVersion };
843
+ },
844
+ /**
845
+ * Looks for any of the standard markdownlint config file names in the
846
+ * repository root. Returns the path to the first one found, or `found: false`
847
+ * if none are present.
848
+ */
849
+ async checkLocalConfigurationFile(ctx) {
850
+ ctx.logger.debug("Checking for local config", { toolId: TOOL_ID });
851
+ for (const name of LOCAL_CONFIG_FILES) {
852
+ const candidate = import_path.default.join(ctx.repositoryRoot, name);
853
+ try {
854
+ import_fs.default.accessSync(candidate);
855
+ ctx.logger.debug("Local config check", { toolId: TOOL_ID, found: true, path: candidate });
856
+ return { found: true, path: candidate };
857
+ } catch {
858
+ }
859
+ }
860
+ ctx.logger.debug("Local config check", { toolId: TOOL_ID, found: false, path: void 0 });
861
+ return { found: false };
862
+ },
863
+ /**
864
+ * Runs markdownlint against the target files and converts the results to
865
+ * Codacy Issue objects.
866
+ *
867
+ * Config resolution order:
868
+ * 1. If `useLocalConfigurationFile` is true, read the project's native config
869
+ * file via `readConfig()` and pass it as the inline config object.
870
+ * 2. If Codacy patterns are configured, build an inline config enabling only
871
+ * those rules (all others disabled via `default: false`).
872
+ * 3. Otherwise, run with markdownlint's built-in default rule set.
873
+ *
874
+ * Category and severity for each issue are sourced from patterns.json (which
875
+ * is generated by `pnpm prefetch` and committed to the repository).
876
+ *
877
+ * All paths in returned Issues are relative to `ctx.repositoryRoot`.
878
+ * Never throws — all errors are captured in the returned `errors` array.
879
+ */
880
+ async analyze(ctx, codacyConfig) {
881
+ const startMs = Date.now();
882
+ ctx.logger.info("Starting analysis", { toolId: TOOL_ID, fileCount: ctx.targetFiles.length });
883
+ const startedAt = /* @__PURE__ */ new Date();
884
+ const issues = [];
885
+ const errors = [];
886
+ const absoluteFiles = ctx.targetFiles.map(
887
+ (f) => import_path.default.resolve(ctx.repositoryRoot, f)
888
+ );
889
+ if (absoluteFiles.length === 0) {
890
+ const completedAt2 = /* @__PURE__ */ new Date();
891
+ return buildResult(startedAt, completedAt2, issues, errors, ctx.targetFiles.length);
892
+ }
893
+ let lintFn;
894
+ let readConfigFn;
895
+ try {
896
+ const mod = await importMarkdownlintSync();
897
+ lintFn = mod.lint;
898
+ readConfigFn = mod.readConfig;
899
+ } catch (err) {
900
+ const completedAt2 = /* @__PURE__ */ new Date();
901
+ errors.push({
902
+ toolId: TOOL_ID,
903
+ phase: "toolInvoke",
904
+ kind: "InvocationError",
905
+ message: `Failed to load markdownlint: ${err instanceof Error ? err.message : String(err)}`,
906
+ level: "error"
907
+ });
908
+ return buildResult(startedAt, completedAt2, issues, errors, ctx.targetFiles.length);
909
+ }
910
+ let inlineConfig;
911
+ if (codacyConfig.useLocalConfigurationFile && codacyConfig.localConfigurationFile) {
912
+ try {
913
+ inlineConfig = readConfigFn(codacyConfig.localConfigurationFile);
914
+ } catch (err) {
915
+ errors.push({
916
+ toolId: TOOL_ID,
917
+ phase: "toolConfig",
918
+ kind: "ConfigReadError",
919
+ message: `Failed to read config file ${codacyConfig.localConfigurationFile}: ${err instanceof Error ? err.message : String(err)}`,
920
+ level: "warning"
921
+ });
922
+ }
923
+ } else if (codacyConfig.patterns.length > 0) {
924
+ inlineConfig = buildMarkdownlintConfig(codacyConfig.patterns);
925
+ }
926
+ const lintOptions = { files: absoluteFiles };
927
+ if (inlineConfig !== void 0) {
928
+ lintOptions.config = inlineConfig;
929
+ }
930
+ try {
931
+ const lintResults = lintFn(lintOptions);
932
+ for (const [filePath, lintErrors] of Object.entries(lintResults)) {
933
+ const relPath = import_path.default.relative(ctx.repositoryRoot, filePath);
934
+ for (const lintError of lintErrors) {
935
+ const ruleId = lintError.ruleNames[0];
936
+ if (!ruleId) {
937
+ errors.push({
938
+ toolId: TOOL_ID,
939
+ phase: "outputParse",
940
+ kind: "UnknownPattern",
941
+ message: `markdownlint returned an issue with no rule name in file: ${relPath}`,
942
+ level: "warning",
943
+ filePath: relPath
944
+ });
945
+ continue;
946
+ }
947
+ const line = lintError.lineNumber;
948
+ const column = lintError.errorRange ? lintError.errorRange[0] : 1;
949
+ const detail = lintError.errorDetail ? `: ${lintError.errorDetail}` : "";
950
+ const message = `${lintError.ruleDescription}${detail}`;
951
+ const meta = ruleMetadata(ruleId);
952
+ issues.push({
953
+ filePath: relPath,
954
+ patternId: `${TOOL_ID}_${ruleId}`,
955
+ toolId: TOOL_ID,
956
+ line,
957
+ column,
958
+ message,
959
+ lineContent: readLine(filePath, line),
960
+ category: meta.category,
961
+ severity: meta.severity
962
+ });
963
+ }
964
+ }
965
+ } catch (err) {
966
+ errors.push({
967
+ toolId: TOOL_ID,
968
+ phase: "toolInvoke",
969
+ kind: "InvocationError",
970
+ message: `markdownlint failed: ${err instanceof Error ? err.message : String(err)}`,
971
+ level: "error"
972
+ });
973
+ }
974
+ const completedAt = /* @__PURE__ */ new Date();
975
+ ctx.logger.info("Analysis complete", { toolId: TOOL_ID, issueCount: issues.length, errorCount: errors.length, durationMs: Date.now() - startMs });
976
+ return buildResult(startedAt, completedAt, issues, errors, ctx.targetFiles.length);
977
+ }
978
+ };
979
+ function buildResult(startedAt, completedAt, issues, errors, filesAnalyzed) {
980
+ const durationMs = completedAt.getTime() - startedAt.getTime();
981
+ return {
982
+ metadata: {
983
+ startedAt: startedAt.toISOString(),
984
+ completedAt: completedAt.toISOString(),
985
+ durationMs
986
+ },
987
+ issues,
988
+ errors,
989
+ summary: {
990
+ toolId: TOOL_ID,
991
+ status: errors.some((e) => e.level === "error") ? "partial" : "success",
992
+ issueCount: issues.length,
993
+ errorCount: errors.length,
994
+ durationMs,
995
+ filesAnalyzed
996
+ }
997
+ };
998
+ }
999
+
1000
+ // src/index.ts
1001
+ var index_default = (0, import_tooling.defineToolAdapter)(adapter);
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@codacy/tools-markdownlint-0",
3
+ "version": "0.1.0",
4
+ "description": "markdownlint adapter — Library-mode Markdown linter",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "dependencies": {
11
+ "markdownlint": "^0.37.4",
12
+ "@codacy/tooling": "0.1.0"
13
+ },
14
+ "license": "MIT",
15
+ "author": "Codacy <support@codacy.com> (https://www.codacy.com)",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/codacy/analysis-cli.git",
19
+ "directory": "packages/tools/markdownlint-0"
20
+ },
21
+ "homepage": "https://github.com/codacy/analysis-cli",
22
+ "engines": {
23
+ "node": ">=20.0.0"
24
+ },
25
+ "scripts": {
26
+ "build": "tsup src/index.ts --format cjs --dts --clean",
27
+ "test": "vitest run",
28
+ "lint": "eslint src/",
29
+ "clean": "rm -rf dist",
30
+ "prefetch": "node ../scripts/fetch-patterns.mjs 547ff16b-d57c-4d75-8067-5ccf3ea88a00 src/patterns.json"
31
+ }
32
+ }