88//-----------------------------------------------------------------------------
99
1010import { normalizeIdentifier } from "micromark-util-normalize-identifier" ;
11- import { findOffsets } from "../util.js" ;
1211
1312//-----------------------------------------------------------------------------
1413// Type Definitions
1514//-----------------------------------------------------------------------------
1615
1716/**
18- * @import { SourceRange } from "@eslint/core"
19- * @import { Heading, Paragraph, TableCell } from "mdast";
17+ * @import { Image, Link } from "mdast";
2018 * @import { MarkdownRuleDefinition } from "../types.js";
21- * @typedef {"referenceLikeUrl" } NoReferenceLikeUrlMessageIds
22- * @typedef {[] } NoReferenceLikeUrlOptions
23- * @typedef {MarkdownRuleDefinition<{ RuleOptions: NoReferenceLikeUrlOptions , MessageIds: NoReferenceLikeUrlMessageIds }> } NoReferenceLikeUrlRuleDefinition
19+ * @typedef {"referenceLikeUrl" } NoReferenceLikeUrlsMessageIds
20+ * @typedef {[] } NoReferenceLikeUrlsOptions
21+ * @typedef {MarkdownRuleDefinition<{ RuleOptions: NoReferenceLikeUrlsOptions , MessageIds: NoReferenceLikeUrlsMessageIds }> } NoReferenceLikeUrlsRuleDefinition
2422 */
2523
2624//-----------------------------------------------------------------------------
@@ -29,23 +27,13 @@ import { findOffsets } from "../util.js";
2927
3028/** Pattern to match both inline links: `[text](url)` and images: ``, with optional title */
3129const linkOrImagePattern =
32- / (?< = (?< ! \\ ) (?: \\ { 2 } ) * ) (?< imageBang > ! ) ? \[ (?< label > (?: \\ .| [ ^ ( ) \\ ] | \( [ \s \S ] * \) ) * ?) \] \( (?< destination > [ \t ] * (?: \r \n ? | \n ) ? (?< ! [ \t ] ) [ \t ] * (?: < [ ^ > ] * > | [ ^ \t ( ) ] + ) ) (?: [ \t ] * (?: \r \n ? | \n ) ? (?< ! [ \t ] ) [ \t ] * (?< title > " [ ^ " ] * " | ' [ ^ ' ] * ' | \( [ ^ ) ] * \) ) ) ? [ \t ] * (?: \r \n ? | \n ) ? (?< ! [ \t ] ) [ \t ] * \) (? ! \( ) / gu;
33-
34- /**
35- * Checks if a given index is within any skip range.
36- * @param {number } index The index to check
37- * @param {Array<SourceRange> } skipRanges The skip ranges
38- * @returns {boolean } True if index is in a skip range
39- */
40- function isInSkipRange ( index , skipRanges ) {
41- return skipRanges . some ( range => range [ 0 ] <= index && index < range [ 1 ] ) ;
42- }
30+ / (?< imageBang > ! ) ? \[ (?< label > (?: \\ .| [ ^ ( ) \\ ] | \( [ \s \S ] * \) ) * ?) \] \( (?< destination > [ \t ] * (?: \r \n ? | \n ) ? (?< ! [ \t ] ) [ \t ] * (?: < [ ^ > ] * > | [ ^ \t ( ) ] + ) ) (?: [ \t ] * (?: \r \n ? | \n ) ? (?< ! [ \t ] ) [ \t ] * (?< title > " [ ^ " ] * " | ' [ ^ ' ] * ' | \( [ ^ ) ] * \) ) ) ? [ \t ] * (?: \r \n ? | \n ) ? (?< ! [ \t ] ) [ \t ] * \) $ / u;
4331
4432//-----------------------------------------------------------------------------
4533// Rule Definition
4634//-----------------------------------------------------------------------------
4735
48- /** @type {NoReferenceLikeUrlRuleDefinition } */
36+ /** @type {NoReferenceLikeUrlsRuleDefinition } */
4937export default {
5038 meta : {
5139 type : "problem" ,
@@ -67,66 +55,33 @@ export default {
6755
6856 create ( context ) {
6957 const { sourceCode } = context ;
70- /** @type {Array<SourceRange> } */
71- const skipRanges = [ ] ;
7258 /** @type {Set<string> } */
7359 const definitionIdentifiers = new Set ( ) ;
74- /** @type {Array<Heading | Paragraph | TableCell > } */
60+ /** @type {Array<Image | Link > } */
7561 const relevantNodes = [ ] ;
7662
7763 return {
7864 definition ( node ) {
7965 definitionIdentifiers . add ( node . identifier ) ;
8066 } ,
8167
82- heading ( node ) {
83- relevantNodes . push ( node ) ;
84- } ,
85-
86- "heading :matches(html, inlineCode)" ( node ) {
87- skipRanges . push ( sourceCode . getRange ( node ) ) ;
88- } ,
89-
90- paragraph ( node ) {
68+ "image, link" ( /** @type {Image | Link } */ node ) {
9169 relevantNodes . push ( node ) ;
9270 } ,
9371
94- "paragraph :matches(html, inlineCode)" ( node ) {
95- skipRanges . push ( sourceCode . getRange ( node ) ) ;
96- } ,
97-
98- tableCell ( node ) {
99- relevantNodes . push ( node ) ;
100- } ,
101-
102- "tableCell :matches(html, inlineCode)" ( node ) {
103- skipRanges . push ( sourceCode . getRange ( node ) ) ;
104- } ,
105-
10672 "root:exit" ( ) {
10773 for ( const node of relevantNodes ) {
10874 const text = sourceCode . getText ( node ) ;
10975
110- let match ;
111- while ( ( match = linkOrImagePattern . exec ( text ) ) !== null ) {
76+ const match = linkOrImagePattern . exec ( text ) ;
77+ if ( match !== null ) {
11278 const {
11379 imageBang,
11480 label,
11581 destination,
11682 title : titleRaw ,
11783 } = match . groups ;
11884 const title = titleRaw ?. slice ( 1 , - 1 ) ;
119- const matchIndex = match . index ;
120- const matchLength = match [ 0 ] . length ;
121-
122- if (
123- isInSkipRange (
124- matchIndex + node . position . start . offset ,
125- skipRanges ,
126- )
127- ) {
128- continue ;
129- }
13085
13186 const isImage = ! ! imageBang ;
13287 const type = isImage ? "image" : "link" ;
@@ -135,37 +90,8 @@ export default {
13590 normalizeIdentifier ( destination ) . toLowerCase ( ) ;
13691
13792 if ( definitionIdentifiers . has ( url ) ) {
138- const {
139- lineOffset : startLineOffset ,
140- columnOffset : startColumnOffset ,
141- } = findOffsets ( text , matchIndex ) ;
142- const {
143- lineOffset : endLineOffset ,
144- columnOffset : endColumnOffset ,
145- } = findOffsets ( text , matchIndex + matchLength ) ;
146-
147- const baseColumn = 1 ;
148- const nodeStartLine = node . position . start . line ;
149- const nodeStartColumn = node . position . start . column ;
150- const startLine = nodeStartLine + startLineOffset ;
151- const endLine = nodeStartLine + endLineOffset ;
152- const startColumn =
153- ( startLine === nodeStartLine
154- ? nodeStartColumn
155- : baseColumn ) + startColumnOffset ;
156- const endColumn =
157- ( endLine === nodeStartLine
158- ? nodeStartColumn
159- : baseColumn ) + endColumnOffset ;
160-
16193 context . report ( {
162- loc : {
163- start : {
164- line : startLine ,
165- column : startColumn ,
166- } ,
167- end : { line : endLine , column : endColumn } ,
168- } ,
94+ loc : node . position ,
16995 messageId : "referenceLikeUrl" ,
17096 data : {
17197 type,
@@ -177,12 +103,8 @@ export default {
177103 return null ;
178104 }
179105
180- const startOffset =
181- node . position . start . offset + matchIndex ;
182- const endOffset = startOffset + matchLength ;
183-
184- return fixer . replaceTextRange (
185- [ startOffset , endOffset ] ,
106+ return fixer . replaceText (
107+ node ,
186108 `${ prefix } [${ label } ][${ destination } ]` ,
187109 ) ;
188110 } ,
0 commit comments