Skip to content

Commit

Permalink
Merge pull request #49 from openzim/colon_in_title
Browse files Browse the repository at this point in the history
Properly parse markdown property with colon and quotes
  • Loading branch information
benoit74 authored Dec 19, 2024
2 parents 5728331 + 08a8a9e commit 57dfbea
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions zimui/src/utils/__tests__/fixtures/basicMarkdownChallenge.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -104,4 +104,4 @@ const testObj = {
};
console.log("I should show up on the console")
const playerNumber = 16;
const player = testObj[playerNumber];
const player = testObj[playerNumber];
26 changes: 25 additions & 1 deletion zimui/src/utils/__tests__/parseChallenge.test.ts
Original file line number Diff line number Diff line change
@@ -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 = ''
Expand All @@ -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)
Expand All @@ -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
})
})
10 changes: 9 additions & 1 deletion zimui/src/utils/parseChallenge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down

0 comments on commit 57dfbea

Please sign in to comment.