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

Commitc1f89ee

Browse files
committed
parse level content
Signed-off-by: shmck <shawn.j.mckay@gmail.com>
1 parentfa641d7 commitc1f89ee

File tree

5 files changed

+187
-139
lines changed

5 files changed

+187
-139
lines changed

‎src/build.ts

Lines changed: 4 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -3,84 +3,14 @@ import * as path from "path";
33
import*as_from"lodash";
44
import*asfsfrom"fs";
55
import*asTfrom"../typings/tutorial";
6+
import{parse}from"./utils/parse";
67
// import validate from './validator';
78

89
// import not working
910
constsimpleGit=require("simple-git/promise");
1011

1112
constworkingDir="tmp";
1213

13-
typeTutorialContent={};
14-
15-
exportfunctionparseContent(md:string):TutorialContent{
16-
letstart:number=-1;
17-
constparts:any[]=[];
18-
19-
constlines=md.split("\n");
20-
21-
// Split the multiple parts - This way enables the creator to use 4/5 level headers inside the content.
22-
lines.forEach((line,index)=>{
23-
if(line.match(/#{1,3}\s/)||index===lines.length-1){
24-
if(start!==-1){
25-
parts.push(lines.slice(start,index).join("\n"));
26-
start=index;
27-
}else{
28-
start=index;
29-
}
30-
}
31-
});
32-
33-
constsections={};
34-
35-
// Identify and remove the header
36-
constsummaryMatch=parts
37-
.shift()
38-
.match(/^#\s(?<tutorialTitle>.*)[\n\r]+(?<tutorialDescription>[^]*)/);
39-
40-
sections["summary"]={
41-
title:summaryMatch.groups.tutorialTitle.trim(),
42-
description:summaryMatch.groups.tutorialDescription.trim(),
43-
};
44-
45-
// Identify each part of the content
46-
parts.forEach((section)=>{
47-
constlevelRegex=/^(##\s(?<levelId>L\d+)\s(?<levelTitle>.*)[\n\r]*(>\s*(?<levelSummary>.*))?[\n\r]+(?<levelContent>[^]*))/;
48-
conststepRegex=/^(###\s(?<stepId>(?<levelId>L\d+)S\d+)\s(?<stepTitle>.*)[\n\r]+(?<stepContent>[^]*))/;
49-
50-
constlevelMatch=section.match(levelRegex);
51-
conststepMatch=section.match(stepRegex);
52-
53-
if(levelMatch){
54-
constlevel={
55-
[levelMatch.groups.levelId]:{
56-
id:levelMatch.groups.levelId,
57-
title:levelMatch.groups.levelTitle,
58-
summary:levelMatch.groups.levelSummary.trim(),
59-
content:levelMatch.groups.levelContent.trim(),
60-
},
61-
};
62-
63-
_.merge(sections,level);
64-
}elseif(stepMatch){
65-
conststep={
66-
[stepMatch.groups.levelId]:{
67-
steps:{
68-
[stepMatch.groups.stepId]:{
69-
id:stepMatch.groups.stepId,
70-
// title: stepMatch.groups.stepTitle, //Not using at this momemnt
71-
content:stepMatch.groups.stepContent.trim(),
72-
},
73-
},
74-
},
75-
};
76-
77-
_.merge(sections,step);
78-
}
79-
});
80-
81-
returnsections;
82-
}
83-
8414
functionrmDir(dir:string,rmSelf=false){
8515
try{
8616
letfiles;
@@ -164,32 +94,10 @@ async function build({ repo, codeBranch, setupBranch, isLocal }: BuildOptions) {
16494
awaitgit.checkout(setupBranch);
16595

16696
// Load files
167-
const_mdContent=fs.readFileSync(
168-
path.join(localPath,"TUTORIAL.md"),
169-
"utf8"
170-
);
171-
let_tutorial=fs.readFileSync(
172-
path.join(localPath,"coderoad.yaml"),
173-
"utf8"
174-
);
175-
176-
// Add one more line to the content as per Shawn's request
177-
constmdContent:any=parseContent(_mdContent);
178-
179-
// Parse tutorial to JSON
180-
consttutorial:T.Tutorial=yamlParser.load(_tutorial);
181-
182-
// Add the summary to the tutorial file
183-
tutorial.summary=mdContent.summary;
184-
185-
// merge content and tutorial
186-
tutorial.levels.forEach((level:T.Level)=>{
187-
const{ steps, ...content}=mdContent[level.id];
188-
189-
level.steps.forEach((step:T.Step)=>_.merge(step,steps[step.id]));
97+
const_content=fs.readFileSync(path.join(localPath,"TUTORIAL.md"),"utf8");
98+
let_config=fs.readFileSync(path.join(localPath,"coderoad.yaml"),"utf8");
19099

191-
_.merge(level,content);
192-
});
100+
consttutorial=parse(_content,_config);
193101

194102
// Checkout the code branches
195103
awaitgit.checkout(codeBranch);

‎src/templates/coderoad.yaml

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,7 @@
22
# This is a YAML-formatted file.
33
## Your personal version of the tutorial
44
##
5-
version:'0.1.0'
6-
## Data used to populate the tutorial summary page
7-
##
8-
summary:
9-
## The title of your tutorial. Required.
10-
##
11-
title:''
12-
## A description of your tutorial. Required.
13-
##
14-
description:''
5+
version:"0.1.0"
156
## Data used to configure and setup the tutorial
167
##
178
config:
@@ -32,28 +23,31 @@ config:
3223
setup:
3324
## A list of commits to load to setup the tutorial
3425
commits:[]
35-
# - commit1
36-
# - commit2
26+
# - commit1
27+
# - commit2
3728
## A list of commands to run to configure the tutorial
38-
commands:[]
29+
commands:
30+
[]
3931
# - npm install
4032
## App versions helps to ensure compatability with the Extension
41-
appVersions:{}
33+
appVersions:
34+
{}
4235
## Ensure compatability with a minimal VSCode CodeRoad version
4336
# vscode: '>=0.7.0'
4437
## Repo information to load code from
4538
##
4639
repo:
4740
## The uri path to the repo containing the code commits. Required.
4841
##
49-
uri:''
42+
uri:""
5043
## The branch on the repo uri that contains the code commits. Required.
51-
branch:''
52-
44+
branch:""
45+
5346
## A list of tutorial dependencies to ensure the environment is setup for the tutorial. Optional.
5447
## The dependencies will be checked by running `dependency.name` --version and comparing it to the version provided.
5548
##
56-
dependencies:[]
49+
dependencies:
50+
[]
5751
## The name of the dependency
5852
# - name: node
5953
# ## The version requirement. See https://github.com/npm/node-semver for options.
@@ -69,16 +63,17 @@ levels:
6963
setup:
7064
## Files to open in a text editor when the task loads. Optional.
7165
files:[]
72-
# - package.json
66+
# - package.json
7367
## Commits to load when the task loads. These should include failing tests. Required.
7468
## The list will be filled by the parser
75-
commits:[]
69+
commits:
70+
[]
7671
# - a commit hash
7772
## Solution for the first task. Required.
7873
solution:
7974
## Files to open when the solution loads. Optional.
8075
files:[]
81-
# - package.json
76+
# - package.json
8277
## Commits that complete the task. All tests should pass when the commits load. These commits will not be loaded by the tutorial user in normal tutorial activity.
8378
## The list will be filled by the parser
8479
commits:[]
@@ -117,10 +112,9 @@ levels:
117112
-commit8
118113
commands:
119114
## A filter is a regex that limits the test results
120-
-filter:'^Example 2'
115+
-filter:"^Example 2"
121116
## A feature that shows subtasks: all filtered active test names and the status of the tests (pass/fail).
122117
-subtasks:true
123118
solution:
124119
commits:
125120
-commit9
126-

‎src/utils/parse.ts

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import*asyamlParserfrom"js-yaml";
2+
import*as_from"lodash";
3+
import*asTfrom"../../typings/tutorial";
4+
5+
typeTutorialFrame={
6+
summary:T.TutorialSummary;
7+
};
8+
9+
exportfunctionparseMdContent(md:string):TutorialFrame|never{
10+
letstart:number=-1;
11+
constparts:any[]=[];
12+
13+
constlines=md.split("\n");
14+
15+
// Split the multiple parts - This way enables the creator to use 4/5 level headers inside the content.
16+
lines.forEach((line,index)=>{
17+
if(line.match(/#{1,3}\s/)||index===lines.length-1){
18+
if(start!==-1){
19+
parts.push(lines.slice(start,index).join("\n"));
20+
start=index;
21+
}else{
22+
start=index;
23+
}
24+
}
25+
});
26+
27+
constsections={};
28+
29+
// Identify and remove the header
30+
constsummaryMatch=parts
31+
.shift()
32+
.match(/^#\s(?<tutorialTitle>.*)[\n\r]+(?<tutorialDescription>[^]*)/);
33+
34+
if(!summaryMatch.groups.tutorialTitle){
35+
thrownewError("Missing tutorial title");
36+
}
37+
38+
if(!summaryMatch.groups.tutorialDescription){
39+
thrownewError("Missing tutorial summary description");
40+
}
41+
42+
sections["summary"]={
43+
title:summaryMatch.groups.tutorialTitle.trim(),
44+
description:summaryMatch.groups.tutorialDescription.trim(),
45+
};
46+
47+
// Identify each part of the content
48+
parts.forEach((section)=>{
49+
constlevelRegex=/^(##\s(?<levelId>L\d+)\s(?<levelTitle>.*)[\n\r]*(>\s*(?<levelSummary>.*))?[\n\r]+(?<levelContent>[^]*))/;
50+
conststepRegex=/^(###\s(?<stepId>(?<levelId>L\d+)S\d+)\s(?<stepTitle>.*)[\n\r]+(?<stepContent>[^]*))/;
51+
52+
constlevelMatch=section.match(levelRegex);
53+
conststepMatch=section.match(stepRegex);
54+
55+
if(levelMatch){
56+
constlevel={
57+
[levelMatch.groups.levelId]:{
58+
id:levelMatch.groups.levelId,
59+
title:levelMatch.groups.levelTitle,
60+
summary:levelMatch.groups.levelSummary.trim(),
61+
content:levelMatch.groups.levelContent.trim(),
62+
},
63+
};
64+
65+
_.merge(sections,level);
66+
}elseif(stepMatch){
67+
conststep={
68+
[stepMatch.groups.levelId]:{
69+
steps:{
70+
[stepMatch.groups.stepId]:{
71+
id:stepMatch.groups.stepId,
72+
// title: stepMatch.groups.stepTitle, //Not using at this momemnt
73+
content:stepMatch.groups.stepContent.trim(),
74+
},
75+
},
76+
},
77+
};
78+
79+
_.merge(sections,step);
80+
}
81+
});
82+
83+
//@ts-ignore
84+
returnsections;
85+
}
86+
87+
exportfunctionparse(_content:string,_config:string):T.Tutorial{
88+
constmdContent:TutorialFrame=parseMdContent(_content);
89+
// Parse tutorial to JSON
90+
consttutorial:T.Tutorial=yamlParser.load(_config);
91+
92+
// Add the summary to the tutorial file
93+
tutorial["summary"]=mdContent.summary;
94+
95+
// merge content and tutorial
96+
if(tutorial.levels){
97+
tutorial.levels.forEach((level:T.Level)=>{
98+
constlevelContent=mdContent[level.id];
99+
if(!levelContent){
100+
console.log(`Markdown content not found for${level.id}`);
101+
return;
102+
}
103+
const{ steps, ...content}=levelContent;
104+
105+
if(steps){
106+
steps.forEach((step:T.Step)=>_.merge(step,steps[step.id]));
107+
}
108+
109+
_.merge(level,content);
110+
});
111+
}
112+
113+
returntutorial;
114+
}

‎tests/parse.test.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import{parse}from"../src/utils/parse";
2+
3+
describe("parse",()=>{
4+
it("should parse summary",()=>{
5+
constmd=`# Insert Tutorial's Title here
6+
7+
Short description to be shown as a tutorial's subtitle.
8+
9+
`;
10+
11+
constyaml=`version: "0.1.0"`;
12+
constresult=parse(md,yaml);
13+
constexpected={
14+
summary:{
15+
description:"Short description to be shown as a tutorial's subtitle.",
16+
title:"Insert Tutorial's Title here",
17+
},
18+
};
19+
expect(result.summary).toEqual(expected.summary);
20+
});
21+
22+
it("should parse a level with a summary",()=>{
23+
constmd=`# Title
24+
25+
Description.
26+
27+
## L1 Put Level's title here
28+
29+
> Level's summary: a short description of the level's content in one line.
30+
31+
Some text
32+
`;
33+
34+
constyaml=`version: "0.1.0"
35+
levels:
36+
- id: L1
37+
`;
38+
constresult=parse(md,yaml);
39+
constexpected={
40+
levels:[
41+
{
42+
id:"L1",
43+
title:"Put Level's title here",
44+
summary:
45+
"Level's summary: a short description of the level's content in one line.",
46+
content:"Some text",
47+
},
48+
],
49+
};
50+
expect(result.levels).toEqual(expected.levels);
51+
});
52+
});

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp