Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 42 additions & 10 deletions support/src/parse.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import mit from "markdown-it";
import type { Token } from "markdown-it/index.js";
import { sourceLocationOf, type SourceLocation } from "./sourceLocation.js";
import {
markUpContent,
sourceLocationOf,
unMarkUpContent,
type SourceLocation,
} from "./sourceLocation.js";

export type ParsedLink = {
readonly target: string;
Expand All @@ -14,14 +19,22 @@ export type ParsedImage = {
readonly sourceLocation: SourceLocation | null;
};

export type DeprecatedTerm = {
readonly term: string;
readonly word: string;
readonly sourceLocation: SourceLocation;
};

export type ParseResult = {
readonly links: readonly ParsedLink[];
readonly images: readonly ParsedImage[];
readonly trailingWhitespace: readonly SourceLocation[];
readonly deprecatedTerm: readonly DeprecatedTerm[];
};

export const parse = (content: string): ParseResult => {
const trailingWhitespace: SourceLocation[] = [];
const deprecatedTerm: DeprecatedTerm[] = [];

content.split(/\n/).forEach((line, index) => {
if (line.endsWith(" ")) {
Expand All @@ -33,7 +46,7 @@ export const parse = (content: string): ParseResult => {
});

const parser = mit();
const tokens = parser.parse(content, {});
const tokens = parser.parse(markUpContent(content), {});

const parsedLinks: ParsedLink[] = [];
const parsedImages: ParsedImage[] = [];
Expand All @@ -46,27 +59,45 @@ export const parse = (content: string): ParseResult => {
);

if (indexOfNextClose > index) {
const target = token.attrGet("href") as string;
const markedUpTarget = token.attrGet("href") as string;
parsedLinks.push({
target,
target: unMarkUpContent(markedUpTarget),
content: tokens
.slice(index + 1, indexOfNextClose)
.map((t) => t.content)
.map((t) => unMarkUpContent(t.content))
.join(""),
sourceLocation: sourceLocationOf(`(${target})`, content),
sourceLocation: sourceLocationOf(markedUpTarget),
});
}
}

if (token.type === "image") {
const src = token.attrGet("src") as string;
const markedUpSrc = token.attrGet("src") as string;
parsedImages.push({
src,
alt: token.content,
sourceLocation: sourceLocationOf(`(${src})`, content),
src: unMarkUpContent(markedUpSrc),
alt: unMarkUpContent(token.content),
sourceLocation: sourceLocationOf(markedUpSrc),
});
}

if (token.type === "text") {
// console.dir(token, { depth: 2 });
for (const match of token.content.matchAll(
/L(?<line0>\d+)C(?<column0>\d+)T(?<word>[\p{Alpha}\p{Number}]*(?<term>homework|student|teacher|bootcamp|classroom|class)[\p{Alpha}\p{Number}]*)/giu,
)) {
// console.dir(match, { depth: 1 });
match.groups &&
deprecatedTerm.push({
term: match.groups.term.toLowerCase(),
word: match.groups.word,
sourceLocation: {
line0: Number(match.groups.line0),
column0: Number(match.groups.column0),
},
});
}
}

if (token.children) scan(token.children);
});
};
Expand All @@ -77,5 +108,6 @@ export const parse = (content: string): ParseResult => {
links: parsedLinks,
images: parsedImages,
trailingWhitespace,
deprecatedTerm,
};
};
42 changes: 30 additions & 12 deletions support/src/sourceLocation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,38 @@ export type SourceLocation = {
readonly column0: number;
};

export const markUpContent = (content: string): string => {
return content
.split(/\n/)
.map((lineText, line0) =>
lineText.replaceAll(
/(?<![\p{Alpha}\p{Number}])([\p{Alpha}\p{Number}]+)/gu,
(matchedText, _, matchedIndex) =>
/^\d+$/.test(matchedText)
? matchedText
: `L${line0}C${matchedIndex}T${matchedText}`,
),
)
.join("\n");
};

export const unMarkUpContent = (s: string) =>
s.replaceAll(
/(?<![\p{Alpha}\p{Number}])L\d+C\d+T([\p{Alpha}\p{Number}]+)/gu,
(_, t) => t,
);

export const sourceLocationOf = (
needle: string,
haystack: string,
markedUpText: string,
): SourceLocation | null => {
const index = haystack.indexOf(needle);
if (index < 0) return null;
const m = markedUpText.match(/L(?<line0>\d+)C(?<column0>\d+)T/);

const lines = haystack.substring(0, index).split("\n");
const lastLine = lines.pop();
const line0 = lines.length;
const column0 = lastLine!.length;
if (m?.groups) {
return {
line0: Number(m.groups.line0),
column0: Number(m.groups.column0) - (m.index ?? 0),
};
}

return {
line0,
column0,
};
return null;
};
10 changes: 10 additions & 0 deletions support/src/validateLinks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,16 @@ const main = async () => {
++errors;
}

for (const found of parsedFile.deprecatedTerm) {
showError(
parsedFile.filename,
found.sourceLocation,
"VL004/deprecated-term",
`Deprecated term '${found.term}'`,
);
if (found.term !== "class") ++errors;
}

for (const img of parsedFile.images) {
if (!isExternalLink(img.src)) {
const resolved = path.join(dirname(parsedFile.filename), img.src);
Expand Down
Loading