From 7e86b0cbb038d3f363daac9fbd4b9ec252b7ddfa Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 5 Jul 2020 15:44:54 -0700 Subject: [PATCH 1/3] add subtask test Signed-off-by: shmck --- tests/parse.test.ts | 78 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 70 insertions(+), 8 deletions(-) diff --git a/tests/parse.test.ts b/tests/parse.test.ts index 28746af..fbf71a1 100644 --- a/tests/parse.test.ts +++ b/tests/parse.test.ts @@ -541,7 +541,6 @@ The first step files: ["someFile.js"], watchers: ["someFile.js"], filter: "someFilter", - subtasks: true, }, solution: { commands: ["npm install"], @@ -579,7 +578,6 @@ The first step files: ["someFile.js"], watchers: ["someFile.js"], filter: "someFilter", - subtasks: true, }, solution: { commits: ["1gfedcba", "987654321"], @@ -631,7 +629,6 @@ The third step files: ["someFile.js"], watchers: ["someFile.js"], filter: "someFilter", - subtasks: true, }, solution: { commands: ["npm install"], @@ -645,7 +642,6 @@ The third step files: ["someFile.js"], watchers: ["someFile.js"], filter: "someFilter", - subtasks: true, }, solution: { commands: ["npm install"], @@ -666,7 +662,6 @@ The third step files: ["someFile.js"], watchers: ["someFile.js"], filter: "someFilter", - subtasks: true, }, solution: { commands: ["npm install"], @@ -709,7 +704,6 @@ The third step files: ["someFile.js"], watchers: ["someFile.js"], filter: "someFilter", - subtasks: true, }, solution: { commits: ["1fedcba", "987654321"], @@ -726,7 +720,6 @@ The third step files: ["someFile.js"], watchers: ["someFile.js"], filter: "someFilter", - subtasks: true, }, solution: { commits: ["3abcdef"], @@ -751,7 +744,6 @@ The third step files: ["someFile.js"], watchers: ["someFile.js"], filter: "someFilter", - subtasks: true, }, solution: { commits: ["5abcdef"], @@ -1419,4 +1411,74 @@ The second uninterrupted step expect(result.levels[0]).toEqual(expected.levels[0]); }); }); + describe("subtasks", () => { + it("should parse subtasks", () => { + const md = `# Subtask Demo + +A demo demonstrating how to use subtasks + +## 1. Subtask Example + +A subtask example + +### 1.1 + +Create a function \`add\` that can take a variety of params. + +#### SUBTASKS + +- Add one number +- Add two numbers +- Add three numbers`; + const skeleton = { + levels: [ + { + id: "1", + steps: [ + { + id: "1.1", + }, + ], + }, + ], + }; + const expected = { + levels: [ + { + id: "1", + title: "Subtask Example", + summary: "A subtask example", + content: "A subtask example", + steps: [ + { + id: "1.1", + setup: { + subtasks: [ + "Add one number", + "Add two numbers", + "Add three numbers", + ], + commits: ["abcdef1"], + }, + content: + "Create a function `add` that can take a variety of params.", + solution: { + commits: ["abcdef2"], + }, + }, + ], + }, + ], + }; + const result = parse({ + text: md, + skeleton, + commits: { + "1.1:T": ["abcdef1"], + "1.1:S": ["abcdef2"], + }, + }); + expect(result.levels).toEqual(expected.levels); + }); + }); }); From 72430c62e1d13258b9ed6f30d5e725c9ceea17c7 Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 5 Jul 2020 15:57:48 -0700 Subject: [PATCH 2/3] support parsing subtasks Signed-off-by: shmck --- src/utils/parse.ts | 43 +++++++++++++++++++++++++++++++------------ tests/parse.test.ts | 15 ++++++++------- typings/tutorial.d.ts | 4 ++-- 3 files changed, 41 insertions(+), 21 deletions(-) diff --git a/src/utils/parse.ts b/src/utils/parse.ts index 7c4fb04..29f5211 100644 --- a/src/utils/parse.ts +++ b/src/utils/parse.ts @@ -91,20 +91,39 @@ export function parseMdContent(md: string): TutorialFrame | never { content: stepContent.trim(), }; } else { - // parse hints from stepContent const hintDetectRegex = /^(#{4}\sHINTS[\n\r]+([\*|\-]\s(?[^]*))[\n\r]+)+/; const hintMatch = section.match(hintDetectRegex); - if (!!hintMatch) { - const hintItemRegex = /[\n\r]+[\*|\-]\s/; - const hints = section - .split(hintItemRegex) - .slice(1) // remove #### HINTS - .map((h) => h.trim()); - if (hints.length) { - mdContent.levels[current.levelIndex].steps[ - current.stepIndex - ].hints = hints; - } + const subtaskDetectRegex = /^(#{4}\sSUBTASKS[\n\r]+([\*|\-]\s(?[^]*))[\n\r]+)+/; + const subtaskMatch = section.match(subtaskDetectRegex); + const listItemregex = /[\n\r]+[\*|\-]\s/; + + switch (true) { + // parse hints from stepContent + case !!hintMatch: + const hints = section + .split(listItemregex) + .slice(1) // remove #### HINTS + .map((h) => h.trim()); + if (hints.length) { + mdContent.levels[current.levelIndex].steps[ + current.stepIndex + ].hints = hints; + } + return; + // parse subtasks from stepContent + case !!subtaskMatch: + const subtasks = section + .split(listItemregex) + .slice(1) // remove #### SUBTASKS + .map((h) => h.trim()); + if (subtasks.length) { + mdContent.levels[current.levelIndex].steps[ + current.stepIndex + ].subtasks = subtasks; + } + return; + default: + console.warn(`No build parser match found for:\n${section}\n`); } } } diff --git a/tests/parse.test.ts b/tests/parse.test.ts index fbf71a1..478918b 100644 --- a/tests/parse.test.ts +++ b/tests/parse.test.ts @@ -1429,7 +1429,8 @@ Create a function \`add\` that can take a variety of params. - Add one number - Add two numbers -- Add three numbers`; +- Add three numbers +`; const skeleton = { levels: [ { @@ -1453,11 +1454,6 @@ Create a function \`add\` that can take a variety of params. { id: "1.1", setup: { - subtasks: [ - "Add one number", - "Add two numbers", - "Add three numbers", - ], commits: ["abcdef1"], }, content: @@ -1465,6 +1461,11 @@ Create a function \`add\` that can take a variety of params. solution: { commits: ["abcdef2"], }, + subtasks: [ + "Add one number", + "Add two numbers", + "Add three numbers", + ], }, ], }, @@ -1478,7 +1479,7 @@ Create a function \`add\` that can take a variety of params. "1.1:S": ["abcdef2"], }, }); - expect(result.levels).toEqual(expected.levels); + expect(result.levels[0]).toEqual(expected.levels[0]); }); }); }); diff --git a/typings/tutorial.d.ts b/typings/tutorial.d.ts index 2b7769c..f19830b 100644 --- a/typings/tutorial.d.ts +++ b/typings/tutorial.d.ts @@ -27,7 +27,7 @@ export type Step = { content: string; setup?: StepActions; solution?: Maybe; - subtasks?: { [testName: string]: boolean }; + subtasks?: string[]; hints?: string[]; }; @@ -52,7 +52,7 @@ export type StepActions = { files?: string[]; watchers?: string[]; filter?: string; - subtasks?: boolean; + subtasks?: string[]; }; export interface TestRunnerArgs { From 859d8e526706cce0666dae9a42012113c8747d9d Mon Sep 17 00:00:00 2001 From: shmck Date: Sun, 5 Jul 2020 16:01:19 -0700 Subject: [PATCH 3/3] refactor parse regexes Signed-off-by: shmck --- src/utils/parse.ts | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/utils/parse.ts b/src/utils/parse.ts index 29f5211..c6e1a07 100644 --- a/src/utils/parse.ts +++ b/src/utils/parse.ts @@ -7,6 +7,15 @@ type TutorialFrame = { levels: T.Level[]; }; +const R = { + summary: /^#\s(?.*)[\n\r]+(?[^]*)/, + level: /^(#{2}\s(?L?\d+\.?)\s(?.*)[\n\r]*(>\s(?.*))?[\n\r]+(?[^]*))/, + step: /^(#{3}\s(?.*)[\n\r]+(?[^]*))/, + hints: /^(#{4}\sHINTS[\n\r]+([\*|\-]\s(?[^]*))[\n\r]+)+/, + subtasks: /^(#{4}\sSUBTASKS[\n\r]+([\*|\-]\s(?[^]*))[\n\r]+)+/, + listItem: /[\n\r]+[\*|\-]\s/, +}; + export function parseMdContent(md: string): TutorialFrame | never { let start: number = -1; const parts: any[] = []; @@ -34,9 +43,7 @@ export function parseMdContent(md: string): TutorialFrame | never { }; // Capture summary - const summaryMatch = parts - .shift() - .match(/^#\s(?.*)[\n\r]+(?[^]*)/); + const summaryMatch = parts.shift().match(R.summary); if (summaryMatch.groups.tutorialTitle) { mdContent.summary.title = summaryMatch.groups.tutorialTitle.trim(); } @@ -49,8 +56,7 @@ export function parseMdContent(md: string): TutorialFrame | never { // Identify each part of the content parts.forEach((section: string) => { // match level - const levelRegex = /^(#{2}\s(?L?\d+\.?)\s(?.*)[\n\r]*(>\s(?.*))?[\n\r]+(?[^]*))/; - const levelMatch: RegExpMatchArray | null = section.match(levelRegex); + const levelMatch: RegExpMatchArray | null = section.match(R.level); if (levelMatch && levelMatch.groups) { const levelId = levelMatch.groups.levelId.replace(".", ""); @@ -77,8 +83,7 @@ export function parseMdContent(md: string): TutorialFrame | never { }; } else { // match step - const stepRegex = /^(#{3}\s(?.*)[\n\r]+(?[^]*))/; - const stepMatch: RegExpMatchArray | null = section.match(stepRegex); + const stepMatch: RegExpMatchArray | null = section.match(R.step); if (stepMatch && stepMatch.groups) { current = { levelId: current.levelId, @@ -91,17 +96,14 @@ export function parseMdContent(md: string): TutorialFrame | never { content: stepContent.trim(), }; } else { - const hintDetectRegex = /^(#{4}\sHINTS[\n\r]+([\*|\-]\s(?[^]*))[\n\r]+)+/; - const hintMatch = section.match(hintDetectRegex); - const subtaskDetectRegex = /^(#{4}\sSUBTASKS[\n\r]+([\*|\-]\s(?[^]*))[\n\r]+)+/; - const subtaskMatch = section.match(subtaskDetectRegex); - const listItemregex = /[\n\r]+[\*|\-]\s/; + const hintMatch = section.match(R.hints); + const subtaskMatch = section.match(R.subtasks); switch (true) { // parse hints from stepContent case !!hintMatch: const hints = section - .split(listItemregex) + .split(R.listItem) .slice(1) // remove #### HINTS .map((h) => h.trim()); if (hints.length) { @@ -113,7 +115,7 @@ export function parseMdContent(md: string): TutorialFrame | never { // parse subtasks from stepContent case !!subtaskMatch: const subtasks = section - .split(listItemregex) + .split(R.listItem) .slice(1) // remove #### SUBTASKS .map((h) => h.trim()); if (subtasks.length) {