@@ -4,10 +4,7 @@ import * as T from "../../typings/tutorial";
44
55type TutorialFrame = {
66 summary : T . TutorialSummary ;
7- levels : {
8- [ levelKey : string ] : T . Level ;
9- } ;
10- steps : { [ stepKey : string ] : Partial < T . Step > } ;
7+ levels : T . Level [ ] ;
118} ;
129
1310export function parseMdContent ( md : string ) : TutorialFrame | never {
@@ -33,8 +30,7 @@ export function parseMdContent(md: string): TutorialFrame | never {
3330 title : "" ,
3431 description : "" ,
3532 } ,
36- levels : { } ,
37- steps : { } ,
33+ levels : [ ] ,
3834 } ;
3935
4036 // Capture summary
@@ -49,23 +45,20 @@ export function parseMdContent(md: string): TutorialFrame | never {
4945 mdContent . summary . description = summaryMatch . groups . tutorialDescription . trim ( ) ;
5046 }
5147
52- let current = { level : "0" , step : "0" } ;
48+ let current = { level : - 1 , step : 0 } ;
5349 // Identify each part of the content
5450 parts . forEach ( ( section : string ) => {
5551 // match level
56- const levelRegex = / ^ ( # { 2 } \s (?< levelId > L \d + ) \s (?< levelTitle > .* ) [ \n \r ] * ( > \s (?< levelSummary > .* ) ) ? [ \n \r ] + (?< levelContent > [ ^ ] * ) ) / ;
52+ const levelRegex = / ^ ( # { 2 } \s (?< levelId > L ? \d + \. ? ) \s (?< levelTitle > .* ) [ \n \r ] * ( > \s (?< levelSummary > .* ) ) ? [ \n \r ] + (?< levelContent > [ ^ ] * ) ) / ;
5753 const levelMatch : RegExpMatchArray | null = section . match ( levelRegex ) ;
54+
5855 if ( levelMatch && levelMatch . groups ) {
59- const {
60- levelId,
61- levelTitle,
62- levelSummary,
63- levelContent,
64- } = levelMatch . groups ;
56+ current = { level : current . level + 1 , step : 0 } ;
57+ const { levelTitle, levelSummary, levelContent } = levelMatch . groups ;
6558
6659 // @ts -ignore
67- mdContent . levels [ levelId ] = {
68- id : levelId ,
60+ mdContent . levels [ current . level ] = {
61+ id : ( current . level + 1 ) . toString ( ) ,
6962 title : levelTitle . trim ( ) ,
7063 summary :
7164 levelSummary && levelSummary . trim ( ) . length
@@ -75,20 +68,21 @@ export function parseMdContent(md: string): TutorialFrame | never {
7568 omission : "..." ,
7669 } ) ,
7770 content : levelContent . trim ( ) ,
71+ steps : [ ] ,
7872 } ;
79- current = { level : levelId , step : "0" } ;
8073 } else {
8174 // match step
82- const stepRegex = / ^ ( # { 3 } \s (?< stepId > (?< levelId > L \d + ) S \d + ) \s (?< stepTitle > .* ) [ \n \r ] + (?< stepContent > [ ^ ] * ) ) / ;
75+ const stepRegex = / ^ ( # { 3 } \s \ (? < s t e p T i t l e > .* ) [ \n \r ] + (?< stepContent > [ ^ ] * ) / ;
8376 const stepMatch : RegExpMatchArray | null = section . match ( stepRegex ) ;
8477 if ( stepMatch && stepMatch . groups ) {
8578 const { stepId, stepContent } = stepMatch . groups ;
86-
87- mdContent . steps [ stepId ] = {
79+ mdContent . levels [ current . level ] . steps [ current . step ] = {
8880 id : stepId ,
8981 content : stepContent . trim ( ) ,
82+ setup : { } ,
83+ solution : { } ,
9084 } ;
91- current = { ...current , step : stepId } ;
85+ current = { ...current , step : current . step + 1 } ;
9286 } else {
9387 // parse hints from stepContent
9488 const hintDetectRegex = / ^ ( # { 4 } \s H I N T S [ \n \r ] + ( \* \s (?< hintContent > [ ^ ] * ) ) [ \n \r ] + ) + / ;
@@ -100,7 +94,7 @@ export function parseMdContent(md: string): TutorialFrame | never {
10094 . slice ( 1 ) // remove #### HINTS
10195 . map ( ( h ) => h . trim ( ) ) ;
10296 if ( hints . length ) {
103- mdContent . steps [ current . step ] . hints = hints ;
97+ mdContent . levels [ current . level ] . steps [ current . step ] . hints = hints ;
10498 }
10599 }
106100 }
@@ -135,72 +129,78 @@ export function parse(params: ParseParams): any {
135129 } ;
136130 }
137131
138- // merge content and tutorial
139- if ( params . skeleton . levels && params . skeleton . levels . length ) {
140- parsed . levels = params . skeleton . levels
141- . map ( ( level : T . Level , levelIndex : number ) => {
142- const levelContent = mdContent . levels [ level . id ] ;
132+ // merge content levels and tutorial
143133
144- if ( ! levelContent ) {
145- return null ;
146- }
147-
148- level = { ...level , ...levelContent } ;
149-
150- // add level setup commits
151- const levelSetupKey = level . id ;
152- if ( params . commits [ levelSetupKey ] ) {
153- level . setup = {
154- ...( level . setup || { } ) ,
155- commits : params . commits [ levelSetupKey ] ,
156- } ;
157- }
134+ parsed . levels = mdContent . levels . map ( ( level : T . Level , levelIndex : number ) => {
135+ // add level setup commits
136+ const levelId = level . id ;
137+ if ( params . commits [ levelId ] ) {
138+ if ( ! level . setup ) {
139+ level . setup = { } ;
140+ }
141+ level . setup . commits = params . commits [ levelId ] ;
142+ }
158143
159- // add level step commits
160- try {
161- level . steps = ( level . steps || [ ] ) . map (
162- ( step : T . Step , stepIndex : number ) => {
163- const stepKey = `${ levelSetupKey } S${ stepIndex + 1 } ` ;
164- const stepSetupKey = `${ stepKey } Q` ;
165- if ( params . commits [ stepSetupKey ] ) {
166- if ( ! step . setup ) {
167- step . setup = {
168- commits : [ ] ,
169- } ;
170- }
171- step . setup . commits = params . commits [ stepSetupKey ] ;
172- }
173-
174- const stepSolutionKey = `${ stepKey } A` ;
175- if ( params . commits [ stepSolutionKey ] ) {
176- if ( ! step . solution ) {
177- step . solution = {
178- commits : [ ] ,
179- } ;
180- }
181- step . solution . commits = params . commits [ stepSolutionKey ] ;
182- }
183-
184- // add markdown
185- const stepMarkdown : Partial < T . Step > = mdContent . steps [ step . id ] ;
186- if ( stepMarkdown ) {
187- step = { ...step , ...stepMarkdown } ;
188- }
189-
190- step . id = `${ stepKey } ` ;
191- return step ;
192- }
193- ) ;
194- } catch ( error ) {
195- console . log ( JSON . stringify ( level . steps ) ) ;
196- console . error ( "Error parsing level steps" ) ;
197- console . error ( error . message ) ;
198- }
144+ // get yaml for level
145+ const configLevel = params . skeleton . levels . find (
146+ ( l : Partial < T . Level > ) => l . id === levelId
147+ ) ;
148+
149+ let configSteps = { } ;
150+ if ( configLevel ) {
151+ const { steps, ...configLevelProps } = configLevel ;
152+ level = { ...configLevelProps , ...level } ;
153+ if ( steps ) {
154+ steps . forEach ( ( s : T . Step ) => {
155+ configSteps [ s . id ] = s ;
156+ } ) ;
157+ }
158+ }
199159
200- return level ;
201- } )
202- . filter ( ( l : T . Level | null ) => ! ! l ) ;
203- }
160+ // add level step commits
161+ // try {
162+ // level.steps = (level.steps || []).map(
163+ // (step: T.Step, stepIndex: number) => {
164+ // const stepKey = `${levelId}S${stepIndex + 1}`;
165+ // const stepSetupKey = `${stepKey}Q`;
166+ // if (params.commits[stepSetupKey]) {
167+ // if (!step.setup) {
168+ // step.setup = {
169+ // commits: [],
170+ // };
171+ // }
172+ // step.setup.commits = params.commits[stepSetupKey];
173+ // }
174+
175+ // const stepSolutionKey = `${stepKey}A`;
176+ // if (params.commits[stepSolutionKey]) {
177+ // if (!step.solution) {
178+ // step.solution = {
179+ // commits: [],
180+ // };
181+ // }
182+ // step.solution.commits = params.commits[stepSolutionKey];
183+ // }
184+
185+ // // add markdown
186+ // const stepMarkdown: Partial<T.Step> =
187+ // mdContent.levels[level.id].steps[step.id];
188+ // if (stepMarkdown) {
189+ // step = { ...step, ...stepMarkdown };
190+ // }
191+
192+ // step.id = `${stepKey}`;
193+ // return step;
194+ // }
195+ // );
196+ // } catch (error) {
197+ // console.log(JSON.stringify(level.steps));
198+ // console.error("Error parsing level steps");
199+ // console.error(error.message);
200+ // }
201+
202+ return level ;
203+ } ) ;
204204
205205 return parsed ;
206206}
0 commit comments