eslint-plugin-markdown-preferences 0.8.0 → 0.10.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/lib/index.js CHANGED
@@ -25,6 +25,98 @@ function createRule(ruleName, rule) {
25
25
  };
26
26
  }
27
27
 
28
+ //#endregion
29
+ //#region src/rules/canonical-code-block-language.ts
30
+ const DEFAULT_LANGUAGES = {
31
+ javascript: "js",
32
+ jsx: "js",
33
+ mjs: "js",
34
+ cjs: "js",
35
+ typescript: "ts",
36
+ tsx: "ts",
37
+ mts: "ts",
38
+ cts: "ts",
39
+ python: "py",
40
+ bash: "sh",
41
+ shell: "sh",
42
+ zsh: "sh",
43
+ yml: "yaml",
44
+ markdown: "md",
45
+ rust: "rs",
46
+ golang: "go",
47
+ cplusplus: "cpp",
48
+ "c++": "cpp",
49
+ postgresql: "sql",
50
+ mysql: "sql",
51
+ sqlite: "sql"
52
+ };
53
+ var canonical_code_block_language_default = createRule("canonical-code-block-language", {
54
+ meta: {
55
+ type: "suggestion",
56
+ docs: {
57
+ description: "enforce canonical language names in code blocks",
58
+ categories: [],
59
+ listCategory: "Stylistic"
60
+ },
61
+ fixable: "code",
62
+ hasSuggestions: false,
63
+ schema: [{
64
+ type: "object",
65
+ properties: { languages: {
66
+ type: "object",
67
+ patternProperties: { "^[\\s\\S]+$": { type: "string" } },
68
+ additionalProperties: false
69
+ } },
70
+ additionalProperties: false
71
+ }],
72
+ messages: { useCanonical: "Use canonical language name \"{{canonical}}\" instead of \"{{current}}\"." }
73
+ },
74
+ create(context) {
75
+ const sourceCode = context.sourceCode;
76
+ const languages = context.options[0]?.languages || DEFAULT_LANGUAGES;
77
+ return { code(node) {
78
+ if (!node.lang || !languages[node.lang]) return;
79
+ const canonical = languages[node.lang];
80
+ const current = node.lang;
81
+ if (current === canonical) return;
82
+ const nodeRange = sourceCode.getRange(node);
83
+ const nodeText = sourceCode.text.slice(nodeRange[0], nodeRange[1]);
84
+ const fenceRegex = /^(`{3,}|~{3,})(\w*)(?:\s.*)?$/mu;
85
+ const fenceMatch = fenceRegex.exec(nodeText.split("\n")[0]);
86
+ if (!fenceMatch) return;
87
+ const [, fence, langInfo] = fenceMatch;
88
+ const langStart = nodeRange[0] + fence.length;
89
+ const langEnd = langStart + langInfo.length;
90
+ const nodeLoc = sourceCode.getLoc(node);
91
+ const beforeFence = sourceCode.text.slice(nodeRange[0], langStart);
92
+ const beforeLines = beforeFence.split(/\n/u);
93
+ const line = nodeLoc.start.line + beforeLines.length - 1;
94
+ const column = (beforeLines.length === 1 ? nodeLoc.start.column : 0) + (beforeLines.at(-1) || "").length;
95
+ context.report({
96
+ node,
97
+ loc: {
98
+ start: {
99
+ line,
100
+ column
101
+ },
102
+ end: {
103
+ line,
104
+ column: column + langInfo.length
105
+ }
106
+ },
107
+ messageId: "useCanonical",
108
+ data: {
109
+ canonical,
110
+ current
111
+ },
112
+ fix(fixer) {
113
+ return fixer.replaceTextRange([langStart, langEnd], canonical);
114
+ }
115
+ });
116
+ } };
117
+ }
118
+ });
119
+
28
120
  //#endregion
29
121
  //#region src/rules/definitions-last.ts
30
122
  var definitions_last_default = createRule("definitions-last", {
@@ -111,6 +203,1108 @@ var hard_linebreak_style_default = createRule("hard-linebreak-style", {
111
203
  }
112
204
  });
113
205
 
206
+ //#endregion
207
+ //#region src/utils/regexp.ts
208
+ const RE_REGEXP_STR = /^\/(.+)\/([A-Za-z]*)$/u;
209
+ /**
210
+ * Convert a string to the `RegExp`.
211
+ * Normal strings (e.g. `"foo"`) is converted to `/^foo$/` of `RegExp`.
212
+ * Strings like `"/^foo/i"` are converted to `/^foo/i` of `RegExp`.
213
+ *
214
+ * @param {string} string The string to convert.
215
+ * @returns {RegExp} Returns the `RegExp`.
216
+ */
217
+ function toRegExp(string) {
218
+ const parts = RE_REGEXP_STR.exec(string);
219
+ if (parts) return new RegExp(parts[1], parts[2]);
220
+ return { test: (s) => s === string };
221
+ }
222
+ /**
223
+ * Checks whether given string is regexp string
224
+ * @param {string} string
225
+ * @returns {boolean}
226
+ */
227
+ function isRegExp(string) {
228
+ return Boolean(RE_REGEXP_STR.test(string));
229
+ }
230
+
231
+ //#endregion
232
+ //#region src/resources/preserve-words.ts
233
+ const defaultPreserveWords = [
234
+ "JavaScript",
235
+ "TypeScript",
236
+ "ECMAScript",
237
+ "ES6",
238
+ ...(function* () {
239
+ const end = (/* @__PURE__ */ new Date()).getFullYear() + 3;
240
+ for (let i = 2015; i <= end; i++) yield `ES${i}`;
241
+ })(),
242
+ "PHP",
243
+ "Python",
244
+ "Java",
245
+ "C#",
246
+ "C++",
247
+ "Rust",
248
+ "Go",
249
+ "go",
250
+ "Swift",
251
+ "Kotlin",
252
+ "Dart",
253
+ "Ruby",
254
+ "Scala",
255
+ "Perl",
256
+ "R",
257
+ "MATLAB",
258
+ "Lua",
259
+ "Haskell",
260
+ "Elixir",
261
+ "Clojure",
262
+ "F#",
263
+ "OCaml",
264
+ "Zig",
265
+ "V",
266
+ "Nim",
267
+ "Crystal",
268
+ "Gleam",
269
+ "Odin",
270
+ "Carbon",
271
+ "HTML",
272
+ "CSS",
273
+ "Sass",
274
+ "SCSS",
275
+ "Less",
276
+ "Stylus",
277
+ "JSON",
278
+ "XML",
279
+ "PDF",
280
+ "CSV",
281
+ "YAML",
282
+ "TOML",
283
+ "Markdown",
284
+ "LaTeX",
285
+ "Parquet",
286
+ "Avro",
287
+ "Protobuf",
288
+ "MessagePack",
289
+ "BSON",
290
+ "HDF5",
291
+ "Apache Arrow",
292
+ "ORC",
293
+ "SQL",
294
+ "GraphQL",
295
+ "React",
296
+ "Vue",
297
+ "Angular",
298
+ "Redux",
299
+ "Svelte",
300
+ "SvelteKit",
301
+ "Preact",
302
+ "Solid",
303
+ "Alpine.js",
304
+ "Lit",
305
+ "Stencil",
306
+ "Ember.js",
307
+ "Backbone.js",
308
+ "jQuery",
309
+ "D3.js",
310
+ "Three.js",
311
+ "Chart.js",
312
+ "Plotly",
313
+ "Astro",
314
+ "Remix",
315
+ "Qwik",
316
+ "SolidJS",
317
+ "Vike",
318
+ "Node.js",
319
+ "Deno",
320
+ "Bun",
321
+ "Electron",
322
+ "Tauri",
323
+ "Next.js",
324
+ "Nuxt.js",
325
+ "Gatsby",
326
+ "Express.js",
327
+ "NestJS",
328
+ "FastAPI",
329
+ "Django",
330
+ "Flask",
331
+ "Ruby on Rails",
332
+ "Spring Boot",
333
+ "Laravel",
334
+ "Phoenix",
335
+ "Actix",
336
+ "Axum",
337
+ "Rocket",
338
+ "Flutter",
339
+ "React Native",
340
+ "Ionic",
341
+ "Xamarin",
342
+ "Expo",
343
+ "Unity",
344
+ "Unreal Engine",
345
+ "ESLint",
346
+ "Prettier",
347
+ "Biome",
348
+ "oxc",
349
+ "swc",
350
+ "Webpack",
351
+ "Vite",
352
+ "Babel",
353
+ "Workbox",
354
+ "Rollup",
355
+ "Parcel",
356
+ "esbuild",
357
+ "Turbo",
358
+ "Turborepo",
359
+ "Nx",
360
+ "Lerna",
361
+ "Rush",
362
+ "npm",
363
+ "yarn",
364
+ "pnpm",
365
+ "bun",
366
+ "bower",
367
+ "composer",
368
+ "pip",
369
+ "conda",
370
+ "Maven",
371
+ "Gradle",
372
+ "SBT",
373
+ "Cargo",
374
+ "homebrew",
375
+ "chocolatey",
376
+ "CocoaPods",
377
+ "Carthage",
378
+ "Swift Package Manager",
379
+ "VS Code",
380
+ "Visual Studio Code",
381
+ "Vim",
382
+ "Neovim",
383
+ "Emacs",
384
+ "Sublime Text",
385
+ "Atom",
386
+ "Brackets",
387
+ "brackets",
388
+ "Visual Studio",
389
+ "IntelliJ IDEA",
390
+ "WebStorm",
391
+ "PHPStorm",
392
+ "PyCharm",
393
+ "Android Studio",
394
+ "Xcode",
395
+ "Docker",
396
+ "Kubernetes",
397
+ "Helm",
398
+ "CI / CD",
399
+ "DevOps",
400
+ "GitOps",
401
+ "IaC",
402
+ "Infrastructure as Code",
403
+ "SaaS",
404
+ "PaaS",
405
+ "IaaS",
406
+ "CDN",
407
+ "Load Balancer",
408
+ "API Gateway",
409
+ "Microservices",
410
+ "Serverless",
411
+ "Lambda",
412
+ "Cloud Functions",
413
+ "Container Registry",
414
+ "Prometheus",
415
+ "Grafana",
416
+ "Terraform",
417
+ "Ansible",
418
+ "Jenkins",
419
+ "GitHub Actions",
420
+ "GitLab CI",
421
+ "CircleCI",
422
+ "Travis CI",
423
+ "Azure DevOps",
424
+ "TeamCity",
425
+ "Bamboo",
426
+ "Buildkite",
427
+ "Drone CI",
428
+ "AWS",
429
+ "Amazon Web Services",
430
+ "Azure",
431
+ "GCP",
432
+ "Google Cloud Platform",
433
+ "Heroku",
434
+ "Vercel",
435
+ "Netlify",
436
+ "Railway",
437
+ "Render",
438
+ "Fly.io",
439
+ "Cloudflare",
440
+ "DigitalOcean",
441
+ "API",
442
+ "APIs",
443
+ "REST",
444
+ "RESTful",
445
+ "gRPC",
446
+ "HTTP",
447
+ "HTTPS",
448
+ "WebSocket",
449
+ "SOAP",
450
+ "XML-RPC",
451
+ "JSON-RPC",
452
+ "CLI",
453
+ "SDK",
454
+ "URL",
455
+ "URI",
456
+ "UUID",
457
+ "GUID",
458
+ "CRUD",
459
+ "ACID",
460
+ "BASE",
461
+ "CAP Theorem",
462
+ "JWT",
463
+ "OAuth",
464
+ "OAuth2",
465
+ "OpenID Connect",
466
+ "SAML",
467
+ "SSO",
468
+ "MFA",
469
+ "2FA",
470
+ "CORS",
471
+ "CSRF",
472
+ "XSS",
473
+ "SSH",
474
+ "FTP",
475
+ "SFTP",
476
+ "SMTP",
477
+ "IMAP",
478
+ "POP3",
479
+ "TCP",
480
+ "UDP",
481
+ "IP",
482
+ "IPv4",
483
+ "IPv6",
484
+ "DNS",
485
+ "DHCP",
486
+ "VPN",
487
+ "SSL",
488
+ "TLS",
489
+ "LDAP",
490
+ "PostgreSQL",
491
+ "MySQL",
492
+ "SQLite",
493
+ "MariaDB",
494
+ "Oracle",
495
+ "SQL Server",
496
+ "CockroachDB",
497
+ "PlanetScale",
498
+ "Neon",
499
+ "NoSQL",
500
+ "MongoDB",
501
+ "DynamoDB",
502
+ "Cassandra",
503
+ "CouchDB",
504
+ "Neo4j",
505
+ "ArangoDB",
506
+ "FaunaDB",
507
+ "Firebase",
508
+ "Supabase",
509
+ "Redis",
510
+ "ElasticSearch",
511
+ "Solr",
512
+ "InfluxDB",
513
+ "TimescaleDB",
514
+ "Prisma",
515
+ "TypeORM",
516
+ "Sequelize",
517
+ "Mongoose",
518
+ "Drizzle",
519
+ "Knex.js",
520
+ "Objection.js",
521
+ "Bookshelf.js",
522
+ "QA",
523
+ "QC",
524
+ "TDD",
525
+ "BDD",
526
+ "E2E",
527
+ "Unit Testing",
528
+ "Integration Testing",
529
+ "Jest",
530
+ "Mocha",
531
+ "Chai",
532
+ "Jasmine",
533
+ "Karma",
534
+ "Vitest",
535
+ "Ava",
536
+ "Tape",
537
+ "Cypress",
538
+ "Playwright",
539
+ "Selenium",
540
+ "Puppeteer",
541
+ "WebDriver",
542
+ "TestCafe",
543
+ "SonarQube",
544
+ "Husky",
545
+ "lint-staged",
546
+ "commitizen",
547
+ "semantic-release",
548
+ "Codecov",
549
+ "CodeClimate",
550
+ "TensorFlow",
551
+ "PyTorch",
552
+ "Keras",
553
+ "Scikit-learn",
554
+ "Pandas",
555
+ "NumPy",
556
+ "OpenCV",
557
+ "Hugging Face",
558
+ "LangChain",
559
+ "OpenAI",
560
+ "Anthropic",
561
+ "Jupyter",
562
+ "MLflow",
563
+ "Weights & Biases",
564
+ "CUDA",
565
+ "ONNX",
566
+ "GPT",
567
+ "BERT",
568
+ "Transformer",
569
+ "Claude",
570
+ "Gemini",
571
+ "LLaMA",
572
+ "Stable Diffusion",
573
+ "DALL-E",
574
+ "Midjourney",
575
+ "AutoML",
576
+ "ETL",
577
+ "ELT",
578
+ "Big Data",
579
+ "Data Lake",
580
+ "Data Warehouse",
581
+ "OLAP",
582
+ "OLTP",
583
+ "Apache Spark",
584
+ "Apache Kafka",
585
+ "Apache Airflow",
586
+ "Hadoop",
587
+ "Snowflake",
588
+ "Databricks",
589
+ "Tableau",
590
+ "Power BI",
591
+ "Looker",
592
+ "OWASP",
593
+ "SAST",
594
+ "DAST",
595
+ "IAST",
596
+ "SCA",
597
+ "Penetration Testing",
598
+ "Vulnerability Assessment",
599
+ "RBAC",
600
+ "ABAC",
601
+ "Zero Trust",
602
+ "PKI",
603
+ "HSM",
604
+ "WAF",
605
+ "DDoS",
606
+ "PWA",
607
+ "SPA",
608
+ "SSR",
609
+ "SSG",
610
+ "CSR",
611
+ "JAMstack",
612
+ "Headless CMS",
613
+ "Edge Computing",
614
+ "WebAssembly",
615
+ "WASM",
616
+ "Service Worker",
617
+ "Web Components",
618
+ "Micro Frontends",
619
+ "BFF",
620
+ "Backend for Frontend",
621
+ "GraphQL",
622
+ "tRPC",
623
+ "gRPC-Web",
624
+ "WebRTC",
625
+ "WebGL",
626
+ "WebGPU",
627
+ "Material UI",
628
+ "Ant Design",
629
+ "Chakra UI",
630
+ "React Bootstrap",
631
+ "Semantic UI React",
632
+ "Blueprint",
633
+ "Mantine",
634
+ "NextUI",
635
+ "Arco Design",
636
+ "Tailwind CSS",
637
+ "Bootstrap",
638
+ "Bulma",
639
+ "Foundation",
640
+ "Semantic UI",
641
+ "Materialize",
642
+ "Spectre.css",
643
+ "Tachyons",
644
+ "PureCSS",
645
+ "styled-components",
646
+ "CSS-in-JS",
647
+ "Emotion",
648
+ "JSS",
649
+ "Styled System",
650
+ "Stitches",
651
+ "Vanilla Extract",
652
+ "Linaria",
653
+ "Aphrodite",
654
+ "Glamorous",
655
+ "Radium",
656
+ "Git",
657
+ "Mercurial",
658
+ "SVN",
659
+ "GitHub",
660
+ "GitLab",
661
+ "Bitbucket",
662
+ "Pull Request",
663
+ "Merge Request",
664
+ "Code Review",
665
+ "Pair Programming",
666
+ "Mob Programming",
667
+ "Docusaurus",
668
+ "GitBook",
669
+ "VitePress",
670
+ "VuePress",
671
+ "Docsify",
672
+ "MkDocs",
673
+ "Sphinx",
674
+ "Jekyll",
675
+ "Hugo",
676
+ "Eleventy",
677
+ "Hexo",
678
+ "Zola",
679
+ "Swagger",
680
+ "OpenAPI",
681
+ "Postman",
682
+ "Insomnia",
683
+ "Redoc",
684
+ "Stoplight",
685
+ "FAQ"
686
+ ];
687
+
688
+ //#endregion
689
+ //#region src/resources/minor-words.ts
690
+ const articles = [
691
+ "a",
692
+ "an",
693
+ "the"
694
+ ];
695
+ const conjunctions = [
696
+ "for",
697
+ "and",
698
+ "nor",
699
+ "but",
700
+ "or",
701
+ "yet",
702
+ "so"
703
+ ];
704
+ const prepositions = [
705
+ "a",
706
+ "as",
707
+ "at",
708
+ "by",
709
+ "ex",
710
+ "in",
711
+ "of",
712
+ "on",
713
+ "re",
714
+ "to",
715
+ "up"
716
+ ];
717
+ const defaultMinorWords = [
718
+ ...articles,
719
+ ...conjunctions,
720
+ ...prepositions
721
+ ];
722
+
723
+ //#endregion
724
+ //#region src/rules/heading-casing.ts
725
+ /**
726
+ * Parse preserve words and phrases from the options
727
+ * - Single words are added to preserveWords
728
+ * - Multi-word phrases are added to preservePhrases and added to preserveWords with no spaces
729
+ */
730
+ function parsePreserveWords(preserveWordsOption) {
731
+ const preserveWords = /* @__PURE__ */ new Map();
732
+ /**
733
+ * Add a single word to the preserveWords map
734
+ */
735
+ function addPreserveWord(word) {
736
+ const lowerWord = word.toLowerCase();
737
+ let list = preserveWords.get(lowerWord);
738
+ if (!list) {
739
+ list = [];
740
+ preserveWords.set(lowerWord, list);
741
+ }
742
+ list.push(word);
743
+ }
744
+ const preservePhrases = /* @__PURE__ */ new Map();
745
+ for (const word of preserveWordsOption) {
746
+ const splitted = word.split(/\s+/);
747
+ if (splitted.length <= 1) addPreserveWord(word);
748
+ else {
749
+ preservePhrases.set(word, splitted);
750
+ addPreserveWord(splitted.join(""));
751
+ }
752
+ }
753
+ return {
754
+ preserveWords,
755
+ preservePhrases: [...preservePhrases.values()].sort((a, b) => b.length - a.length)
756
+ };
757
+ }
758
+ /**
759
+ * Parse text into words with offsets
760
+ */
761
+ function parseText(text, firstNode, lastNode) {
762
+ const words = [];
763
+ const pattern = /(\w+(?:[^\s\w]\w+)*|:\w+:|[^\s\w]+|\s+)/gu;
764
+ let match;
765
+ while ((match = pattern.exec(text)) !== null) {
766
+ const token = match[1];
767
+ if (/^\s+$/.test(token)) continue;
768
+ const punctuation = /^(?::\w+:|[^\s\w]+)$/.test(token);
769
+ words.push({
770
+ word: token,
771
+ offset: match.index,
772
+ punctuation,
773
+ first: false,
774
+ last: false
775
+ });
776
+ }
777
+ if (firstNode) {
778
+ for (const w of words) if (!w.punctuation) {
779
+ w.first = true;
780
+ break;
781
+ }
782
+ }
783
+ if (lastNode) for (let i = words.length - 1; i >= 0; i--) {
784
+ const w = words[i];
785
+ if (!w.punctuation) {
786
+ w.last = true;
787
+ break;
788
+ }
789
+ }
790
+ return words;
791
+ }
792
+ /**
793
+ * Convert a single word based on case style and context
794
+ */
795
+ function convertWord({ word, first, last }, caseStyle, minorWords) {
796
+ if (caseStyle === "Title Case") {
797
+ if (first || last) return {
798
+ word: word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(),
799
+ isMinorWord: false
800
+ };
801
+ if (minorWords.some((minorWord) => minorWord.toLowerCase() === word.toLowerCase())) return {
802
+ word: word.toLowerCase(),
803
+ isMinorWord: true
804
+ };
805
+ return {
806
+ word: word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(),
807
+ isMinorWord: false
808
+ };
809
+ }
810
+ if (first) return {
811
+ word: word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(),
812
+ isMinorWord: false
813
+ };
814
+ return {
815
+ word: word.toLowerCase(),
816
+ isMinorWord: false
817
+ };
818
+ }
819
+ var heading_casing_default = createRule("heading-casing", {
820
+ meta: {
821
+ type: "suggestion",
822
+ docs: {
823
+ description: "enforce consistent casing in headings.",
824
+ categories: [],
825
+ listCategory: "Stylistic"
826
+ },
827
+ fixable: "code",
828
+ hasSuggestions: false,
829
+ schema: [{
830
+ type: "object",
831
+ properties: {
832
+ style: { enum: ["Title Case", "Sentence case"] },
833
+ preserveWords: {
834
+ type: "array",
835
+ items: { type: "string" },
836
+ description: "Words that should be preserved as-is (case-insensitive matching)"
837
+ },
838
+ ignorePatterns: {
839
+ type: "array",
840
+ items: { type: "string" },
841
+ description: "Regular expression patterns for words to ignore during casing checks"
842
+ },
843
+ minorWords: {
844
+ type: "array",
845
+ items: { type: "string" },
846
+ description: "Words that should not be capitalized in Title Case (unless they're the first or last word)"
847
+ }
848
+ },
849
+ additionalProperties: false
850
+ }],
851
+ messages: {
852
+ expectedTitleCase: "Expected \"{{actual}}\" to be \"{{expected}}\" (Title Case).",
853
+ expectedTitleCaseMinorWord: "Expected \"{{actual}}\" to be \"{{expected}}\" (Title Case - minor word).",
854
+ expectedSentenceCase: "Expected \"{{actual}}\" to be \"{{expected}}\" (Sentence case).",
855
+ expectedPreserveWord: "Expected \"{{actual}}\" to be \"{{expected}}\" (preserved word)."
856
+ }
857
+ },
858
+ create(context) {
859
+ const sourceCode = context.sourceCode;
860
+ const caseStyle = context.options[0]?.style || "Title Case";
861
+ const { preserveWords, preservePhrases } = parsePreserveWords(context.options[0]?.preserveWords || defaultPreserveWords);
862
+ const minorWords = context.options[0]?.minorWords || defaultMinorWords;
863
+ const ignorePatterns = (context.options[0]?.ignorePatterns || [
864
+ "/^v\\d+/u",
865
+ "/\\w+\\.[a-z\\d]+$/u",
866
+ "/\\w*(?:API|Api)$/u",
867
+ "/\\w*(?:SDK|Sdk)$/u",
868
+ "/\\w*(?:CLI|Cli)$/u"
869
+ ]).map((pattern) => {
870
+ if (isRegExp(pattern)) return toRegExp(pattern);
871
+ try {
872
+ return new RegExp(pattern, "v");
873
+ } catch {}
874
+ try {
875
+ return new RegExp(pattern, "u");
876
+ } catch {}
877
+ return new RegExp(pattern);
878
+ });
879
+ /**
880
+ * Check text node and report word-level errors
881
+ */
882
+ function checkTextNode(node, firstNode, lastNode) {
883
+ const text = sourceCode.getText(node);
884
+ const wordAndOffsets = parseText(text, firstNode, lastNode);
885
+ const processed = /* @__PURE__ */ new Set();
886
+ for (let index = 0; index < wordAndOffsets.length; index++) {
887
+ if (processed.has(index)) continue;
888
+ processed.add(index);
889
+ const wordAndOffset = wordAndOffsets[index];
890
+ if (wordAndOffset.punctuation) continue;
891
+ if (ignorePatterns.some((pattern) => pattern.test(wordAndOffset.word))) continue;
892
+ const preservePhrase = findPreservePhrase(wordAndOffsets, index);
893
+ if (preservePhrase) {
894
+ for (let wordIndex = 0; wordIndex < preservePhrase.length; wordIndex++) {
895
+ processed.add(index + wordIndex);
896
+ verifyWord(wordAndOffsets[index + wordIndex], preservePhrase[wordIndex], "preserved");
897
+ }
898
+ continue;
899
+ }
900
+ const preserveWordList = preserveWords.get(wordAndOffset.word.toLowerCase());
901
+ if (preserveWordList) {
902
+ if (!preserveWordList.some((w) => w === wordAndOffset.word)) verifyWord(wordAndOffset, preserveWordList[0], "preserved");
903
+ continue;
904
+ }
905
+ const expectedWordResult = convertWord(wordAndOffset, caseStyle, minorWords);
906
+ verifyWord(wordAndOffset, expectedWordResult.word, expectedWordResult.isMinorWord ? "minor" : "normal");
907
+ }
908
+ /**
909
+ * Verify a single word against the expected casing
910
+ */
911
+ function verifyWord(wordAndOffset, expectedWord, wordType = "normal") {
912
+ const { word, offset } = wordAndOffset;
913
+ if (word === expectedWord) return;
914
+ const nodeLoc = sourceCode.getLoc(node);
915
+ const beforeLines = text.slice(0, offset).split(/\n/u);
916
+ const line = nodeLoc.start.line + beforeLines.length - 1;
917
+ const column = (beforeLines.length === 1 ? nodeLoc.start.column : 1) + (beforeLines.at(-1) || "").length;
918
+ const nodeRange = sourceCode.getRange(node);
919
+ const wordRange = [nodeRange[0] + offset, nodeRange[0] + offset + word.length];
920
+ context.report({
921
+ node,
922
+ messageId: wordType === "preserved" ? "expectedPreserveWord" : caseStyle === "Title Case" ? wordType === "minor" ? "expectedTitleCaseMinorWord" : "expectedTitleCase" : "expectedSentenceCase",
923
+ data: {
924
+ actual: word,
925
+ expected: expectedWord
926
+ },
927
+ loc: {
928
+ start: {
929
+ line,
930
+ column
931
+ },
932
+ end: {
933
+ line,
934
+ column: column + word.length
935
+ }
936
+ },
937
+ fix(fixer) {
938
+ return fixer.replaceTextRange(wordRange, expectedWord);
939
+ }
940
+ });
941
+ }
942
+ }
943
+ /**
944
+ * Find a preserve phrase starting from the given index
945
+ * Returns the longest matching phrase or null if no match is found
946
+ */
947
+ function findPreservePhrase(wordAndOffsets, index) {
948
+ const firstWord = wordAndOffsets[index];
949
+ if (firstWord.punctuation) return null;
950
+ const firstLowerWord = firstWord.word.toLowerCase();
951
+ let returnCandidate = null;
952
+ let subWords = null;
953
+ for (const phrase of preservePhrases) {
954
+ if (returnCandidate && returnCandidate.preservePhrase.length !== phrase.length) break;
955
+ if (firstLowerWord !== phrase[0].toLowerCase()) continue;
956
+ if (!subWords || subWords.length !== phrase.length) subWords = wordAndOffsets.slice(index, index + phrase.length).map((wo) => wo.word);
957
+ if (subWords.length === phrase.length && subWords.every((word, i) => word.toLowerCase() === phrase[i].toLowerCase())) {
958
+ let matchCount = 0;
959
+ for (let i = 0; i < subWords.length; i++) {
960
+ const word = subWords[i];
961
+ if (word === phrase[i]) matchCount++;
962
+ }
963
+ if (!returnCandidate || matchCount > returnCandidate.matchCount) returnCandidate = {
964
+ preservePhrase: phrase,
965
+ matchCount
966
+ };
967
+ }
968
+ }
969
+ return returnCandidate?.preservePhrase ?? null;
970
+ }
971
+ return { heading(node) {
972
+ if (!node.children.length) return;
973
+ const children = node.children.filter((child) => child.type !== "text" || child.value.trim());
974
+ children.forEach((child, i) => {
975
+ if (child.type === "text") checkTextNode(child, i === 0, i === node.children.length - 1);
976
+ });
977
+ } };
978
+ }
979
+ });
980
+
981
+ //#endregion
982
+ //#region src/utils/lines.ts
983
+ const cache = /* @__PURE__ */ new WeakMap();
984
+ var ParsedLines = class {
985
+ lines;
986
+ constructor(codeText) {
987
+ let offset = 0;
988
+ this.lines = codeText.split(/(?<=\n)/u).map((lineText, index) => {
989
+ const start = offset;
990
+ offset += lineText.length;
991
+ const range = [start, offset];
992
+ let text = lineText;
993
+ let linebreak = "";
994
+ if (text.at(-1) === "\n") {
995
+ text = text.slice(0, -1);
996
+ linebreak = "\n";
997
+ }
998
+ if (text.at(-1) === "\r") {
999
+ text = text.slice(0, -1);
1000
+ linebreak = `\r${linebreak}`;
1001
+ }
1002
+ return {
1003
+ text,
1004
+ range,
1005
+ line: index + 1,
1006
+ linebreak
1007
+ };
1008
+ });
1009
+ }
1010
+ [Symbol.iterator]() {
1011
+ return this.lines[Symbol.iterator]();
1012
+ }
1013
+ get length() {
1014
+ return this.lines.length;
1015
+ }
1016
+ get(lineNumber) {
1017
+ return this.lines[lineNumber - 1];
1018
+ }
1019
+ };
1020
+ /**
1021
+ * Parse the lines of the source code.
1022
+ * @param sourceCode source code to parse
1023
+ * @returns parsed lines
1024
+ */
1025
+ function parseLines(sourceCode) {
1026
+ const cached = cache.get(sourceCode);
1027
+ if (cached) return cached;
1028
+ const parsedLines = new ParsedLines(sourceCode.text);
1029
+ cache.set(sourceCode, parsedLines);
1030
+ return parsedLines;
1031
+ }
1032
+
1033
+ //#endregion
1034
+ //#region src/rules/no-laziness-blockquotes.ts
1035
+ /**
1036
+ * Helper function to get blockquote line information.
1037
+ */
1038
+ function getBlockquoteLineInfo(line) {
1039
+ const regex = /^\s*(?:>\s*)*/u;
1040
+ const match = regex.exec(line.text);
1041
+ return {
1042
+ line,
1043
+ prefix: match[0],
1044
+ level: (match[0].match(/>/gu) || []).length
1045
+ };
1046
+ }
1047
+ var no_laziness_blockquotes_default = createRule("no-laziness-blockquotes", {
1048
+ meta: {
1049
+ type: "problem",
1050
+ docs: {
1051
+ description: "disallow laziness in blockquotes",
1052
+ categories: ["recommended"],
1053
+ listCategory: "Stylistic"
1054
+ },
1055
+ fixable: void 0,
1056
+ hasSuggestions: true,
1057
+ schema: [],
1058
+ messages: {
1059
+ lazyBlockquoteLine: "Expected {{level}} '>' marker(s), but found {{actualLevel}}. This line will be interpreted as part of level {{level}} blockquote.",
1060
+ addMarker: "Add {{missingMarkers}} '>' marker(s).",
1061
+ addLineBreak: "Add line break to separate from blockquote."
1062
+ }
1063
+ },
1064
+ create(context) {
1065
+ const sourceCode = context.sourceCode;
1066
+ const checkedLines = /* @__PURE__ */ new Set();
1067
+ const lines = parseLines(sourceCode);
1068
+ /**
1069
+ * Report invalid blockquote lines.
1070
+ */
1071
+ function reportInvalidLines(invalidLines, base) {
1072
+ const invalidGroups = [];
1073
+ for (const invalidLine of invalidLines) {
1074
+ const currentGroup = invalidGroups.at(-1);
1075
+ if (!currentGroup || currentGroup.level < invalidLine.level) {
1076
+ invalidGroups.push({
1077
+ level: invalidLine.level,
1078
+ lines: [invalidLine]
1079
+ });
1080
+ continue;
1081
+ }
1082
+ if (currentGroup.level === invalidLine.level) {
1083
+ currentGroup.lines.push(invalidLine);
1084
+ continue;
1085
+ }
1086
+ if (invalidLine.level < currentGroup.level) break;
1087
+ }
1088
+ for (const group of invalidGroups) {
1089
+ const first = group.lines[0];
1090
+ const last = group.lines.at(-1);
1091
+ context.report({
1092
+ loc: {
1093
+ start: {
1094
+ line: first.line.line,
1095
+ column: 1
1096
+ },
1097
+ end: {
1098
+ line: last.line.line,
1099
+ column: last.line.text.length + 1
1100
+ }
1101
+ },
1102
+ messageId: "lazyBlockquoteLine",
1103
+ data: {
1104
+ level: `${base.level}`,
1105
+ actualLevel: `${group.level}`
1106
+ },
1107
+ suggest: [{
1108
+ messageId: "addMarker",
1109
+ data: { missingMarkers: `${base.level - group.level}` },
1110
+ *fix(fixer) {
1111
+ for (const invalidLine of group.lines) yield fixer.replaceTextRange([invalidLine.line.range[0], invalidLine.line.range[0] + invalidLine.prefix.length], base.prefix);
1112
+ }
1113
+ }, {
1114
+ messageId: "addLineBreak",
1115
+ fix: (fixer) => {
1116
+ return fixer.insertTextBeforeRange([first.line.range[0], first.line.range[0]], `${first.prefix.trimEnd()}\n`);
1117
+ }
1118
+ }]
1119
+ });
1120
+ }
1121
+ }
1122
+ return { "blockquote:exit"(node) {
1123
+ const loc = sourceCode.getLoc(node);
1124
+ const startLine = loc.start.line;
1125
+ const endLine = loc.end.line;
1126
+ const base = getBlockquoteLineInfo(lines.get(startLine));
1127
+ const invalidLines = [];
1128
+ for (let lineNumber = startLine + 1; lineNumber <= endLine; lineNumber++) {
1129
+ if (checkedLines.has(lineNumber)) {
1130
+ reportInvalidLines(invalidLines, base);
1131
+ invalidLines.length = 0;
1132
+ continue;
1133
+ }
1134
+ checkedLines.add(lineNumber);
1135
+ const line = lines.get(lineNumber);
1136
+ const current = getBlockquoteLineInfo(line);
1137
+ if (base.level <= current.level) {
1138
+ reportInvalidLines(invalidLines, base);
1139
+ invalidLines.length = 0;
1140
+ continue;
1141
+ }
1142
+ invalidLines.push(current);
1143
+ }
1144
+ reportInvalidLines(invalidLines, base);
1145
+ } };
1146
+ }
1147
+ });
1148
+
1149
+ //#endregion
1150
+ //#region src/rules/no-multiple-empty-lines.ts
1151
+ var no_multiple_empty_lines_default = createRule("no-multiple-empty-lines", {
1152
+ meta: {
1153
+ type: "layout",
1154
+ docs: {
1155
+ description: "disallow multiple empty lines in Markdown files.",
1156
+ categories: null,
1157
+ listCategory: "Stylistic"
1158
+ },
1159
+ fixable: "whitespace",
1160
+ hasSuggestions: false,
1161
+ schema: [{
1162
+ type: "object",
1163
+ properties: {
1164
+ max: {
1165
+ type: "integer",
1166
+ minimum: 0,
1167
+ default: 1
1168
+ },
1169
+ maxEOF: {
1170
+ type: "integer",
1171
+ minimum: 0,
1172
+ default: 0
1173
+ },
1174
+ maxBOF: {
1175
+ type: "integer",
1176
+ minimum: 0,
1177
+ default: 0
1178
+ }
1179
+ },
1180
+ additionalProperties: false
1181
+ }],
1182
+ messages: {
1183
+ blankBeginningOfFile: "Too many blank lines at the beginning of file. Max of {{max}} allowed.",
1184
+ blankEndOfFile: "Too many blank lines at the end of file. Max of {{max}} allowed.",
1185
+ consecutiveBlank: "More than {{max}} blank {{pluralizedLines}} not allowed."
1186
+ }
1187
+ },
1188
+ create(context) {
1189
+ const sourceCode = context.sourceCode;
1190
+ const option = context.options[0] || {};
1191
+ const max = typeof option.max === "number" ? option.max : 1;
1192
+ const maxEOF = typeof option.maxEOF === "number" ? option.maxEOF : 0;
1193
+ const maxBOF = typeof option.maxBOF === "number" ? option.maxBOF : 0;
1194
+ const ignoreLocs = [];
1195
+ /**
1196
+ * Register the range of nodes to ignore (code, html, yaml, toml, json)
1197
+ * @param node mdast node
1198
+ */
1199
+ function addIgnoreLoc(node) {
1200
+ const loc = sourceCode.getLoc(node);
1201
+ ignoreLocs.push({
1202
+ startLine: loc.start.line,
1203
+ endLine: loc.end.line
1204
+ });
1205
+ }
1206
+ return {
1207
+ code: addIgnoreLoc,
1208
+ html: addIgnoreLoc,
1209
+ yaml: addIgnoreLoc,
1210
+ toml: addIgnoreLoc,
1211
+ json: addIgnoreLoc,
1212
+ "root:exit"() {
1213
+ const lines = [...parseLines(sourceCode)];
1214
+ const bofEmptyLines = [];
1215
+ while (lines.length) {
1216
+ if (lines[0].text.trim()) break;
1217
+ bofEmptyLines.push(lines.shift());
1218
+ }
1219
+ const invalidBOFEmptyLines = bofEmptyLines.slice(maxBOF);
1220
+ if (invalidBOFEmptyLines.length > 0) {
1221
+ const first = invalidBOFEmptyLines[0];
1222
+ const last = invalidBOFEmptyLines[invalidBOFEmptyLines.length - 1];
1223
+ context.report({
1224
+ loc: {
1225
+ start: {
1226
+ line: first.line,
1227
+ column: 1
1228
+ },
1229
+ end: {
1230
+ line: last.line,
1231
+ column: last.text.length + 1
1232
+ }
1233
+ },
1234
+ messageId: "blankBeginningOfFile",
1235
+ data: { max: maxBOF },
1236
+ fix(fixer) {
1237
+ return fixer.removeRange([first.range[0], last.range[1]]);
1238
+ }
1239
+ });
1240
+ }
1241
+ const eofEmptyLines = [];
1242
+ while (lines.length) {
1243
+ if (lines[lines.length - 1].text.trim()) break;
1244
+ eofEmptyLines.unshift(lines.pop());
1245
+ }
1246
+ const invalidEOFEmptyLines = eofEmptyLines.slice(maxEOF);
1247
+ if (invalidEOFEmptyLines.length > 0) {
1248
+ const first = invalidEOFEmptyLines[0];
1249
+ const last = invalidEOFEmptyLines[invalidEOFEmptyLines.length - 1];
1250
+ context.report({
1251
+ loc: {
1252
+ start: {
1253
+ line: first.line,
1254
+ column: 1
1255
+ },
1256
+ end: {
1257
+ line: last.line,
1258
+ column: last.text.length + 1
1259
+ }
1260
+ },
1261
+ messageId: "blankEndOfFile",
1262
+ data: { max: maxEOF },
1263
+ fix(fixer) {
1264
+ return fixer.removeRange([first.range[0], last.range[1]]);
1265
+ }
1266
+ });
1267
+ }
1268
+ const emptyLines = [];
1269
+ for (const lineInfo of lines) {
1270
+ if (!lineInfo.text.trim() && !ignoreLocs.some(({ startLine, endLine }) => {
1271
+ return lineInfo.line > startLine && lineInfo.line < endLine;
1272
+ })) {
1273
+ emptyLines.push(lineInfo);
1274
+ continue;
1275
+ }
1276
+ const invalidEmptyLines = emptyLines.slice(max);
1277
+ emptyLines.length = 0;
1278
+ if (invalidEmptyLines.length) {
1279
+ const first = invalidEmptyLines[0];
1280
+ const last = invalidEmptyLines[invalidEmptyLines.length - 1];
1281
+ context.report({
1282
+ loc: {
1283
+ start: {
1284
+ line: first.line,
1285
+ column: 1
1286
+ },
1287
+ end: {
1288
+ line: last.line,
1289
+ column: last.text.length + 1
1290
+ }
1291
+ },
1292
+ messageId: "consecutiveBlank",
1293
+ data: {
1294
+ max,
1295
+ pluralizedLines: max === 1 ? "line" : "lines"
1296
+ },
1297
+ fix(fixer) {
1298
+ return fixer.removeRange([first.range[0], last.range[1]]);
1299
+ }
1300
+ });
1301
+ }
1302
+ }
1303
+ }
1304
+ };
1305
+ }
1306
+ });
1307
+
114
1308
  //#endregion
115
1309
  //#region src/rules/no-text-backslash-linebreak.ts
116
1310
  var no_text_backslash_linebreak_default = createRule("no-text-backslash-linebreak", {
@@ -242,45 +1436,28 @@ var no_trailing_spaces_default = createRule("no-trailing-spaces", {
242
1436
  "root:exit"() {
243
1437
  const re = /[^\S\n\r]+$/u;
244
1438
  const skipMatch = /^[^\S\n\r]*$/u;
245
- const lines = sourceCode.lines;
246
- const linebreaks = sourceCode.text.match(/\r?\n/gu);
1439
+ const lines = parseLines(sourceCode);
247
1440
  const commentLineNumbers = getCommentLineNumbers();
248
- let totalLength = 0;
249
- for (let i = 0, ii = lines.length; i < ii; i++) {
250
- const lineNumber = i + 1;
251
- const linebreakLength = linebreaks && linebreaks[i] ? linebreaks[i].length : 1;
252
- const lineLength = lines[i].length + linebreakLength;
253
- const matches = re.exec(lines[i]);
254
- if (!matches) {
255
- totalLength += lineLength;
256
- continue;
257
- }
1441
+ for (const lineInfo of lines) {
1442
+ const matches = re.exec(lineInfo.text);
1443
+ if (!matches) continue;
258
1444
  const location = {
259
1445
  start: {
260
- line: lineNumber,
1446
+ line: lineInfo.line,
261
1447
  column: matches.index + 1
262
1448
  },
263
1449
  end: {
264
- line: lineNumber,
265
- column: lineLength + 1 - linebreakLength
1450
+ line: lineInfo.line,
1451
+ column: matches.index + 1 + matches[0].length
266
1452
  }
267
1453
  };
268
- const rangeStart = totalLength + location.start.column - 1;
269
- const rangeEnd = totalLength + location.end.column - 1;
1454
+ const range = [lineInfo.range[0] + location.start.column - 1, lineInfo.range[0] + location.end.column - 1];
270
1455
  if (ignoreNodes.some((node) => {
271
- const range = sourceCode.getRange(node);
272
- return range[0] <= rangeStart && rangeEnd <= range[1];
273
- })) {
274
- totalLength += lineLength;
275
- continue;
276
- }
277
- if (skipBlankLines && skipMatch.test(lines[i])) {
278
- totalLength += lineLength;
279
- continue;
280
- }
281
- const fixRange = [rangeStart, rangeEnd];
282
- if (!ignoreComments || !commentLineNumbers.has(lineNumber)) report(location, fixRange);
283
- totalLength += lineLength;
1456
+ const nodeRange = sourceCode.getRange(node);
1457
+ return nodeRange[0] <= range[0] && range[1] <= nodeRange[1];
1458
+ })) continue;
1459
+ if (skipBlankLines && skipMatch.test(lineInfo.text)) continue;
1460
+ if (!ignoreComments || !commentLineNumbers.has(lineInfo.line)) report(location, range);
284
1461
  }
285
1462
  }
286
1463
  };
@@ -621,25 +1798,6 @@ var prefer_link_reference_definitions_default = createRule("prefer-link-referenc
621
1798
  }
622
1799
  });
623
1800
 
624
- //#endregion
625
- //#region src/utils/url.ts
626
- /**
627
- * Utility function to check if a string is a valid URL.
628
- */
629
- function isValidURL(url) {
630
- return Boolean(createURLSafe(url));
631
- }
632
- /**
633
- * Utility function to create a URL object safely.
634
- */
635
- function createURLSafe(url) {
636
- try {
637
- return new URL(url);
638
- } catch {
639
- return null;
640
- }
641
- }
642
-
643
1801
  //#endregion
644
1802
  //#region src/rules/prefer-linked-words.ts
645
1803
  var prefer_linked_words_default = createRule("prefer-linked-words", {
@@ -741,7 +1899,7 @@ var prefer_linked_words_default = createRule("prefer-linked-words", {
741
1899
  * Adjust link to be relative to the file.
742
1900
  */
743
1901
  function adjustLink(link) {
744
- if (isValidURL(link)) return link;
1902
+ if (URL.canParse(link)) return link;
745
1903
  if (link.startsWith("#")) return link;
746
1904
  const absoluteLink = path.isAbsolute(link) || path.posix.isAbsolute(link) ? link : path.join(context.cwd, link);
747
1905
  return `./${path.relative(path.dirname(context.filename), absoluteLink)}`;
@@ -749,31 +1907,6 @@ var prefer_linked_words_default = createRule("prefer-linked-words", {
749
1907
  }
750
1908
  });
751
1909
 
752
- //#endregion
753
- //#region src/utils/regexp.ts
754
- const RE_REGEXP_STR = /^\/(.+)\/([A-Za-z]*)$/u;
755
- /**
756
- * Convert a string to the `RegExp`.
757
- * Normal strings (e.g. `"foo"`) is converted to `/^foo$/` of `RegExp`.
758
- * Strings like `"/^foo/i"` are converted to `/^foo/i` of `RegExp`.
759
- *
760
- * @param {string} string The string to convert.
761
- * @returns {RegExp} Returns the `RegExp`.
762
- */
763
- function toRegExp(string) {
764
- const parts = RE_REGEXP_STR.exec(string);
765
- if (parts) return new RegExp(parts[1], parts[2]);
766
- return { test: (s) => s === string };
767
- }
768
- /**
769
- * Checks whether given string is regexp string
770
- * @param {string} string
771
- * @returns {boolean}
772
- */
773
- function isRegExp(string) {
774
- return Boolean(RE_REGEXP_STR.test(string));
775
- }
776
-
777
1910
  //#endregion
778
1911
  //#region src/rules/sort-definitions.ts
779
1912
  var sort_definitions_default = createRule("sort-definitions", {
@@ -947,14 +2080,14 @@ var sort_definitions_default = createRule("sort-definitions", {
947
2080
  }
948
2081
  /** Compile order option */
949
2082
  function compileOption(orderOption) {
950
- const cache = /* @__PURE__ */ new Map();
2083
+ const cache$1 = /* @__PURE__ */ new Map();
951
2084
  const compiled = compileOptionWithoutCache(orderOption);
952
2085
  return {
953
2086
  match: (node) => {
954
- const cached = cache.get(node);
2087
+ const cached = cache$1.get(node);
955
2088
  if (cached != null) return cached;
956
2089
  const result = compiled.match(node);
957
- cache.set(node, result);
2090
+ cache$1.set(node, result);
958
2091
  return result;
959
2092
  },
960
2093
  sort: compiled.sort
@@ -1005,7 +2138,7 @@ var sort_definitions_default = createRule("sort-definitions", {
1005
2138
  if (node.label === patternStr || node.identifier === patternStr) return true;
1006
2139
  if (node.type === "definition") {
1007
2140
  if (node.url === patternStr) return true;
1008
- if (isValidURL(patternStr)) {
2141
+ if (URL.canParse(patternStr) && URL.canParse(node.url)) {
1009
2142
  const normalizedPattern = normalizedURL(patternStr);
1010
2143
  const normalizedUrl = normalizedURL(node.url);
1011
2144
  if (normalizedUrl.startsWith(normalizedPattern)) return true;
@@ -1052,7 +2185,7 @@ function getQuote(text) {
1052
2185
  * Normalize a URL by ensuring it ends with a slash.
1053
2186
  */
1054
2187
  function normalizedURL(url) {
1055
- const urlObj = createURLSafe(url);
2188
+ const urlObj = new URL(url);
1056
2189
  if (!urlObj) return url;
1057
2190
  return urlObj.href.endsWith("/") ? urlObj.href : `${urlObj.href}/`;
1058
2191
  }
@@ -1060,8 +2193,12 @@ function normalizedURL(url) {
1060
2193
  //#endregion
1061
2194
  //#region src/utils/rules.ts
1062
2195
  const rules$1 = [
2196
+ canonical_code_block_language_default,
1063
2197
  definitions_last_default,
1064
2198
  hard_linebreak_style_default,
2199
+ heading_casing_default,
2200
+ no_laziness_blockquotes_default,
2201
+ no_multiple_empty_lines_default,
1065
2202
  no_text_backslash_linebreak_default,
1066
2203
  no_trailing_spaces_default,
1067
2204
  prefer_inline_code_words_default,
@@ -1091,6 +2228,7 @@ const plugins = {
1091
2228
  };
1092
2229
  const rules$2 = {
1093
2230
  "markdown-preferences/hard-linebreak-style": "error",
2231
+ "markdown-preferences/no-laziness-blockquotes": "error",
1094
2232
  "markdown-preferences/no-text-backslash-linebreak": "error"
1095
2233
  };
1096
2234
 
@@ -1102,7 +2240,7 @@ __export(meta_exports, {
1102
2240
  version: () => version
1103
2241
  });
1104
2242
  const name = "eslint-plugin-markdown-preferences";
1105
- const version = "0.8.0";
2243
+ const version = "0.10.0";
1106
2244
 
1107
2245
  //#endregion
1108
2246
  //#region src/index.ts
@@ -1111,11 +2249,16 @@ const rules = rules$1.reduce((obj, r) => {
1111
2249
  obj[r.meta.docs.ruleName] = r;
1112
2250
  return obj;
1113
2251
  }, {});
2252
+ const resources = {
2253
+ defaultPreserveWords,
2254
+ defaultMinorWords
2255
+ };
1114
2256
  var src_default = {
1115
2257
  meta: meta_exports,
1116
2258
  configs,
1117
- rules
2259
+ rules,
2260
+ resources
1118
2261
  };
1119
2262
 
1120
2263
  //#endregion
1121
- export { configs, src_default as default, meta_exports as meta, rules };
2264
+ export { configs, src_default as default, meta_exports as meta, resources, rules };