Skip to content
\n

but i am having a bit trouble with matching the tags with regex in my extensions.

\n

As far as i know, the start should simply be something like start(src) { return src.match(/^:::foo\\n/)?.index; },.This only tells marked that this extension might be interested in processing the src.

\n

Later, in the tokenizer, I would have something like:

\n
tokenizer(src, tokens) {\n    const rule = /^:::foo\\n([\\s\\S]*?)\\n:::/;\n    const match = rule.exec(src);\n    if (match) {\n      const token = {\n        type: 'foo',\n        raw: match[0],\n        tokens: []\n      };\n      this.lexer.blockTokens(match[1], token.tokens);\n      return token;\n    }\n  },
\n

Normally I would end the rule with \\n to signal end of the block, but then I would be unable to match the :::: version because I would be looking at \\n:::\\n. But still, if I have nested elements, this is not working properly. So my question is how should these regexes look like to properly match the closing \"tags\" when nesting?

\n

Maybe one thing to note is that in case of blockquote, the pattern is actually:

\n
> quote\n> > nested\n> > quote
\n

and it will look like this:

\n
\n

quote

\n
\n

nested
\nquote

\n
\n
\n

PS: I can add :{3,} to beginning and end of the patterns but that does not help because it will match opening tag of the parent but it will also match opening tag of the child as closing tag. So that is not working either.

","upvoteCount":1,"answerCount":1,"acceptedAnswer":{"@type":"Answer","text":"

I think i figured it out. Not sure if this is the \"right\" way to do it but it is working:

\n
const tabs = {\n  name: 'tabs',\n  level: 'block',\n  start(src) { return src.match(/^:{3,}tabs\\n/)?.index; },\n  tokenizer(src, tokens) {\n    let count = 0\n    // because this is a block token, we will actually receive \"\\n\" as first character.\n    for (let i = 0; i < src.length; i++) {\n      if (src.charAt(i) === ':') {\n        count++\n        continue;\n      }\n      if (count > 0) {\n        break\n      }\n    }\n\n    if (count === 0) {\n      return\n    }\n\n    const pattern = `^:{${count}}tabs\\\\n([\\\\s\\\\S]*?)\\\\n:{${count}}`;\n    const rule = new RegExp(pattern)\n    const match = rule.exec(src);\n\n    if (match) {\n      const token = {\n        type: 'tabs',\n        raw: match[0],\n        tokens: []\n      };\n      this.lexer.blockTokens(match[1], token.tokens);\n      token.tokens = token.tokens.filter(t => t.type === 'tab')\n      return token;\n    }\n  },\n};
","upvoteCount":1,"url":"https://github.com/markedjs/marked/discussions/3416#discussioncomment-10366194"}}}
Discussion options

You must be logged in to vote

I think i figured it out. Not sure if this is the "right" way to do it but it is working:

const tabs = {
  name: 'tabs',
  level: 'block',
  start(src) { return src.match(/^:{3,}tabs\n/)?.index; },
  tokenizer(src, tokens) {
    let count = 0
    // because this is a block token, we will actually receive "\n" as first character.
    for (let i = 0; i < src.length; i++) {
      if (src.charAt(i) === ':') {
        count++
        continue;
      }
      if (count > 0) {
        break
      }
    }

    if (count === 0) {
      return
    }

    const pattern = `^:{${count}}tabs\\n([\\s\\S]*?)\\n:{${count}}`;
    const rule = new RegExp(pattern)
    const match = rule.exec(src);

    if (match

Replies: 1 comment

Comment options

You must be logged in to vote
0 replies
Answer selected by ivanjaros
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Q&A
Labels
None yet
1 participant