From 71fe2b8abbbeaae9033808a1b02636e16dc31424 Mon Sep 17 00:00:00 2001 From: Allo Date: Sun, 5 Feb 2023 09:53:05 +0800 Subject: [PATCH 01/10] fix(build): match bad_src flaws for markdown files --- build/check-images.ts | 22 +++++----- build/flaws/broken-links.ts | 26 +++--------- build/matches-in-text.ts | 42 ++++++++++++++----- .../images/bad_src/{index.html => index.md} | 8 ++-- 4 files changed, 51 insertions(+), 47 deletions(-) rename testing/content/files/en-us/web/images/bad_src/{index.html => index.md} (71%) diff --git a/build/check-images.ts b/build/check-images.ts index 7e02fc1289a0..2fa5e7f6ac57 100644 --- a/build/check-images.ts +++ b/build/check-images.ts @@ -8,7 +8,7 @@ import sizeOf from "image-size"; import { Document, Image } from "../content"; import { FLAW_LEVELS } from "../libs/constants"; -import { findMatchesInText } from "./matches-in-text"; +import { findMatchesInText, findMatchesInMarkdown } from "./matches-in-text"; import { DEFAULT_LOCALE } from "../libs/constants"; /** @@ -23,6 +23,8 @@ export function checkImageReferences(doc, $, options, { url, rawContent }) { const checked = new Map(); + const isMarkdown = doc.isMarkdown; + function addImageFlaw( $img, src, @@ -32,11 +34,11 @@ export function checkImageReferences(doc, $, options, { url, rawContent }) { // (addImageFlaw) is called two times. We can then assume the // findMatchesInText() will find it two times too. For each call, // we need to match the call based in counting matches from findMatchesInText(). - const matches = [ - ...findMatchesInText(src, rawContent, { - attribute: "src", - }), - ]; + const matches = isMarkdown + ? findMatchesInMarkdown(rawContent, "image", src) + : findMatchesInText(src, rawContent, { + attribute: "src", + }); const checkedBefore = checked.get(src) || 0; matches.forEach((match, i) => { if (i !== checkedBefore) { @@ -243,11 +245,9 @@ export function checkImageWidths(doc, $, options, { rawContent }) { } const id = `image_widths${doc.flaws.image_widths.length + 1}`; $img.attr("data-flaw", id); - const matches = [ - ...findMatchesInText(style, rawContent, { - attribute: "style", - }), - ]; + const matches = findMatchesInText(style, rawContent, { + attribute: "style", + }); const checkedBefore = checked.get(style) || 0; matches.forEach((match, i) => { if (i !== checkedBefore) { diff --git a/build/flaws/broken-links.ts b/build/flaws/broken-links.ts index c7ed1cfa0d69..1168e6b949a8 100644 --- a/build/flaws/broken-links.ts +++ b/build/flaws/broken-links.ts @@ -1,11 +1,8 @@ import fs from "node:fs"; import path from "node:path"; -import fromMarkdown from "mdast-util-from-markdown"; -import visit from "unist-util-visit"; - import { Document, Redirect, Image } from "../../content"; -import { findMatchesInText } from "../matches-in-text"; +import { findMatchesInText, findMatchesInMarkdown } from "../matches-in-text"; import { DEFAULT_LOCALE, FLAW_LEVELS, @@ -15,17 +12,6 @@ import { isValidLocale } from "../../libs/locale-utils"; const dirname = __dirname; -function findMatchesInMarkdown(rawContent, href) { - const matches = []; - visit(fromMarkdown(rawContent), "link", (node: any) => { - if (node.url == href) { - const { line, column } = node.position.start; - matches.push({ line, column }); - } - }); - return matches; -} - const _safeToHttpsDomains = new Map(); function getSafeToHttpDomains() { if (!_safeToHttpsDomains.size) { @@ -120,12 +106,10 @@ export function getBrokenLinksFlaws(doc, $, { rawContent }, level) { href, doc.isMarkdown - ? findMatchesInMarkdown(rawContent, href) - : Array.from( - findMatchesInText(href, rawContent, { - attribute: "href", - }) - ) + ? findMatchesInMarkdown(rawContent, "link", href) + : findMatchesInText(href, rawContent, { + attribute: "href", + }) ); } // findMatchesInText() is a generator function so use `Array.from()` diff --git a/build/matches-in-text.ts b/build/matches-in-text.ts index 08a24c762ea8..cc72d1e65466 100644 --- a/build/matches-in-text.ts +++ b/build/matches-in-text.ts @@ -1,27 +1,47 @@ +import fromMarkdown from "mdast-util-from-markdown"; +import visit from "unist-util-visit"; + const ESCAPE_CHARS_RE = /[.*+?^${}()|[\]\\]/g; -export function* findMatchesInText( - needle, - haystack, +type Match = { line: number; column: number }; + +export function findMatchesInText( + needle: string, + haystack: string, { attribute = null } = {} ) { // Need to remove any characters that can affect a regex if we're going // use the string in a manually constructed regex. const escaped = needle.replace(ESCAPE_CHARS_RE, "\\$&"); - let rex; - if (attribute) { - rex = new RegExp(`${attribute}=['"](${escaped})['"]`, "g"); - } else { - rex = new RegExp(`(${escaped})`, "g"); - } + const rex = attribute + ? new RegExp(`${attribute}=['"](${escaped})['"]`, "g") + : new RegExp(`(${escaped})`, "g"); + const matches: Array = []; for (const match of haystack.matchAll(rex)) { const left = haystack.slice(0, match.index); const line = (left.match(/\n/g) || []).length + 1; const lastIndexOf = left.lastIndexOf("\n") + 1; const column = match.index - lastIndexOf + 1 + (attribute ? attribute.length + 2 : 0); - yield { line, column }; + matches.push({ line, column }); } + return matches; +} + +export function findMatchesInMarkdown( + rawContent: string, + type: string, + url: string +) { + const matches: Array = []; + const content = fromMarkdown(rawContent); + visit(content, type, (node: any) => { + if (node.url == url) { + const { line, column } = node.position.start; + matches.push({ line, column }); + } + }); + return matches; } export function getFirstMatchInText(needle, haystack) { @@ -29,7 +49,7 @@ export function getFirstMatchInText(needle, haystack) { const left = haystack.substring(0, index); const line = left.split("\n").length; const column = left.length - left.lastIndexOf("\n"); - return { line, column }; + return { line, column } as Match; } export function replaceMatchingLinksInMarkdown(needle, haystack, replacement) { diff --git a/testing/content/files/en-us/web/images/bad_src/index.html b/testing/content/files/en-us/web/images/bad_src/index.md similarity index 71% rename from testing/content/files/en-us/web/images/bad_src/index.html rename to testing/content/files/en-us/web/images/bad_src/index.md index 1ddedd9d6627..ccea887c7a9e 100644 --- a/testing/content/files/en-us/web/images/bad_src/index.html +++ b/testing/content/files/en-us/web/images/bad_src/index.md @@ -4,13 +4,13 @@ --- - +![](actuallynota.svg) - +![](/en-us/web) - +![](actuallynota.png) - +![](empty.gif) From efe765f5f808ab8bd73e617e4026ed38e75d39c7 Mon Sep 17 00:00:00 2001 From: Allo Date: Sun, 5 Feb 2023 10:18:39 +0800 Subject: [PATCH 02/10] strict the type checking --- build/matches-in-text.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/build/matches-in-text.ts b/build/matches-in-text.ts index cc72d1e65466..e45c1365eea7 100644 --- a/build/matches-in-text.ts +++ b/build/matches-in-text.ts @@ -30,13 +30,12 @@ export function findMatchesInText( export function findMatchesInMarkdown( rawContent: string, - type: string, + type: "link" | "image", url: string ) { const matches: Array = []; - const content = fromMarkdown(rawContent); - visit(content, type, (node: any) => { - if (node.url == url) { + visit(fromMarkdown(rawContent), type, (node: any) => { + if (node.url === url) { const { line, column } = node.position.start; matches.push({ line, column }); } From a3e55a5807acbdd28686fdfb54c4de551c682472 Mon Sep 17 00:00:00 2001 From: Allo Date: Wed, 8 Feb 2023 10:19:07 +0800 Subject: [PATCH 03/10] apply suggestions and also match html elements in markdown content --- build/check-images.ts | 72 ++++++++++--------- build/flaws/broken-links.ts | 8 +-- build/flaws/heading-links.ts | 2 +- build/flaws/index.ts | 2 +- build/flaws/pre-tags.ts | 2 +- build/flaws/unsafe-html.ts | 2 +- build/{matches-in-text.ts => matches.ts} | 35 ++++++--- .../files/en-us/web/images/bad_src/index.md | 22 ++++-- testing/tests/index.test.ts | 15 ++++ 9 files changed, 104 insertions(+), 56 deletions(-) rename build/{matches-in-text.ts => matches.ts} (68%) diff --git a/build/check-images.ts b/build/check-images.ts index 2fa5e7f6ac57..a77ea12bc947 100644 --- a/build/check-images.ts +++ b/build/check-images.ts @@ -8,7 +8,7 @@ import sizeOf from "image-size"; import { Document, Image } from "../content"; import { FLAW_LEVELS } from "../libs/constants"; -import { findMatchesInText, findMatchesInMarkdown } from "./matches-in-text"; +import { findMatchesInText, findMatchesInMarkdown } from "./matches"; import { DEFAULT_LOCALE } from "../libs/constants"; /** @@ -21,52 +21,56 @@ export function checkImageReferences(doc, $, options, { url, rawContent }) { const checkImages = options.flawLevels.get("images") !== FLAW_LEVELS.IGNORE; - const checked = new Map(); + const checked = new Map(); const isMarkdown = doc.isMarkdown; function addImageFlaw( $img, src, - { explanation, externalImage = false, suggestion = null } + { + explanation, + externalImage = false, + suggestion = null, + }: { + explanation: string; + externalImage?: boolean; + suggestion?: string; + } ) { // If the document has *two* `` tags, this function // (addImageFlaw) is called two times. We can then assume the // findMatchesInText() will find it two times too. For each call, // we need to match the call based in counting matches from findMatchesInText(). const matches = isMarkdown - ? findMatchesInMarkdown(rawContent, "image", src) - : findMatchesInText(src, rawContent, { - attribute: "src", - }); - const checkedBefore = checked.get(src) || 0; - matches.forEach((match, i) => { - if (i !== checkedBefore) { - return; - } - if (!("images" in doc.flaws)) { - doc.flaws.images = []; - } - let fixable = false; - if (suggestion) { - $img.attr("src", suggestion); - fixable = true; - } - const id = `image${doc.flaws.images.length + 1}`; - $img.attr("data-flaw", id); - doc.flaws.images.push({ - id, - src, - fixable, - suggestion, - explanation, - externalImage, - ...match, - }); - - // Use this to remember which in the list of matches we've dealt with. - checked.set(src, checkedBefore + 1); + ? findMatchesInMarkdown(src, rawContent, { type: "image" }) + : findMatchesInText(src, rawContent, { attribute: "src" }); + const checkedBefore = checked.get(src) ?? 0; + const match = matches?.[checkedBefore]; + if (!match) { + return; // we haven't found the match. We may need to deal with the match finder function. + } + if (!("images" in doc.flaws)) { + doc.flaws.images = []; + } + const fixable = Boolean(suggestion); + if (suggestion) { + $img.attr("src", suggestion); + } + const id = `image${doc.flaws.images.length + 1}`; + $img.attr("data-flaw", id); + doc.flaws.images.push({ + id, + src, + fixable, + suggestion, + explanation, + externalImage, + ...match, }); + + // Use this to remember which in the list of matches we've dealt with. + checked.set(src, checkedBefore + 1); } $("img[src]").each((i, element) => { diff --git a/build/flaws/broken-links.ts b/build/flaws/broken-links.ts index 1168e6b949a8..b2b51dbd587e 100644 --- a/build/flaws/broken-links.ts +++ b/build/flaws/broken-links.ts @@ -2,7 +2,7 @@ import fs from "node:fs"; import path from "node:path"; import { Document, Redirect, Image } from "../../content"; -import { findMatchesInText, findMatchesInMarkdown } from "../matches-in-text"; +import { findMatchesInText, findMatchesInMarkdown } from "../matches"; import { DEFAULT_LOCALE, FLAW_LEVELS, @@ -106,15 +106,13 @@ export function getBrokenLinksFlaws(doc, $, { rawContent }, level) { href, doc.isMarkdown - ? findMatchesInMarkdown(rawContent, "link", href) + ? findMatchesInMarkdown(href, rawContent, { type: "link" }) : findMatchesInText(href, rawContent, { attribute: "href", }) ); } - // findMatchesInText() is a generator function so use `Array.from()` - // to turn it into an array so we can use `.forEach()` because that - // gives us an `i` for every loop. + matches.get(href).forEach((match, i) => { if (i !== index) { return; diff --git a/build/flaws/heading-links.ts b/build/flaws/heading-links.ts index 9002779a37e2..a0253a6ff7e4 100644 --- a/build/flaws/heading-links.ts +++ b/build/flaws/heading-links.ts @@ -1,4 +1,4 @@ -import { findMatchesInText } from "../matches-in-text"; +import { findMatchesInText } from "../matches"; // You're not allowed to have `` elements inside `

` or `

` elements // because those will be rendered out as "links to themselves". diff --git a/build/flaws/index.ts b/build/flaws/index.ts index e1c48c6ec705..9e7b959e5a32 100644 --- a/build/flaws/index.ts +++ b/build/flaws/index.ts @@ -8,7 +8,7 @@ import { DEFAULT_LOCALE } from "../../libs/constants"; import { replaceMatchesInText, replaceMatchingLinksInMarkdown, -} from "../matches-in-text"; +} from "../matches"; import { forceExternalURL, downloadAndResizeImage } from "../utils"; import { getBadBCDQueriesFlaws } from "./bad-bcd-queries"; import { getBrokenLinksFlaws } from "./broken-links"; diff --git a/build/flaws/pre-tags.ts b/build/flaws/pre-tags.ts index 5f6d6e198aa9..75a8d9c833ab 100644 --- a/build/flaws/pre-tags.ts +++ b/build/flaws/pre-tags.ts @@ -1,6 +1,6 @@ import { Flaw } from "."; -import { getFirstMatchInText } from "../matches-in-text"; +import { getFirstMatchInText } from "../matches"; const escapeHTML = (s) => s .replace(/&/g, "&") diff --git a/build/flaws/unsafe-html.ts b/build/flaws/unsafe-html.ts index 6ee2a58b41e9..2f6aff9b3a62 100644 --- a/build/flaws/unsafe-html.ts +++ b/build/flaws/unsafe-html.ts @@ -4,7 +4,7 @@ import { INTERACTIVE_EXAMPLES_BASE_URL, LIVE_SAMPLES_BASE_URL, } from "../../libs/env"; -import { findMatchesInText } from "../matches-in-text"; +import { findMatchesInText } from "../matches"; const safeIFrameSrcs = [ // EmbedGHLiveSample.ejs diff --git a/build/matches-in-text.ts b/build/matches.ts similarity index 68% rename from build/matches-in-text.ts rename to build/matches.ts index e45c1365eea7..9b93cfda1159 100644 --- a/build/matches-in-text.ts +++ b/build/matches.ts @@ -9,7 +9,7 @@ export function findMatchesInText( needle: string, haystack: string, { attribute = null } = {} -) { +): Array { // Need to remove any characters that can affect a regex if we're going // use the string in a manually constructed regex. const escaped = needle.replace(ESCAPE_CHARS_RE, "\\$&"); @@ -28,14 +28,33 @@ export function findMatchesInText( return matches; } +// find links or images in markdown content that match the given URL export function findMatchesInMarkdown( + url: string, rawContent: string, - type: "link" | "image", - url: string -) { + { type }: { type: "link" | "image" } +): Array { const matches: Array = []; - visit(fromMarkdown(rawContent), type, (node: any) => { - if (node.url === url) { + const attributeType = type === "link" ? "href" : "src"; + const tree = fromMarkdown(rawContent); + // Find all the links and images in the markdown + // we should also find any HTML elements that contain links or images + visit(tree, [type, "html"], (node: any) => { + if (node.type === "html") { + const matchesInHtml = findMatchesInText(url, node.value, { + attribute: attributeType, + }); + const correctedMatches = matchesInHtml.map(({ line, column }): Match => { + if (line === 1) { + // if it's the first line, we need to add the column offset + column += node.position.start.column - 1; + } + line += node.position.start.line - 1; + return { line, column }; + }); + matches.push(...correctedMatches); + } else if (node.url === url) { + // else this would be a markdown link or image const { line, column } = node.position.start; matches.push({ line, column }); } @@ -43,12 +62,12 @@ export function findMatchesInMarkdown( return matches; } -export function getFirstMatchInText(needle, haystack) { +export function getFirstMatchInText(needle, haystack): Match { const index = haystack.indexOf(needle); const left = haystack.substring(0, index); const line = left.split("\n").length; const column = left.length - left.lastIndexOf("\n"); - return { line, column } as Match; + return { line, column }; } export function replaceMatchingLinksInMarkdown(needle, haystack, replacement) { diff --git a/testing/content/files/en-us/web/images/bad_src/index.md b/testing/content/files/en-us/web/images/bad_src/index.md index ccea887c7a9e..1bde1772a64b 100644 --- a/testing/content/files/en-us/web/images/bad_src/index.md +++ b/testing/content/files/en-us/web/images/bad_src/index.md @@ -3,14 +3,26 @@ title: tag with src that isn't a valid image slug: Web/Images/Bad_src --- - -![](actuallynota.svg) - ![](/en-us/web) ![](actuallynota.png) - -![](empty.gif) + + + + + + + + +
+ broken image +
diff --git a/testing/tests/index.test.ts b/testing/tests/index.test.ts index ae35c3ae7c71..08b1d724f0f6 100644 --- a/testing/tests/index.test.ts +++ b/testing/tests/index.test.ts @@ -1070,6 +1070,21 @@ test("image flaws with bad images", () => { "File not present on disk, an empty file, or not an image" ).length ).toBe(4); + // Check the line and column numbers for html tags in markdown + expect({ + line: flaws.images[2].line, + column: flaws.images[2].column, + }).toEqual({ + line: 16, + column: 12, + }); + expect({ + line: flaws.images[3].line, + column: flaws.images[3].column, + }).toEqual({ + line: 25, + column: 17, + }); }); test("linked to local files", () => { From 0fd5947caebc0a326b042b6093bf7d63950eaa4d Mon Sep 17 00:00:00 2001 From: Allo Date: Wed, 8 Feb 2023 10:26:06 +0800 Subject: [PATCH 04/10] check length before getting item by index --- build/check-images.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/check-images.ts b/build/check-images.ts index a77ea12bc947..4cfc2001a4a9 100644 --- a/build/check-images.ts +++ b/build/check-images.ts @@ -46,10 +46,10 @@ export function checkImageReferences(doc, $, options, { url, rawContent }) { ? findMatchesInMarkdown(src, rawContent, { type: "image" }) : findMatchesInText(src, rawContent, { attribute: "src" }); const checkedBefore = checked.get(src) ?? 0; - const match = matches?.[checkedBefore]; - if (!match) { + if (matches.length <= checkedBefore) { return; // we haven't found the match. We may need to deal with the match finder function. } + const match = matches[checkedBefore]; if (!("images" in doc.flaws)) { doc.flaws.images = []; } From 4326119f5677a740bf4bcbf121aaea4091ba975b Mon Sep 17 00:00:00 2001 From: Allo Date: Wed, 8 Feb 2023 13:11:01 +0800 Subject: [PATCH 05/10] print warning when index out of bound --- build/check-images.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build/check-images.ts b/build/check-images.ts index 4cfc2001a4a9..4a984527af59 100644 --- a/build/check-images.ts +++ b/build/check-images.ts @@ -47,7 +47,10 @@ export function checkImageReferences(doc, $, options, { url, rawContent }) { : findMatchesInText(src, rawContent, { attribute: "src" }); const checkedBefore = checked.get(src) ?? 0; if (matches.length <= checkedBefore) { - return; // we haven't found the match. We may need to deal with the match finder function. + console.warn( + `Could not find enough matches for src: ${src}, index ${checkedBefore} out of bounds` + ); + return; } const match = matches[checkedBefore]; if (!("images" in doc.flaws)) { From 91e84d65c92fb89a34d232f7abc9aa8e8550ac70 Mon Sep 17 00:00:00 2001 From: Allo Date: Wed, 8 Feb 2023 20:51:19 +0800 Subject: [PATCH 06/10] remove unused import --- build/flaws/broken-links.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/build/flaws/broken-links.ts b/build/flaws/broken-links.ts index 264ef9fd4adc..2bfcca6ac7b0 100644 --- a/build/flaws/broken-links.ts +++ b/build/flaws/broken-links.ts @@ -1,5 +1,4 @@ import fs from "node:fs"; -import path from "node:path"; import { Document, Redirect, Image } from "../../content/index.js"; import { findMatchesInText, findMatchesInMarkdown } from "../matches.js"; From 3267e43c7ad0acf273930f0a93d143d4ca824545 Mon Sep 17 00:00:00 2001 From: Claas Augner Date: Thu, 29 Feb 2024 16:24:00 +0100 Subject: [PATCH 07/10] refactor(build): inline single-use var --- build/check-images.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/build/check-images.ts b/build/check-images.ts index 087686116463..ecd5710b657c 100644 --- a/build/check-images.ts +++ b/build/check-images.ts @@ -32,8 +32,6 @@ export function checkImageReferences( const checked = new Map(); - const isMarkdown = doc.isMarkdown; - function addImageFlaw( $img, src, @@ -51,7 +49,7 @@ export function checkImageReferences( // (addImageFlaw) is called two times. We can then assume the // findMatchesInText() will find it two times too. For each call, // we need to match the call based in counting matches from findMatchesInText(). - const matches = isMarkdown + const matches = doc.isMarkdown ? findMatchesInMarkdown(src, rawContent, { type: "image" }) : findMatchesInText(src, rawContent, { attribute: "src" }); const checkedBefore = checked.get(src) ?? 0; From b638e40960cfbec56d3f2fba45e5fb0ffbbb758d Mon Sep 17 00:00:00 2001 From: Claas Augner Date: Thu, 29 Feb 2024 16:24:38 +0100 Subject: [PATCH 08/10] refactor(build): update array type syntax --- build/matches.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build/matches.ts b/build/matches.ts index 5476f6235aae..595534aab88a 100644 --- a/build/matches.ts +++ b/build/matches.ts @@ -9,14 +9,14 @@ export function findMatchesInText( needle: string, haystack: string, { attribute = null } = {} -): Array { +): Match[] { // Need to remove any characters that can affect a regex if we're going // use the string in a manually constructed regex. const escaped = needle.replace(ESCAPE_CHARS_RE, "\\$&"); const rex = attribute ? new RegExp(`${attribute}=['"](${escaped})['"]`, "g") : new RegExp(`(${escaped})`, "g"); - const matches: Array = []; + const matches: Match[] = []; for (const match of haystack.matchAll(rex)) { const left = haystack.slice(0, match.index); const line = (left.match(/\n/g) || []).length + 1; @@ -33,8 +33,8 @@ export function findMatchesInMarkdown( url: string, rawContent: string, { type }: { type: "link" | "image" } -): Array { - const matches: Array = []; +): Match[] { + const matches: Match[] = []; const attributeType = type === "link" ? "href" : "src"; const tree = fromMarkdown(rawContent); // Find all the links and images in the markdown From ac96741dd8806316adc3bb633190a6c8b1d2cfcd Mon Sep 17 00:00:00 2001 From: Claas Augner Date: Thu, 29 Feb 2024 16:30:16 +0100 Subject: [PATCH 09/10] chore(build): add param types --- build/check-images.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/check-images.ts b/build/check-images.ts index ecd5710b657c..c9168b8597e7 100644 --- a/build/check-images.ts +++ b/build/check-images.ts @@ -33,8 +33,8 @@ export function checkImageReferences( const checked = new Map(); function addImageFlaw( - $img, - src, + $img: cheerio.Cheerio, + src: string, { explanation, externalImage = false, From 74621d28c2edacb6d4641e290362c0f75dd85f32 Mon Sep 17 00:00:00 2001 From: Allo Date: Fri, 1 Mar 2024 16:39:57 +0800 Subject: [PATCH 10/10] chore: add node type directive --- build/matches.ts | 5 +++-- package.json | 1 + yarn.lock | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/build/matches.ts b/build/matches.ts index 595534aab88a..c8205094c35e 100644 --- a/build/matches.ts +++ b/build/matches.ts @@ -1,3 +1,4 @@ +import "mdast-util-directive"; import { fromMarkdown } from "mdast-util-from-markdown"; import { visit } from "unist-util-visit"; @@ -39,7 +40,7 @@ export function findMatchesInMarkdown( const tree = fromMarkdown(rawContent); // Find all the links and images in the markdown // we should also find any HTML elements that contain links or images - visit(tree, [type, "html"], (node: any) => { + visit(tree, [type, "html"], (node) => { if (node.type === "html") { const matchesInHtml = findMatchesInText(url, node.value, { attribute: attributeType, @@ -53,7 +54,7 @@ export function findMatchesInMarkdown( return { line, column }; }); matches.push(...correctedMatches); - } else if (node.url === url) { + } else if (node.type == type && node.url === url) { // else this would be a markdown link or image const { line, column } = node.position.start; matches.push({ line, column }); diff --git a/package.json b/package.json index e2b3ff9a7131..9f738f903541 100644 --- a/package.json +++ b/package.json @@ -211,6 +211,7 @@ "jest-watch-typeahead": "^2.2.2", "jsdom": "^24.0.0", "lint-staged": "^13.2.3", + "mdast-util-directive": "^3.0.0", "mdast-util-to-hast": "^13.1.0", "mini-css-extract-plugin": "^2.8.1", "node-dev": "^8.0.0", diff --git a/yarn.lock b/yarn.lock index bbaa526ab74b..d4715f793e78 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4761,6 +4761,11 @@ character-entities@^2.0.0: resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.2.tgz#2d09c2e72cd9523076ccb21157dff66ad43fcc22" integrity sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ== +character-reference-invalid@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz#85c66b041e43b47210faf401278abf808ac45cb9" + integrity sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw== + chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" @@ -8697,6 +8702,19 @@ ipaddr.js@^2.1.0: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.1.0.tgz#2119bc447ff8c257753b196fc5f1ce08a4cdf39f" integrity sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ== +is-alphabetical@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-2.0.1.tgz#01072053ea7c1036df3c7d19a6daaec7f19e789b" + integrity sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ== + +is-alphanumerical@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz#7c03fbe96e3e931113e57f964b0a368cc2dfd875" + integrity sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw== + dependencies: + is-alphabetical "^2.0.0" + is-decimal "^2.0.0" + is-array-buffer@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.1.tgz#deb1db4fcae48308d54ef2442706c0393997052a" @@ -8798,6 +8816,11 @@ is-date-object@^1.0.1, is-date-object@^1.0.5: dependencies: has-tostringtag "^1.0.0" +is-decimal@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-2.0.1.tgz#9469d2dc190d0214fd87d78b78caecc0cc14eef7" + integrity sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A== + is-docker@^2.0.0, is-docker@^2.1.1: version "2.2.1" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" @@ -8861,6 +8884,11 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" +is-hexadecimal@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz#86b5bf668fca307498d319dfc03289d781a90027" + integrity sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg== + is-inside-container@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-inside-container/-/is-inside-container-1.0.0.tgz#e81fba699662eb31dbdaf26766a61d4814717ea4" @@ -10301,6 +10329,20 @@ md5@^2.3.0: crypt "0.0.2" is-buffer "~1.1.6" +mdast-util-directive@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-directive/-/mdast-util-directive-3.0.0.tgz#3fb1764e705bbdf0afb0d3f889e4404c3e82561f" + integrity sha512-JUpYOqKI4mM3sZcNxmF/ox04XYFFkNwr0CFlrQIkCwbvH0xzMCqkMqAde9wRd80VAhaUrwFwKm2nxretdT1h7Q== + dependencies: + "@types/mdast" "^4.0.0" + "@types/unist" "^3.0.0" + devlop "^1.0.0" + mdast-util-from-markdown "^2.0.0" + mdast-util-to-markdown "^2.0.0" + parse-entities "^4.0.0" + stringify-entities "^4.0.0" + unist-util-visit-parents "^6.0.0" + mdast-util-find-and-replace@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.0.tgz#ca0a9232afdc53f4260582ac2d0227cf94b4a220" @@ -11611,6 +11653,20 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" +parse-entities@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-4.0.1.tgz#4e2a01111fb1c986549b944af39eeda258fc9e4e" + integrity sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w== + dependencies: + "@types/unist" "^2.0.0" + character-entities "^2.0.0" + character-entities-legacy "^3.0.0" + character-reference-invalid "^2.0.0" + decode-named-character-reference "^1.0.0" + is-alphanumerical "^2.0.0" + is-decimal "^2.0.0" + is-hexadecimal "^2.0.0" + parse-json@^5.0.0, parse-json@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"