Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit46b64db

Browse files
authored
Merge pull request#33 from coderoad/feature/validate-markdown
Feature/validate markdown
2 parents2587efd +183a5cd commit46b64db

File tree

4 files changed

+219
-2
lines changed

4 files changed

+219
-2
lines changed

‎package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name":"@coderoad/cli",
3-
"version":"0.2.0",
3+
"version":"0.2.1",
44
"description":"A CLI to build the configuration file for Coderoad Tutorials",
55
"keywords": [
66
"coderoad",
@@ -25,7 +25,7 @@
2525
],
2626
"main":"bin/coderoad",
2727
"bin": {
28-
"@coderoad/coderoad":"bin/coderoad",
28+
"@coderoad/cli":"bin/coderoad",
2929
"coderoad":"bin/coderoad"
3030
},
3131
"scripts": {

‎src/build.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { getCommits, CommitLogObject } from "./utils/commits";
88
importskeletonSchemafrom"./schema/skeleton";
99
importtutorialSchemafrom"./schema/tutorial";
1010
import{validateSchema}from"./utils/validateSchema";
11+
import{validateMarkdown}from"./utils/validateMarkdown";
1112
import*asTfrom"../typings/tutorial";
1213

1314
constwrite=util.promisify(fs.writeFile);
@@ -72,6 +73,18 @@ async function build(args: string[]) {
7273
return;
7374
}
7475

76+
// validate markdown loosely
77+
try{
78+
constisValid=validateMarkdown(_markdown);
79+
if(!isValid){
80+
console.warn("Invalid markdown");
81+
}
82+
}catch(e){
83+
console.error("Error validating markdown:");
84+
console.error(e.message);
85+
return;
86+
}
87+
7588
// parse yaml skeleton config
7689
letskeleton;
7790
try{

‎src/utils/validateMarkdown.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
typeValidation={
2+
message:string;
3+
validate:(t:string)=>boolean;
4+
};
5+
6+
constvalidations: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+
constdescription=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+
constheaders=t.match(/^#{2}\s(.+)$/gm)||[];
30+
for(constheaderofheaders){
31+
if(!header.match(/^#{2}\s(L\d+)\s(.+)$/)){
32+
returnfalse;
33+
}
34+
}
35+
returntrue;
36+
},
37+
},
38+
{
39+
message:"should have a step `###` with a format of `L[0-9]+S[0-9]+`",
40+
validate:(t)=>{
41+
constheaders=t.match(/^#{3}\s(.+)$/gm)||[];
42+
for(constheaderofheaders){
43+
if(!header.match(/^#{3}\s(L\d+)S\d+/)){
44+
returnfalse;
45+
}
46+
}
47+
returntrue;
48+
},
49+
},
50+
];
51+
52+
constcodeBlockRegex=/```[a-z]*\n[\s\S]*?\n```/gm;
53+
54+
exportfunctionvalidateMarkdown(md:string):boolean{
55+
// remove codeblocks which might contain any valid combinations
56+
consttext=md.replace(codeBlockRegex,"");
57+
58+
letvalid=true;
59+
60+
for(constvofvalidations){
61+
if(!v.validate(text)){
62+
valid=false;
63+
if(process.env.NODE_ENV!=="test"){
64+
console.warn(v.message);
65+
}
66+
}
67+
}
68+
69+
returnvalid;
70+
}

‎tests/markdown.test.ts

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import{validateMarkdown}from"../src/utils/validateMarkdown";
2+
3+
describe("validate markdown",()=>{
4+
it("should return false if missing a summary title (#)",()=>{
5+
constmd=`
6+
Description.
7+
8+
## L1 Put Level's title here
9+
10+
> Level's summary: a short description of the level's content in one line.
11+
12+
Some text that describes the level`;
13+
expect(validateMarkdown(md)).toBe(false);
14+
});
15+
16+
it("should return false if contains multiple `#` headers",()=>{
17+
constmd1=`# A Title
18+
Description.
19+
20+
# Another Title
21+
22+
## L1 Put Level's title here
23+
24+
> Level's summary: a short description of the level's content in one line.
25+
26+
Some text that describes the level`;
27+
28+
constmd2=`# A Title
29+
Description.
30+
31+
32+
## L1 Put Level's title here
33+
34+
> Level's summary: a short description of the level's content in one line.
35+
36+
Some text that describes the level
37+
38+
# Another title
39+
`;
40+
41+
expect(validateMarkdown(md1)).toBe(false);
42+
expect(validateMarkdown(md2)).toBe(false);
43+
});
44+
45+
it("should return false if missing a summary description",()=>{
46+
constmd=`# A Title
47+
48+
## L1 Put Level's title here
49+
50+
> Level's summary: a short description of the level's content in one line.
51+
52+
Some text that describes the level
53+
`;
54+
expect(validateMarkdown(md)).toBe(false);
55+
});
56+
57+
it("should return false if `##` doesn't preface a level",()=>{
58+
constmd=`# A Title
59+
60+
A description
61+
62+
## Put Level's title here
63+
64+
> Level's summary: a short description of the level's content in one line.
65+
66+
Some text that describes the level
67+
`;
68+
expect(validateMarkdown(md)).toBe(false);
69+
});
70+
71+
it("should return false if `###` doesn't preface a step",()=>{
72+
constmd=`# A Title
73+
74+
A description
75+
76+
## Put Level's title here
77+
78+
> Level's summary: a short description of the level's content in one line.
79+
80+
Some text that describes the level
81+
82+
### A Step
83+
84+
First step
85+
`;
86+
});
87+
88+
it("should return true for valid markdown",()=>{
89+
constmd=`# Title
90+
91+
Description.
92+
93+
## L1 Put Level's title here
94+
95+
> Level's summary: a short description of the level's content in one line.
96+
97+
Some text that describes the level
98+
99+
### L1S1
100+
101+
First Step`;
102+
expect(validateMarkdown(md)).toBe(true);
103+
});
104+
105+
it("should ignore markdown content in codeblocks",()=>{
106+
constmd=`# 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+
131+
First Step`;
132+
expect(validateMarkdown(md)).toBe(true);
133+
});
134+
});

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp