diff --git a/CHANGELOG.md b/CHANGELOG.md index 78626a1..6e0a931 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix support for all FCC supported spoken languages (#20) - Remove incomplete support of dark mode, no more white on white text: not readable (#33) +- Parse properly markdown property with colon and quotes (#6) ### Added diff --git a/zimui/src/utils/__tests__/fixtures/basicMarkdownChallenge.md b/zimui/src/utils/__tests__/fixtures/basicMarkdownChallenge.md index eabd7da..ba40bdd 100644 --- a/zimui/src/utils/__tests__/fixtures/basicMarkdownChallenge.md +++ b/zimui/src/utils/__tests__/fixtures/basicMarkdownChallenge.md @@ -1,6 +1,6 @@ --- id: 56533eb9ac21ba0edf2244c9 -title: Accessing Object Properties with Variables +title: 'Accessing: Object Properties with Variables' challengeType: 1 videoUrl: 'https://scrimba.com/c/cnQyKur' forumTopicId: 16165 @@ -104,4 +104,4 @@ const testObj = { }; console.log("I should show up on the console") const playerNumber = 16; -const player = testObj[playerNumber]; \ No newline at end of file +const player = testObj[playerNumber]; diff --git a/zimui/src/utils/__tests__/parseChallenge.test.ts b/zimui/src/utils/__tests__/parseChallenge.test.ts index 578a75a..cc46026 100644 --- a/zimui/src/utils/__tests__/parseChallenge.test.ts +++ b/zimui/src/utils/__tests__/parseChallenge.test.ts @@ -1,7 +1,7 @@ import { readFile } from 'fs/promises' import { join } from 'path' import { beforeAll, describe, expect, it } from 'vitest' -import { Challenge, parseChallenge } from '../parseChallenge' +import { Challenge, parseChallenge, extractKeyValueFromMarkdown } from '../parseChallenge' describe('Parsing a basic JS challenge', () => { let markdown = '' @@ -18,6 +18,15 @@ describe('Parsing a basic JS challenge', () => { expect(typeof description === 'string').toBe(true) expect(description && description.length > 0).toBe(true) }) + it('should pull the header from the markdown', async () => { + const headers = challenge.header + expect(typeof headers === 'object').toBe(true) + expect(headers["title"]).toEqual('Accessing: Object Properties with Variables') + expect(headers["challengeType"]).toEqual('1') + expect(headers["dashedName"]).toEqual('accessing-object-properties-with-variables') + expect(headers["id"]).toEqual('56533eb9ac21ba0edf2244c9') + expect(headers["videoUrl"]).toEqual('https://scrimba.com/c/cnQyKur') + }) it('should pull the seed code from the markdown', async () => { const seed = challenge.seed expect(typeof seed === 'string').toBe(true) @@ -32,3 +41,18 @@ describe('Parsing a basic JS challenge', () => { expect(typeof solutions[0] === 'string').toBe(true) }) }) + +describe('Extract key/value for markdown header', () => { + it('should parse property with quotes', async () => { + expect(extractKeyValueFromMarkdown("title: 'A title: with a colon and quotes'")).toEqual(['title', 'A title: with a colon and quotes']) + }) + it('should parse property without quotes', async () => { + expect(extractKeyValueFromMarkdown("title: A simple title")).toEqual(['title', 'A simple title']) + }) + it('should not care about extra spaces', async () => { + expect(extractKeyValueFromMarkdown("title: A simple title ")).toEqual(['title', 'A simple title']) + }) + it('should not care about extra spaces with quotes', async () => { + expect(extractKeyValueFromMarkdown("title: ' A simple title ' ")).toEqual(['title', ' A simple title ']) // keep whitespaces inside the quotes + }) +}) diff --git a/zimui/src/utils/parseChallenge.ts b/zimui/src/utils/parseChallenge.ts index e5f153d..4248052 100644 --- a/zimui/src/utils/parseChallenge.ts +++ b/zimui/src/utils/parseChallenge.ts @@ -4,6 +4,14 @@ export const parseChallenge = (markdownStr: string): Challenge => { return new Challenge(marked.lexer(markdownStr)) } +export const extractKeyValueFromMarkdown = (rawString: string): string[] => { + // return a tuple of key and value for a given markdown header string + // which format is "key: value" or "key: 'quoted value: with colon'" + // value is unquotted, and leading/trailing whitespaces (outside of the + // quotes if any) are dropped + return rawString.split(/:\s*'?(.*?)(?:'\s*|\s*$)/s).slice(0,2) +} + type HintTokens = | marked.Tokens.Space | marked.Tokens.Code @@ -22,7 +30,7 @@ export class Challenge { const rawStrings = frontMatter.text.split('\n') const data: { [key: string]: string } = {} for (const rawString of rawStrings) { - const keyVal = rawString.split(': ') + const keyVal = extractKeyValueFromMarkdown(rawString) data[keyVal[0]] = keyVal[1] } return data