thephpleague / commonmark

Highly-extensible PHP Markdown parser which fully supports the CommonMark and GFM specs.
https://commonmark.thephpleague.com
BSD 3-Clause "New" or "Revised" License
2.75k stars 194 forks source link

Delimeter processor doesn't run in links and images #1002

Closed dkarlovi closed 11 months ago

dkarlovi commented 11 months ago

Version(s) affected

2.4.1

Description

This works:

This is an asset lookup: {{asset('assets/images/logo.svg')}}

This doesn't work:

![Logo]({{asset('assets/images/logo.svg')}})

How to reproduce

Register this delimiter processor

final class ExpressionDelimiter implements DelimiterProcessorInterface
{
    public function getOpeningCharacter(): string
    {
        return '{';
    }

    public function getClosingCharacter(): string
    {
        return '}';
    }

    public function getMinLength(): int
    {
        return 2;
    }

    public function getDelimiterUse(DelimiterInterface $opener, DelimiterInterface $closer): int
    {
        return 2;
    }

    public function process(AbstractStringContainer $opener, AbstractStringContainer $closer, int $delimiterUse): void
    {
        $opener->insertAfter($this->expression($opener, $closer));
    }

    private function expression(AbstractStringContainer $opener, AbstractStringContainer $closer): AbstractStringContainer
    {
        $expressionNode = new Expression();

        $node = $opener->next();
        while ($node !== null && $node !== $closer) {
            if ($node instanceof StringContainerInterface === false) {
                throw new \RuntimeException('Invalid node type found');
            }
            $expressionNode->append($node);
            $expressionNode->appendChild($node);
            $node = $node->next();
        }

        return $expressionNode;
    }
}

Possible solution

No response

Additional context

The idea is to allow placing expressions into a MD file (say, reference assets, images which get processed in some way before rendering the Markdown).

See https://github.com/sigwinhq/yassg/pull/181

Did this project help you today? Did it make you happy in any way?

No response

colinodell commented 11 months ago

According to the CommonMark spec, link text is allowed to contain other inlines (including delimiter-based ones) but link destinations are not. You can see this by testing ![foo](**emphasis**) in several different Markdown parsers

The idea is to allow placing expressions into a MD file (say, reference assets, images which get processed in some way before rendering the Markdown).

Ah! For that case I'd highly recommend performing that pre-processing before parsing the Markdown (so that the expressions are actually rendered into Markdown). You could do this before passing the Markdown into this library, or by listening for the DocumentPreParsedEvent.

Your syntax looks very similar to Twig - you could run the document through Twig first (to render the expressions) and then feed that final Markdown through here.

dkarlovi commented 11 months ago

@colinodell thanks for the inspiration, I did consider doing it like that before, but it seemed kind of heavy handed because you go from not being able to do anything to being able to do way too much. :laughing:

I'll do it by implementing the Twig preprocessing in a sandboxed manner, meaning the Twig instance will be specifically narrowed as much as possible.

Thanks, have a good day!

colinodell commented 11 months ago

That sounds like a great approach! Feel free to reach out again if you have any other questions 🙂