Skip to content

Commit a6ae501

Browse files
authored
Merge pull request #10 from coderoad/feature/test-output
Feature/test output
2 parents c263369 + f11a7ab commit a6ae501

File tree

6 files changed

+356
-134
lines changed

6 files changed

+356
-134
lines changed

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
build
2-
node_modules
2+
node_modules
3+
coverage

.vscode/launch.json

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"type": "node",
9+
"request": "launch",
10+
"name": "Jest All",
11+
"program": "${workspaceFolder}/node_modules/.bin/jest",
12+
"args": ["--runInBand"],
13+
"console": "integratedTerminal",
14+
"internalConsoleOptions": "neverOpen",
15+
"windows": {
16+
"program": "${workspaceFolder}/node_modules/jest/bin/jest"
17+
}
18+
}
19+
]
20+
}

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"moduleFileExtensions": [
5353
"js",
5454
"ts"
55-
]
55+
],
56+
"collectCoverage": true
5657
}
5758
}

src/templates/coderoad.yaml

+5-24
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,8 @@ config:
3131
# - npm install
3232
## App versions helps to ensure compatability with the Extension
3333
appVersions:
34-
{}
3534
## Ensure compatability with a minimal VSCode CodeRoad version
36-
# vscode: '>=0.7.0'
35+
vscode: ">=0.7.0"
3736
## Repo information to load code from
3837
##
3938
repo:
@@ -62,25 +61,16 @@ levels:
6261
## Setup for the first task. Required.
6362
setup:
6463
## Files to open in a text editor when the task loads. Optional.
65-
files: []
66-
# - package.json
67-
## Commits to load when the task loads. These should include failing tests. Required.
68-
## The list will be filled by the parser
69-
commits:
70-
[]
71-
# - a commit hash
64+
files:
65+
- package.json
7266
## Solution for the first task. Required.
7367
solution:
7468
## Files to open when the solution loads. Optional.
75-
files: []
76-
# - package.json
77-
## 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.
78-
## The list will be filled by the parser
79-
commits: []
69+
files:
70+
- package.json
8071
## Example Two: Running commands
8172
- id: L1S2
8273
setup:
83-
commits: []
8474
## CLI commands that are run when the task loads. Optional.
8575
commands:
8676
- npm install
@@ -94,27 +84,18 @@ levels:
9484
setup:
9585
files:
9686
- package.json
97-
commits:
98-
- commit7
9987
## Listeners that run tests when a file or directory changes.
10088
watchers:
10189
- package.json
10290
- node_modules/some-package
10391
solution:
10492
files:
10593
- package.json
106-
commits:
107-
- commit8
10894
## Example Four: Subtasks
10995
- id: L1S4
11096
setup:
111-
commits:
112-
- commit8
11397
commands:
11498
## A filter is a regex that limits the test results
11599
- filter: "^Example 2"
116100
## A feature that shows subtasks: all filtered active test names and the status of the tests (pass/fail).
117101
- subtasks: true
118-
solution:
119-
commits:
120-
- commit9

src/utils/parse.ts

+95-87
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import * as T from "../../typings/tutorial";
44

55
type TutorialFrame = {
66
summary: T.TutorialSummary;
7+
levels: {
8+
[levelKey: string]: T.Level;
9+
};
10+
steps: { [stepKey: string]: Partial<T.Step> };
711
};
812

913
export function parseMdContent(md: string): TutorialFrame | never {
@@ -24,73 +28,66 @@ export function parseMdContent(md: string): TutorialFrame | never {
2428
}
2529
});
2630

27-
const sections = {};
31+
const mdContent: TutorialFrame = {
32+
summary: {
33+
title: "",
34+
description: "",
35+
},
36+
levels: {},
37+
steps: {},
38+
};
2839

29-
// Identify and remove the header
40+
// Capture summary
3041
const summaryMatch = parts
3142
.shift()
3243
.match(/^#\s(?<tutorialTitle>.*)[\n\r]+(?<tutorialDescription>[^]*)/);
33-
3444
if (!summaryMatch.groups.tutorialTitle) {
3545
throw new Error("Missing tutorial title");
3646
}
47+
mdContent.summary.title = summaryMatch.groups.tutorialTitle.trim();
3748

3849
if (!summaryMatch.groups.tutorialDescription) {
3950
throw new Error("Missing tutorial summary description");
4051
}
41-
42-
sections["summary"] = {
43-
title: summaryMatch.groups.tutorialTitle.trim(),
44-
description: summaryMatch.groups.tutorialDescription.trim(),
45-
};
52+
mdContent.summary.description = summaryMatch.groups.tutorialDescription.trim();
4653

4754
// Identify each part of the content
48-
parts.forEach((section) => {
55+
parts.forEach((section: string) => {
56+
// match level
4957
const levelRegex = /^(##\s(?<levelId>L\d+)\s(?<levelTitle>.*)[\n\r]*(>\s*(?<levelSummary>.*))?[\n\r]+(?<levelContent>[^]*))/;
50-
const stepRegex = /^(###\s(?<stepId>(?<levelId>L\d+)S\d+)\s(?<stepTitle>.*)[\n\r]+(?<stepContent>[^]*))/;
51-
52-
const levelMatch = section.match(levelRegex);
53-
const stepMatch = section.match(stepRegex);
54-
55-
if (levelMatch) {
58+
const levelMatch: RegExpMatchArray | null = section.match(levelRegex);
59+
if (levelMatch && levelMatch.groups) {
5660
const {
5761
levelId,
5862
levelTitle,
5963
levelSummary,
6064
levelContent,
6165
} = levelMatch.groups;
6266

63-
const level = {
64-
[levelId]: {
65-
id: levelId,
66-
title: levelTitle,
67-
summary: levelSummary
68-
? levelSummary.trim()
69-
: _.truncate(levelContent, { length: 80, omission: "..." }),
70-
content: levelContent.trim(),
71-
},
72-
};
73-
74-
_.merge(sections, level);
75-
} else if (stepMatch) {
76-
const step = {
77-
[stepMatch.groups.levelId]: {
78-
steps: {
79-
[stepMatch.groups.stepId]: {
80-
id: stepMatch.groups.stepId,
81-
// title: stepMatch.groups.stepTitle, //Not using at this momemnt
82-
content: stepMatch.groups.stepContent.trim(),
83-
},
84-
},
85-
},
67+
// @ts-ignore
68+
mdContent.levels[levelId] = {
69+
id: levelId,
70+
title: levelTitle,
71+
summary: levelSummary
72+
? levelSummary.trim()
73+
: _.truncate(levelContent, { length: 80, omission: "..." }),
74+
content: levelContent.trim(),
8675
};
87-
88-
_.merge(sections, step);
76+
} else {
77+
// match step
78+
const stepRegex = /^(###\s(?<stepId>(?<levelId>L\d+)S\d+)\s(?<stepTitle>.*)[\n\r]+(?<stepContent>[^]*))/;
79+
const stepMatch: RegExpMatchArray | null = section.match(stepRegex);
80+
if (stepMatch && stepMatch.groups) {
81+
const { stepId, stepContent } = stepMatch.groups;
82+
mdContent.steps[stepId] = {
83+
id: stepId,
84+
content: stepContent.trim(),
85+
};
86+
}
8987
}
9088
});
9189

92-
// @ts-ignore
93-
return sections;
90+
return mdContent;
9491
}
9592

9693
type ParseParams = {
@@ -100,65 +97,76 @@ type ParseParams = {
10097
};
10198

10299
export function parse(params: ParseParams): any {
103-
const parsed = { ...params.config };
104-
105100
const mdContent: TutorialFrame = parseMdContent(params.text);
106101

107-
// Add the summary to the tutorial file
108-
parsed["summary"] = mdContent.summary;
102+
const parsed: Partial<T.Tutorial> = {
103+
summary: mdContent.summary,
104+
config: params.config.config,
105+
levels: [],
106+
};
109107

110108
// merge content and tutorial
111-
if (parsed.levels) {
112-
parsed.levels.forEach((level: T.Level, levelIndex: number) => {
113-
const levelContent = mdContent[level.id];
109+
if (params.config.levels && params.config.levels.length) {
110+
parsed.levels = params.config.levels.map(
111+
(level: T.Level, levelIndex: number) => {
112+
const levelContent = mdContent.levels[level.id];
113+
114+
if (!levelContent) {
115+
console.log(`Markdown content not found for ${level.id}`);
116+
return;
117+
}
114118

115-
if (!levelContent) {
116-
console.log(`Markdown content not found for ${level.id}`);
117-
return;
118-
}
119+
level = { ...level, ...levelContent };
119120

120-
// add level setup commits
121-
const levelSetupKey = `L${levelIndex + 1}`;
122-
if (params.commits[levelSetupKey]) {
123-
if (!level.setup) {
124-
level.setup = {
125-
commits: [],
126-
};
121+
// add level setup commits
122+
const levelSetupKey = level.id;
123+
if (params.commits[levelSetupKey]) {
124+
if (!level.setup) {
125+
level.setup = {
126+
commits: [],
127+
};
128+
}
129+
level.setup.commits = params.commits[levelSetupKey];
127130
}
128-
level.setup.commits = params.commits[levelSetupKey];
129-
}
130131

131-
const { steps, ...content } = levelContent;
132-
133-
// add level step commits
134-
if (steps) {
135-
steps.forEach((step: T.Step, stepIndex: number) => {
136-
const stepSetupKey = `${levelSetupKey}S${stepIndex + `1`}Q`;
137-
if (params.commits[stepSetupKey]) {
138-
if (!step.setup) {
139-
step.setup = {
140-
commits: [],
141-
};
132+
// add level step commits
133+
level.steps = (level.steps || []).map(
134+
(step: T.Step, stepIndex: number) => {
135+
const stepKey = `${levelSetupKey}S${stepIndex + 1}`;
136+
const stepSetupKey = `${stepKey}Q`;
137+
if (params.commits[stepSetupKey]) {
138+
if (!step.setup) {
139+
step.setup = {
140+
commits: [],
141+
};
142+
}
143+
step.setup.commits = params.commits[stepSetupKey];
144+
}
145+
146+
const stepSolutionKey = `${stepKey}A`;
147+
if (params.commits[stepSolutionKey]) {
148+
if (!step.solution) {
149+
step.solution = {
150+
commits: [],
151+
};
152+
}
153+
step.solution.commits = params.commits[stepSolutionKey];
142154
}
143-
step.setup.commits = params.commits[stepSetupKey];
144-
}
145155

146-
const stepSolutionKey = `${levelSetupKey}S${stepIndex + `1`}A`;
147-
if (params.commits[stepSolutionKey]) {
148-
if (!step.solution) {
149-
step.solution = {
150-
commits: [],
151-
};
156+
// add markdown
157+
const stepMarkdown: Partial<T.Step> = mdContent.steps[step.id];
158+
if (stepMarkdown) {
159+
step = { ...step, ...stepMarkdown };
152160
}
153-
step.solution.commits = params.commits[stepSolutionKey];
161+
162+
step.id = `${stepKey}`;
163+
return step;
154164
}
165+
);
155166

156-
return _.merge(step, steps[step.id]);
157-
});
167+
return level;
158168
}
159-
160-
_.merge(level, content);
161-
});
169+
);
162170
}
163171

164172
return parsed;

0 commit comments

Comments
 (0)