Best practice for asymmetrical inline parsers

I’m working on adding a Markdown language extension for an asymmetrical syntax (similar to image/link tags). What’s the best practice for implementing something like this? When trying to mimic the existing image/link implementation, I see that cx.parts, Mark, and InlineDelimiter are only available internally.

I am not sure what you are trying to implement, maybe you can explain more.

As per cx.parts, Mark, Close and InlineDelimiter are internal code, you could mimic them by simply recreating them, but for InlineDelimiter, you would also need to recreate resolveMarkers which internally convert the InlineDelimiter to actual elements, here it is referenced:

Here is the code to be mimicked for the resolveMarkers, not much has to be changed, on the top of my head I can say you would need to change this.elt to cx.elt in a parseInline, and create a custom list of parts by manually looping through each element as if the you are in the parseInline and pushing elements to the parts list which can be fed to the resolveMarkers function as a parameter at the end of the loop.

I know this sounds complicated, and so some point it is, so I really am not sure if its the recommended way to go about this.

Also I have the code mimicking a lot of this, not specifically for images/links, but for emphases, which can be rewritten to your need quite easily, I can send it to you in Discord if you want it.

The idea is to either let the built-in matcher handle the matching, by using DelimiterType.resolve, or do it manually when seeing a closing delimiter, using findOpeningDelimiter and takeContent.

Oh yeah totally forgot about takeContent, thats practically the public resolveMarkers, I had to recreate it for the editing of emphases logic, sorry about that. :upside_down_face:

Okay, I believe I came up with a solution, although I still had to access cx.parts directly after using takeContent which has to be ignored by TS. Is there any way that (or a similar method) can be made public for better TS support?

It would be useful to know why you had to touch cx.parts here.

I based my solution on the implementation of link/image tags, so I used cx.parts to replace the given content.

parse(cx, next, pos) {
  if (!(next === getCode(']') && cx.char(pos + 1) === getCode(']'))) { return -1 }

  // @ts-ignore
  const parts = cx.parts

  const openIndex = cx.findOpeningDelimiter(ReferenceStartDelimiter)

  if (Number.isInteger(openIndex)) {
    const start = parts[openIndex].from
    const end = pos + 2
    const content = cx.takeContent(openIndex)

    content.unshift(cx.elt('ReferenceMark', start, start + 2))
    content.push(cx.elt('ReferenceMark', end - 2, end))

    let ref = parts[openIndex] = cx.elt('Reference', start, end, content)

    return ref.to
  }

  return -1
},

@marijn any advice on how to refactor this to not use cx.parts?

1 Like

What prevents you from using takeContent here?