vendor and env first commit
This commit is contained in:
+50
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Extension\Embed\Bridge;
|
||||
|
||||
use Embed\Embed as EmbedLib;
|
||||
use League\CommonMark\Exception\MissingDependencyException;
|
||||
use League\CommonMark\Extension\Embed\Embed;
|
||||
use League\CommonMark\Extension\Embed\EmbedAdapterInterface;
|
||||
|
||||
final class OscaroteroEmbedAdapter implements EmbedAdapterInterface
|
||||
{
|
||||
private EmbedLib $embedLib;
|
||||
|
||||
public function __construct(?EmbedLib $embed = null)
|
||||
{
|
||||
if ($embed === null) {
|
||||
if (! \class_exists(EmbedLib::class)) {
|
||||
throw new MissingDependencyException('The embed/embed package is not installed. Please install it with Composer to use this adapter.');
|
||||
}
|
||||
|
||||
$embed = new EmbedLib();
|
||||
}
|
||||
|
||||
$this->embedLib = $embed;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function updateEmbeds(array $embeds): void
|
||||
{
|
||||
$extractors = $this->embedLib->getMulti(...\array_map(static fn (Embed $embed) => $embed->getUrl(), $embeds));
|
||||
foreach ($extractors as $i => $extractor) {
|
||||
if ($extractor->code !== null) {
|
||||
$embeds[$i]->setEmbedCode($extractor->code->html);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Extension\Embed;
|
||||
|
||||
class DomainFilteringAdapter implements EmbedAdapterInterface
|
||||
{
|
||||
private EmbedAdapterInterface $decorated;
|
||||
|
||||
/** @psalm-var non-empty-string */
|
||||
private string $regex;
|
||||
|
||||
/**
|
||||
* @param string[] $allowedDomains
|
||||
*/
|
||||
public function __construct(EmbedAdapterInterface $decorated, array $allowedDomains)
|
||||
{
|
||||
$this->decorated = $decorated;
|
||||
$this->regex = self::createRegex($allowedDomains);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function updateEmbeds(array $embeds): void
|
||||
{
|
||||
$this->decorated->updateEmbeds(\array_values(\array_filter($embeds, function (Embed $embed): bool {
|
||||
return \preg_match($this->regex, $embed->getUrl()) === 1;
|
||||
})));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $allowedDomains
|
||||
*
|
||||
* @psalm-return non-empty-string
|
||||
*/
|
||||
private static function createRegex(array $allowedDomains): string
|
||||
{
|
||||
$allowedDomains = \array_map('preg_quote', $allowedDomains);
|
||||
|
||||
return '/^(?:https?:\/\/)?(?:[^.]+\.)*(' . \implode('|', $allowedDomains) . ')/';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Extension\Embed;
|
||||
|
||||
use League\CommonMark\Node\Block\AbstractBlock;
|
||||
|
||||
final class Embed extends AbstractBlock
|
||||
{
|
||||
private string $url;
|
||||
private ?string $embedCode;
|
||||
|
||||
public function __construct(string $url, ?string $embedCode = null)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->url = $url;
|
||||
$this->embedCode = $embedCode;
|
||||
}
|
||||
|
||||
public function getUrl(): string
|
||||
{
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
public function setUrl(string $url): void
|
||||
{
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
public function getEmbedCode(): ?string
|
||||
{
|
||||
return $this->embedCode;
|
||||
}
|
||||
|
||||
public function setEmbedCode(?string $embedCode): void
|
||||
{
|
||||
$this->embedCode = $embedCode;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Extension\Embed;
|
||||
|
||||
/**
|
||||
* Interface for a service which updates the embed code(s) for the given array of embeds
|
||||
*/
|
||||
interface EmbedAdapterInterface
|
||||
{
|
||||
/**
|
||||
* @param Embed[] $embeds
|
||||
*/
|
||||
public function updateEmbeds(array $embeds): void;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Extension\Embed;
|
||||
|
||||
use League\CommonMark\Environment\EnvironmentBuilderInterface;
|
||||
use League\CommonMark\Event\DocumentParsedEvent;
|
||||
use League\CommonMark\Extension\ConfigurableExtensionInterface;
|
||||
use League\Config\ConfigurationBuilderInterface;
|
||||
use Nette\Schema\Expect;
|
||||
|
||||
final class EmbedExtension implements ConfigurableExtensionInterface
|
||||
{
|
||||
public function configureSchema(ConfigurationBuilderInterface $builder): void
|
||||
{
|
||||
$builder->addSchema('embed', Expect::structure([
|
||||
'adapter' => Expect::type(EmbedAdapterInterface::class),
|
||||
'allowed_domains' => Expect::arrayOf('string')->default([]),
|
||||
'fallback' => Expect::anyOf('link', 'remove')->default('link'),
|
||||
]));
|
||||
}
|
||||
|
||||
public function register(EnvironmentBuilderInterface $environment): void
|
||||
{
|
||||
$adapter = $environment->getConfiguration()->get('embed.adapter');
|
||||
\assert($adapter instanceof EmbedAdapterInterface);
|
||||
|
||||
$allowedDomains = $environment->getConfiguration()->get('embed.allowed_domains');
|
||||
if ($allowedDomains !== []) {
|
||||
$adapter = new DomainFilteringAdapter($adapter, $allowedDomains);
|
||||
}
|
||||
|
||||
$environment
|
||||
->addBlockStartParser(new EmbedStartParser(), 300)
|
||||
->addEventListener(DocumentParsedEvent::class, new EmbedProcessor($adapter, $environment->getConfiguration()->get('embed.fallback')), 1010)
|
||||
->addRenderer(Embed::class, new EmbedRenderer());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Extension\Embed;
|
||||
|
||||
use League\CommonMark\Node\Block\AbstractBlock;
|
||||
use League\CommonMark\Parser\Block\BlockContinue;
|
||||
use League\CommonMark\Parser\Block\BlockContinueParserInterface;
|
||||
use League\CommonMark\Parser\Cursor;
|
||||
|
||||
class EmbedParser implements BlockContinueParserInterface
|
||||
{
|
||||
private Embed $embed;
|
||||
|
||||
public function __construct(string $url)
|
||||
{
|
||||
$this->embed = new Embed($url);
|
||||
}
|
||||
|
||||
public function getBlock(): AbstractBlock
|
||||
{
|
||||
return $this->embed;
|
||||
}
|
||||
|
||||
public function isContainer(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function canHaveLazyContinuationLines(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function canContain(AbstractBlock $childBlock): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function tryContinue(Cursor $cursor, BlockContinueParserInterface $activeBlockParser): ?BlockContinue
|
||||
{
|
||||
return BlockContinue::none();
|
||||
}
|
||||
|
||||
public function addLine(string $line): void
|
||||
{
|
||||
}
|
||||
|
||||
public function closeBlock(): void
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Extension\Embed;
|
||||
|
||||
use League\CommonMark\Event\DocumentParsedEvent;
|
||||
use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
|
||||
use League\CommonMark\Node\Block\Paragraph;
|
||||
use League\CommonMark\Node\Inline\Text;
|
||||
use League\CommonMark\Node\NodeIterator;
|
||||
|
||||
final class EmbedProcessor
|
||||
{
|
||||
public const FALLBACK_REMOVE = 'remove';
|
||||
public const FALLBACK_LINK = 'link';
|
||||
|
||||
private EmbedAdapterInterface $adapter;
|
||||
private string $fallback;
|
||||
|
||||
public function __construct(EmbedAdapterInterface $adapter, string $fallback = self::FALLBACK_REMOVE)
|
||||
{
|
||||
$this->adapter = $adapter;
|
||||
$this->fallback = $fallback;
|
||||
}
|
||||
|
||||
public function __invoke(DocumentParsedEvent $event): void
|
||||
{
|
||||
$document = $event->getDocument();
|
||||
$embeds = [];
|
||||
foreach (new NodeIterator($document) as $node) {
|
||||
if (! ($node instanceof Embed)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($node->parent() !== $document) {
|
||||
$replacement = new Paragraph();
|
||||
$replacement->appendChild(new Text($node->getUrl()));
|
||||
$node->replaceWith($replacement);
|
||||
} else {
|
||||
$embeds[] = $node;
|
||||
}
|
||||
}
|
||||
|
||||
$this->adapter->updateEmbeds($embeds);
|
||||
|
||||
foreach ($embeds as $embed) {
|
||||
if ($embed->getEmbedCode() !== null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->fallback === self::FALLBACK_REMOVE) {
|
||||
$embed->detach();
|
||||
} elseif ($this->fallback === self::FALLBACK_LINK) {
|
||||
$paragraph = new Paragraph();
|
||||
$paragraph->appendChild(new Link($embed->getUrl(), $embed->getUrl()));
|
||||
$embed->replaceWith($paragraph);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Extension\Embed;
|
||||
|
||||
use League\CommonMark\Node\Node;
|
||||
use League\CommonMark\Renderer\ChildNodeRendererInterface;
|
||||
use League\CommonMark\Renderer\NodeRendererInterface;
|
||||
|
||||
class EmbedRenderer implements NodeRendererInterface
|
||||
{
|
||||
/**
|
||||
* @param Embed $node
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @psalm-suppress MoreSpecificImplementedParamType
|
||||
*/
|
||||
public function render(Node $node, ChildNodeRendererInterface $childRenderer)
|
||||
{
|
||||
Embed::assertInstanceOf($node);
|
||||
|
||||
return $node->getEmbedCode() ?? '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the league/commonmark package.
|
||||
*
|
||||
* (c) Colin O'Dell <colinodell@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace League\CommonMark\Extension\Embed;
|
||||
|
||||
use League\CommonMark\Parser\Block\BlockStart;
|
||||
use League\CommonMark\Parser\Block\BlockStartParserInterface;
|
||||
use League\CommonMark\Parser\Cursor;
|
||||
use League\CommonMark\Parser\MarkdownParserStateInterface;
|
||||
use League\CommonMark\Util\LinkParserHelper;
|
||||
|
||||
class EmbedStartParser implements BlockStartParserInterface
|
||||
{
|
||||
public function tryStart(Cursor $cursor, MarkdownParserStateInterface $parserState): ?BlockStart
|
||||
{
|
||||
if ($cursor->isIndented() || $parserState->getParagraphContent() !== null || ! ($parserState->getActiveBlockParser()->isContainer())) {
|
||||
return BlockStart::none();
|
||||
}
|
||||
|
||||
// 0-3 leading spaces are okay
|
||||
$cursor->advanceToNextNonSpaceOrTab();
|
||||
|
||||
// The line must begin with "https://"
|
||||
if (! str_starts_with($cursor->getRemainder(), 'https://')) {
|
||||
return BlockStart::none();
|
||||
}
|
||||
|
||||
// A valid link must be found next
|
||||
if (($dest = LinkParserHelper::parseLinkDestination($cursor)) === null) {
|
||||
return BlockStart::none();
|
||||
}
|
||||
|
||||
// Skip any trailing whitespace
|
||||
$cursor->advanceToNextNonSpaceOrTab();
|
||||
|
||||
// We must be at the end of the line; otherwise, this link was not by itself
|
||||
if (! $cursor->isAtEnd()) {
|
||||
return BlockStart::none();
|
||||
}
|
||||
|
||||
return BlockStart::of(new EmbedParser($dest))->at($cursor);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user