Skip to content

Instantly share code, notes, and snippets.

@DavidWells
Last active April 8, 2024 03:46
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save DavidWells/67afcf0338ebef664a7e418f4f8ca27c to your computer and use it in GitHub Desktop.
Save DavidWells/67afcf0338ebef664a7e418f4f8ca27c to your computer and use it in GitHub Desktop.
Find all ``` code blocks in markdown
const fs = require('fs')
const path = require('path')
const content = fs.readFileSync(path.resolve(__dirname, 'zmd-with-code.md'), 'utf-8')
// https://regex101.com/r/nIlW1U/6
const PATTERN = /^([A-Za-z \t]*)```([A-Za-z]*)?\n([\s\S]*?)```([A-Za-z \t]*)*$/gm
function findCodeBlocks(block) {
let matches
let errors = []
let blocks = []
while ((matches = PATTERN.exec(block)) !== null) {
if (matches.index === PATTERN.lastIndex) {
PATTERN.lastIndex++ // avoid infinite loops with zero-width matches
}
const [ match, prefix, syntax, content, postFix ] = matches
const lang = syntax || 'none'
const lineNumber = getLineNumber(block, matches)
let hasError = false
/* // debug
console.log(`prefix: "${prefix}"`)
console.log(`postFix: "${postFix}"`)
console.log('syntax:', lang)
console.log('Content:')
console.log(content.trim())
console.log('───────────────────────')
/** */
/* Validate code blocks */
if (prefix && prefix.match(/\S/)) {
hasError = true
errors.push({
line: lineNumber,
position: matches.index,
message: `Prefix "${prefix}" not allowed on line ${lineNumber}. Remove it to fix the code block.`,
block: match
})
}
if (postFix && postFix.match(/\S/)) {
hasError = true
const line = lineNumber + (countLines(match) - 1)
errors.push({
line,
position: matches.index + match.length,
message: `Postfix "${postFix}" not allowed on line ${line}. Remove it to fix the code block.`,
block: match
})
}
if (!hasError) {
blocks.push({
line: lineNumber,
position: matches.index,
syntax: lang,
block: match,
code: content.trim()
})
}
}
return {
errors,
blocks
}
}
function countLines(text = '') {
return text.split('\n').length
}
function getLineNumber(text = '', matches) {
return countLines(text.substr(0, matches.index))
}
const { blocks, errors } = findCodeBlocks(content)
console.log('blocks')
console.log(blocks)
console.log('errors')
console.log(errors)

Markdown with code blocks

https://regex101.com/r/nIlW1U/6

Markdowndown code blocks work with triple `'s

This pattern matches prefix, syntax, contents, and postfix

Like this \``or "```" or ``` inline blocks are like thiscode here`

x```js asdf


test


Indented

test


```js
xyz

Indented with syntax

xyz

With code content

const foo = () => {}

Postfix

const foo = () => {}
```x

With internal ticks

```js
// comment `
const foo = `lol
  cool with ticks \`\`\`
`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment