Skip to content

Commit 3feef7c

Browse files
committed
add validate markdown fn
Signed-off-by: shmck <shawn.j.mckay@gmail.com>
1 parent d4916da commit 3feef7c

File tree

2 files changed

+100
-6
lines changed

2 files changed

+100
-6
lines changed

src/utils/validateMarkdown.ts

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,72 @@
1+
type Validation = {
2+
message: string;
3+
validate: (t: string) => boolean;
4+
};
5+
6+
const validations: Validation[] = [
7+
{
8+
message: "should start with a title",
9+
validate: (t) => !!t.match(/^#\s.+/),
10+
},
11+
{
12+
message: "should not have multiple `#` headers",
13+
validate: (t) => !t.match(/[\n\r]#\s/),
14+
},
15+
{
16+
message: "should have a summary description under the title",
17+
validate: (t) => {
18+
const [summary] = t.split(/[\n\r]##/) || [""];
19+
const description = summary
20+
.split(/\n/)
21+
.slice(1)
22+
.filter((l) => l.length);
23+
return !!description.length;
24+
},
25+
},
26+
{
27+
message: "should have a level `##` with a format of `L[0-9]+`",
28+
validate: (t) => {
29+
const headers = t.match(/^#{2}\s(.+)$/gm) || [];
30+
console.log("level headers", headers);
31+
for (const header of headers) {
32+
if (!header.match(/^#{2}\s(L\d+)\s(.+)$/)) {
33+
return false;
34+
}
35+
}
36+
return true;
37+
},
38+
},
39+
{
40+
message: "should have a step `###` with a format of `L[0-9]+S[0-9]+`",
41+
validate: (t) => {
42+
const headers = t.match(/^#{3}\s(.+)$/gm) || [];
43+
console.log("step headers", headers);
44+
for (const header of headers) {
45+
if (!header.match(/^#{3}\s(L\d+)S\d+/)) {
46+
return false;
47+
}
48+
}
49+
return true;
50+
},
51+
},
52+
];
53+
54+
const codeBlockRegex = /```[a-z]*\n[\s\S]*?\n```/gm;
55+
156
export function validateMarkdown(md: string): boolean {
2-
// validate title (#)
3-
// validate description
4-
// validate level
5-
// validate steps
6-
// validate codeblock formats
57+
// remove codeblocks which might contain any valid combinations
58+
const text = md.replace(codeBlockRegex, "");
59+
60+
let valid = true;
61+
62+
for (const v of validations) {
63+
if (!v.validate(text)) {
64+
valid = false;
65+
// if (process.env.NODE_ENV !== "test") {
66+
console.warn(v.message);
67+
// }
68+
}
69+
}
770

8-
return false;
71+
return valid;
972
}

tests/markdown.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ Some text that describes the level
3737
3838
# Another title
3939
`;
40+
4041
expect(validateMarkdown(md1)).toBe(false);
4142
expect(validateMarkdown(md2)).toBe(false);
4243
});
@@ -97,6 +98,36 @@ Some text that describes the level
9798
9899
### L1S1
99100
101+
First Step`;
102+
expect(validateMarkdown(md)).toBe(true);
103+
});
104+
105+
it("should ignore markdown content in codeblocks", () => {
106+
const md = `# Title
107+
108+
Description.
109+
110+
\`\`\`md
111+
# A codeblock
112+
113+
Should not be a problem
114+
\`\`\`
115+
116+
117+
## L1 Put Level's title here
118+
119+
> Level's summary: a short description of the level's content in one line.
120+
121+
Some text that describes the level
122+
123+
\`\`\`
124+
## Another Level in markdown
125+
126+
Should not be an issue
127+
\`\`\`
128+
129+
### L1S1
130+
100131
First Step`;
101132
expect(validateMarkdown(md)).toBe(true);
102133
});

0 commit comments

Comments
 (0)