Full Code of aptoma/twig-markdown for AI

master 3729cc890049 cached
19 files
27.5 KB
7.7k tokens
58 symbols
1 requests
Download .txt
Repository: aptoma/twig-markdown
Branch: master
Commit: 3729cc890049
Files: 19
Total size: 27.5 KB

Directory structure:
gitextract_3um_xo79/

├── .github/
│   └── workflows/
│       └── test.yml
├── .gitignore
├── CHANGELOG.md
├── README.md
├── composer.json
├── phpunit.xml.dist
├── src/
│   └── Aptoma/
│       └── Twig/
│           ├── Extension/
│           │   ├── MarkdownEngine/
│           │   │   ├── GitHubMarkdownEngine.php
│           │   │   ├── MichelfMarkdownEngine.php
│           │   │   ├── PHPLeagueCommonMarkEngine.php
│           │   │   └── ParsedownEngine.php
│           │   ├── MarkdownEngineInterface.php
│           │   └── MarkdownExtension.php
│           ├── Node/
│           │   └── MarkdownNode.php
│           └── TokenParser/
│               └── MarkdownTokenParser.php
└── tests/
    └── Aptoma/
        └── Twig/
            ├── Extension/
            │   ├── MarkdownEngine/
            │   │   ├── GithubMarkdownEngineTest.php
            │   │   ├── PHPLeagueCommonMarkEngineTest.php
            │   │   └── ParsedownEngineTest.php
            │   └── MarkdownExtensionTest.php
            └── TokenParser/
                └── MarkdownTokenParserTest.php

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/test.yml
================================================
name: Test

on: [push, pull_request]

jobs:
  run:
    runs-on: 'ubuntu-latest'
    strategy:
      matrix:
        php-versions: ['7.2', '7.3', '7.4', '8.0']

    steps:
    - name: Checkout
      uses: actions/checkout@v2

    - name: Setup PHP
      uses: shivammathur/setup-php@v2
      with:
        php-version: ${{ matrix.php-versions }}
        coverage: xdebug

    - run: mkdir -p build/logs

    - name: Install composer dependencies
      uses: ramsey/composer-install@v1

    - name: Run Tests
      run: vendor/bin/phpunit


================================================
FILE: .gitignore
================================================
vendor
composer.phar
composer.lock
phpunit.xml
.phpunit.result.cache


================================================
FILE: CHANGELOG.md
================================================
CHANGELOG
=========

3.4.1
-----

- **Added**: Define implements \Twig\Extension\ExtensionInterface

3.4.0
-----

 - **Added**: PHP 8.0 compatibility
 - **Changed**: Migrate test suite from Travis to GitHub

3.3.1
-----

- **FIX**: Fix invalid cacheDir for GH engine on Windows

3.3.0
-----

- **Added**: Support for Twig 3

3.2.0

- **Added**: Support for HMTL escaping in ParsdownEngine

2.1.0
-----

- **FIX**: Upgrade to Twig 2.7 and namespace, due to [a security issue](https://symfony.com/blog/twig-sandbox-information-disclosure)

2.0.0
-----

- **BC**: Require Twig v1.12, in order to replace deprecated Twig_Filter_Method with Twig_SimpleFilter
- **Added**: Add support for ParsedownEngine

1.2.0
-----

- **Added**: Add support for GitHub's markdown engine

1.1.0
-----

- **Added**: Add support for PHP League CommonMark engine

1.0.0
-----

- **BC**: Remove deprecated dflydev-markdown parser


================================================
FILE: README.md
================================================
Twig Markdown Extension
=======================

[![Build Status](https://github.com/aptoma/twig-markdown/workflows/Test/badge.svg?branch=master)](https://github.com/aptoma/twig-markdown/actions?query=branch%3Amaster)

**THIS EXTENSION IS NO LONGER MAINTAINED, AND WE WILL NOT MAKE ANY NEW RELEASES. IF ANYONE WANTS TO TAKE OVER, PLEASE MAKE A FORK AND PUBLISH A NEW PACKAGE, AND WE'LL LINK TO THE NEW VERSION.**

Twig Markdown extension provides a new filter and a tag to allow parsing of
content as Markdown in [Twig][1] templates.

This extension could be integrated with several Markdown parser as it provides an interface, which allows you to customize your Markdown parser.

### Supported parsers

 * [michelf/php-markdown](https://github.com/michelf/php-markdown) (+ MarkdownExtra)
 * [league/commonmark](http://commonmark.thephpleague.com/)
 * [KnpLabs/php-github-api](https://github.com/KnpLabs/php-github-api)
 * [erusev/parsedown](https://github.com/erusev/parsedown)

## Features

 * Filter support `{{ "# Heading Level 1"|markdown }}`
 * Tag support `{% markdown %}{% endmarkdown %}`

When used as a tag, the indentation level of the first line sets the default indentation level for the rest of the tag content.
From this indentation level, all same indentation or outdented levels text will be transformed as regular text.

This feature allows you to write your Markdown content at any indentation level without caring of Markdown internal transformation:

```php
<div>
    <h1 class="someClass">{{ title }}</h1>

    {% markdown %}
    This is a list that is indented to match the context around the markdown tag:

    * List item 1
    * List item 2
        * Sub List Item
            * Sub Sub List Item

    The following block will be transformed as code, as it is indented more than the
    surrounding content:

        $code = "good";

    {% endmarkdown %}

</div>
```

## Installation

Run the composer command to install the latest stable version:

```bash
composer require aptoma/twig-markdown
```

Or update your `composer.json`:

```json
{
    "require": {
        "aptoma/twig-markdown": "~3.0"
    }
}
```

You can choose to provide your own Markdown engine, although we recommend
using [michelf/php-markdown](https://github.com/michelf/php-markdown):

```bash
composer require michelf/php-markdown ~1.8
```

```json
{
    "require": {
        "michelf/php-markdown": "~1.8"
    }
}
```

You may also use the [PHP League CommonMark engine](http://commonmark.thephpleague.com/):

```bash
composer require league/commonmark ~0.19
```

```json
{
    "require": {
        "league/commonmark": "~0.19"
    }
}
```

## Usage

### Twig Extension

The Twig extension provides the `markdown` tag and filter support.

Assuming that you are using [composer](http://getcomposer.org) autoloading,
add the extension to the Twig environment:

```php

use Aptoma\Twig\Extension\MarkdownExtension;
use Aptoma\Twig\Extension\MarkdownEngine;

$engine = new MarkdownEngine\MichelfMarkdownEngine();

$twig->addExtension(new MarkdownExtension($engine));
```

### Twig Token Parser

The Twig token parser provides the `markdown` tag only!

```php
use Aptoma\Twig\TokenParser\MarkdownTokenParser;

$twig->addTokenParser(new MarkdownTokenParser());
```

### Symfony

To use this extension in a [Symfony 3/4 app](https://symfony.com) (including [Pimcore](https://pimcore.com/)), add the following snippet to your app's `app/config/services.yml` file:

```yaml
services:
    # ...

    markdown.engine:
        class: Aptoma\Twig\Extension\MarkdownEngine\MichelfMarkdownEngine
    twig.markdown:
        class: Aptoma\Twig\Extension\MarkdownExtension
        arguments: ['@markdown.engine']
        tags:
            - { name: twig.extension }
```

### GitHub Markdown Engine

`MarkdownEngine\GitHubMarkdownEngine` provides an interface to GitHub's markdown engine using their public API via [`KnpLabs\php-github-api`][2]. To reduce API calls, rendered documents are hashed and cached in the filesystem. You can pass a GitHub repository and the path to be used for caching to the constructor:

```php
use Aptoma\Twig\Extension\MarkdownEngine;

$engine = new MarkdownEngine\GitHubMarkdownEngine(
    'aptoma/twig-markdown', // The GitHub repository to use as a context
    true,                   // Whether to use GitHub's Flavored Markdown (GFM)
    '/tmp/markdown-cache',  // Path on filesystem to store rendered documents
);
```

In order to authenticate the API client (for instance), it's possible to pass an own instance of `\GitHub\Client` instead of letting the engine create one itself:

```php
$client = new \Github\Client;
$client->authenticate('GITHUB_CLIENT_ID', 'GITHUB_CLIENT_SECRET', \Github\Client::AUTH_URL_CLIENT_ID);

$engine = new MarkdownEngine\GitHubMarkdownEngine('aptoma/twig-markdown', true, '/tmp/markdown-cache', $client);
```

### Using a different Markdown parser engine

If you want to use a different Markdown parser, you need to create an adapter
that implements `Aptoma\Twig\Extension\MarkdownEngineInterface.php`. Have
a look at `Aptoma\Twig\Extension\MarkdownEngine\MichelfMarkdownEngine` for an
example.

## Tests

The test suite uses PHPUnit:

    $ phpunit

## License

Twig Markdown Extension is licensed under the MIT license.

[1]: http://twig.sensiolabs.org
[2]: https://github.com/knplabs/php-github-api


================================================
FILE: composer.json
================================================
{
    "name": "aptoma/twig-markdown",
    "description": "Twig extension to work with Markdown content",
    "keywords": ["twig", "markdown"],
    "license": "MIT",
    "authors": [
        {
            "name": "Gunnar Lium",
            "email": "gunnar@aptoma.com"
        },
        {
            "name": "Joris Berthelot",
            "email": "joris@berthelot.tel"
        }
    ],
    "require": {
        "php": "^7.0|^8.0",
        "twig/twig": "^2.7.0|^3.0"
    },
    "require-dev": {
        "php": "^7.2.5|^8.0",
        "phpunit/phpunit": "~6.0|~5.0|~8.0",
        "michelf/php-markdown": "~1",
        "league/commonmark": "~0.5",
        "knplabs/github-api": "~3.0",
        "erusev/parsedown": "^1.6",
        "guzzlehttp/guzzle": "^7.2",
        "http-interop/http-factory-guzzle": "^1.0"
    },
    "suggest": {
        "michelf/php-markdown": "Original Markdown engine with MarkdownExtra.",
        "knplabs/github-api": "Needed for using GitHub's Markdown engine provided through their API."
    },
    "autoload": {
        "psr-0": { "Aptoma": "src/" }
    }
}


================================================
FILE: phpunit.xml.dist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false"
         bootstrap="vendor/autoload.php"
>
    <testsuites>
        <testsuite name="Aptoma Markdown Test Suite">
            <directory>./tests/</directory>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist>
            <directory>src/</directory>
        </whitelist>
    </filter>
</phpunit>


================================================
FILE: src/Aptoma/Twig/Extension/MarkdownEngine/GitHubMarkdownEngine.php
================================================
<?php
namespace Aptoma\Twig\Extension\MarkdownEngine;

use Aptoma\Twig\Extension\MarkdownEngineInterface;

/**
 * GithubMarkdownEngine.php
 *
 * Maps GitHub's Markdown engine API to Aptoma\Twig Markdown Extension using
 * KnpLabs\php-github-api.
 *
 * @author Lukas W <lukaswhl@gmail.com>
 */
class GitHubMarkdownEngine implements MarkdownEngineInterface
{
    /**
     * Constructor
     *
     * @param string $contextRepo The repository context. Pass a GitHub repo
     *        such as 'aptoma/twig-markdown' to render e.g. issues #23 in the
     *        context of the repo.
     * @param bool $gfm Whether to use GitHub's Flavored Markdown or the
     *        standard markdown. Default is true.
     * @param string $cacheDir Location on disk where rendered documents should
     *        be stored. Defaults to 'github-markdown-cache' folder in system
     *        temp directory if no path is provided.
     * @param \Github\Client $client Client object to use. A new Github\Client()
     *        object is constructed automatically if $client is null.
     */
    public function __construct($contextRepo = null, $gfm = true, $cacheDir = null, \GitHub\Client $client=null)
    {
        $this->repo = $contextRepo;
        $this->mode = $gfm ? 'gfm' : 'markdown';
        if (is_null($cacheDir)) {
            $cacheDir = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'github-markdown-cache';
        }
        $this->cacheDir = rtrim($cacheDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
        if (!is_dir($this->cacheDir)) {
            @mkdir($this->cacheDir, 0777, true);
        }

        if ($client === null) {
            $client = new \Github\Client();
        }
        $this->api = $client->api('markdown');
    }

    /**
     * {@inheritdoc}
     */
    public function transform($content)
    {
        $cacheFile = $this->getCachePath($content);
        if (file_exists($cacheFile)) {
            return file_get_contents($cacheFile);;
        }

        $response = $this->api->render($content, $this->mode, $this->repo);
        file_put_contents($cacheFile, $response);
        return $response;
    }

    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return 'KnpLabs\php-github-api';
    }

    private function getCachePath($content)
    {
        return $this->cacheDir . md5($content) . '_' . $this->mode. '_' . str_replace('/', '.', $this->repo);
    }

    private $api;
    private $cacheDir;
    private $repo;
    private $mode;
}


================================================
FILE: src/Aptoma/Twig/Extension/MarkdownEngine/MichelfMarkdownEngine.php
================================================
<?php

namespace Aptoma\Twig\Extension\MarkdownEngine;

use Aptoma\Twig\Extension\MarkdownEngineInterface;
use Michelf\MarkdownExtra;

/**
 * MichelfMarkdownEngine.php
 *
 * Maps Michelf\MarkdownExtra to Aptoma\Twig Markdown Extension
 *
 * @author Joris Berthelot <joris@berthelot.tel>
 */
class MichelfMarkdownEngine implements MarkdownEngineInterface
{
    /**
     * {@inheritdoc}
     */
    public function transform($content)
    {
        return MarkdownExtra::defaultTransform($content);
    }

    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return 'Michelf\Markdown';
    }
}


================================================
FILE: src/Aptoma/Twig/Extension/MarkdownEngine/PHPLeagueCommonMarkEngine.php
================================================
<?php

namespace Aptoma\Twig\Extension\MarkdownEngine;

use Aptoma\Twig\Extension\MarkdownEngineInterface;
use League\CommonMark\CommonMarkConverter;

/**
 * PHPLeagueCommonMarkEngine.php
 *
 * Maps League\CommonMark\CommonMarkConverter to Aptoma\Twig Markdown Extension
 *
 * @author Casey McLaughlin <caseyamcl@gmail.com>
 */
class PHPLeagueCommonMarkEngine implements MarkdownEngineInterface
{
    /**
     * @var \League\CommonMark\CommonMarkConverter
     */
    private $converter;

    /**
     * Constructor
     *
     * Accepts CommonMarkConverter or creates one automatically
     *
     * @param \League\CommonMark\CommonMarkConverter $converter
     */
    public function __construct(CommonMarkConverter $converter = null)
    {
        $this->converter = $converter ?: new CommonMarkConverter();
    }

    /**
     * {@inheritdoc}
     */
    public function transform($content)
    {
        return $this->converter->convertToHtml($content);
    }

    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return 'League\CommonMark';
    }
}


================================================
FILE: src/Aptoma/Twig/Extension/MarkdownEngine/ParsedownEngine.php
================================================
<?php

namespace Aptoma\Twig\Extension\MarkdownEngine;

use Aptoma\Twig\Extension\MarkdownEngineInterface;
use Parsedown;

/**
 * ParsedownEngine.php
 *
 * Maps erusev/parsedown to Aptoma\Twig Markdown Extension
 *
 * @author Sébastien Lourseau <https://github.com/SebLours>
 */
class ParsedownEngine implements MarkdownEngineInterface
{
    /**
     * @var Parsedown
     */
    protected $engine;

    /**
     * @param string|null $instanceName
     */
    public function __construct($instanceName = null)
    {
        $this->engine = Parsedown::instance($instanceName);
    }

    /**
     * {@inheritdoc}
     */
    public function transform($content)
    {
        return $this->engine->parse($content);
    }

    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return 'erusev/parsedown';
    }
    
    /**
     * Turn on/off escaping within the generated HTML. Should be
     * turned on for untrusted user input.
     *
     * @param bool $bool Flag to set Safe Mode to
     */
    public function setSafeMode($bool)
    {
        $this->engine->setSafeMode($bool === true);
    }
    
    /**
     * Turn on/off escaping HTML in trusted user input.
     *
     * @param bool $bool Flag to set markup escaped to
     */
    public function setMarkupEscaped($bool)
    {
        $this->engine->setMarkupEscaped($bool === true);
    }
}


================================================
FILE: src/Aptoma/Twig/Extension/MarkdownEngineInterface.php
================================================
<?php

namespace Aptoma\Twig\Extension;

/**
 * MarkdownEngineInterface.php
 *
 * Provide software interface to maps various Markdown engines
 *
 * @author Joris Berthelot <joris@berthelot.tel>
 */
interface MarkdownEngineInterface
{
    /**
     * Transforms the given markdown data in HTML
     *
     * @param string $content Markdown data
     * @return string
     */
    public function transform($content);

    /**
     * Return Markdown engine vendor ID
     *
     * @return string
     */
    public function getName();
}


================================================
FILE: src/Aptoma/Twig/Extension/MarkdownExtension.php
================================================
<?php

namespace Aptoma\Twig\Extension;

use Aptoma\Twig\TokenParser\MarkdownTokenParser;

/**
 * MarkdownExtension provides support for Markdown.
 *
 * @author Gunnar Lium <gunnar@aptoma.com>
 * @author Joris Berthelot <joris@berthelot.tel>
 */
class MarkdownExtension extends \Twig\Extension\AbstractExtension implements \Twig\Extension\ExtensionInterface
{

    /**
     * @var MarkdownEngineInterface $markdownEngine
     */
    private $markdownEngine;

    /**
     * @param MarkdownEngineInterface $markdownEngine The Markdown parser engine
     */
    public function __construct(MarkdownEngineInterface $markdownEngine)
    {
        $this->markdownEngine = $markdownEngine;
    }

    /**
     * {@inheritdoc}
     */
    public function getFilters()
    {
        return array(
            new \Twig\TwigFilter(
                'markdown',
                array($this, 'parseMarkdown'),
                array('is_safe' => array('html'))
            )
        );
    }

    /**
     * Transform Markdown content to HTML
     *
     * @param string $content The Markdown content to be transformed
     * @return string The result of the Markdown engine transformation
     */
    public function parseMarkdown($content)
    {
        return $this->markdownEngine->transform($content);
    }

    /**
     * {@inheritdoc}
     */
    public function getTokenParsers()
    {
        return array(new MarkdownTokenParser());
    }
}


================================================
FILE: src/Aptoma/Twig/Node/MarkdownNode.php
================================================
<?php

namespace Aptoma\Twig\Node;

/**
 * Represents a markdown node.
 *
 * It parses content as Markdown.
 *
 * @author Gunnar Lium <gunnar@aptoma.com>
 * @author Joris Berthelot <joris@berthelot.tel>
 */
class MarkdownNode extends \Twig\Node\Node
{
    public function __construct(\Twig\Node\Node $body, $lineno, $tag = 'markdown')
    {
        parent::__construct(array('body' => $body), array(), $lineno, $tag);
    }

    /**
     * Compiles the node to PHP.
     *
     * @param \Twig\Compiler A Twig\Compiler instance
     */
    public function compile(\Twig\Compiler $compiler)
    {
        $compiler
            ->addDebugInfo($this)
            ->write('ob_start();' . PHP_EOL)
            ->subcompile($this->getNode('body'))
            ->write('$content = ob_get_clean();' . PHP_EOL)
            ->write('preg_match("/^\s*/", $content, $matches);' . PHP_EOL)
            ->write('$lines = explode("\n", $content);' . PHP_EOL)
            ->write('$content = preg_replace(\'/^\' . $matches[0]. \'/\', "", $lines);' . PHP_EOL)
            ->write('$content = join("\n", $content);' . PHP_EOL)
            ->write('echo $this->env->getExtension(\'Aptoma\Twig\Extension\MarkdownExtension\')->parseMarkdown($content);' . PHP_EOL);
    }
}


================================================
FILE: src/Aptoma/Twig/TokenParser/MarkdownTokenParser.php
================================================
<?php

namespace Aptoma\Twig\TokenParser;

use Aptoma\Twig\Node\MarkdownNode;

/**
 * @author Gunnar Lium <gunnar@aptoma.com>
 * @author Joris Berthelot <joris@berthelot.tel>
 */
class MarkdownTokenParser extends \Twig\TokenParser\AbstractTokenParser
{
    /**
     * {@inheritdoc}
     */
    public function parse(\Twig\Token $token)
    {
        $lineno = $token->getLine();

        $this->parser->getStream()->expect(\Twig\Token::BLOCK_END_TYPE);
        $body = $this->parser->subparse(array($this, 'decideMarkdownEnd'), true);
        $this->parser->getStream()->expect(\Twig\Token::BLOCK_END_TYPE);

        return new MarkdownNode($body, $lineno, $this->getTag());
    }

    /**
     * Decide if current token marks end of Markdown block.
     *
     * @param \Twig\Token $token
     * @return bool
     */
    public function decideMarkdownEnd(\Twig\Token $token)
    {
        return $token->test('endmarkdown');
    }

    /**
     * {@inheritdoc}
     */
    public function getTag()
    {
        return 'markdown';
    }
}


================================================
FILE: tests/Aptoma/Twig/Extension/MarkdownEngine/GithubMarkdownEngineTest.php
================================================
<?php

namespace Aptoma\Twig\Extension\MarkdownEngine;

use Aptoma\Twig\Extension\MarkdownExtensionTest;
use Github\Client;

require_once(__DIR__ . '/../MarkdownExtensionTest.php');

/**
 * Class GitHubMarkdownEngineTest
 *
 * @author Lukas W <lukaswhl@gmail.com>
 */
class GitHubMarkdownEngineTest extends MarkdownExtensionTest
{
    /**
     * @dataProvider getParseMarkdownTests
     */
    public function testParseMarkdown($template, $expected, $context = array())
    {
        try {
           $this->assertEquals($expected, $this->getTemplate($template)->render($context));
        } catch (\Exception $e) {
            $this->markTestSkipped($e->getMessage());
        }
    }

    public function getParseMarkdownTests()
    {
        return array(
            array('{{ "# Main Title"|markdown }}', '<h1>Main Title</h1>'),
            array('{{ content|markdown }}', '<h1>Main Title</h1>', array('content' => '# Main Title')),
            // Check if GFM is working
            array('{{ "@aptoma"|markdown }}',
                  '<p><a href="https://github.com/aptoma" class="user-mention">@aptoma</a></p>'),
        );
    }

    protected function getEngine()
    {
        $client = new Client();

        if ($client->rateLimit()->getResource('core')->getLimit() < 1) {
            $this->markTestSkipped('The github API rate limit is reached, so this engine cannot be tested.');
        }

        return new GitHubMarkdownEngine();
    }
}


================================================
FILE: tests/Aptoma/Twig/Extension/MarkdownEngine/PHPLeagueCommonMarkEngineTest.php
================================================
<?php

namespace Aptoma\Twig\Extension\MarkdownEngine;

use Aptoma\Twig\Extension\MarkdownExtensionTest;

// Require parent class if not autoloaded
if (!class_exists('\Aptoma\Twig\Extension\MarkdownExtensionTest')) {
    require_once(__DIR__ . '/../MarkdownExtensionTest.php');
}

/**
 * Class PHPLeagueCommonMarkEngineTest
 *
 * @author Casey McLaughlin <caseyamcl@gmail.com>
 */
class PHPLeagueCommonMarkEngineTest extends MarkdownExtensionTest
{
    protected function getEngine()
    {
        return new PHPLeagueCommonMarkEngine();
    }
}


================================================
FILE: tests/Aptoma/Twig/Extension/MarkdownEngine/ParsedownEngineTest.php
================================================
<?php

namespace Aptoma\Twig\Extension\MarkdownEngine;

use Aptoma\Twig\Extension\MarkdownExtension;
use Aptoma\Twig\Extension\MarkdownExtensionTest;

// Require parent class if not autoloaded
if (!class_exists('\Aptoma\Twig\Extension\MarkdownExtensionTest')) {
    require_once(__DIR__ . '/../MarkdownExtensionTest.php');
}

/**
 * Class ParsedownEngineTest
 *
 * @author Sébastien Lourseau <https://github.com/SebLours>
 */
class ParsedownEngineTest extends MarkdownExtensionTest
{
    public function getParseMarkdownTests()
    {
        return array(
            array('{{ "# Main Title"|markdown }}', '<h1>Main Title</h1>'),
            array('{{ content|markdown }}', '<h1>Main Title</h1>', array('content' => '# Main Title')),
            array('{% markdown %}{{ content }}{% endmarkdown %}', '<h1>Main Title</h1>', array('content' => '# Main Title'))
        );
    }

    protected function getEngine()
    {
        return new ParsedownEngine();
    }

    public function testSafeMode()
    {
        $engine = $this->getEngine();
        $loader = new \Twig\Loader\ArrayLoader(array('index' => '{{ "_Test_<em>Test</em>[xss](javascript:alert%281%29)"|markdown }}'));
        $twig = new \Twig\Environment($loader, array('debug' => true, 'cache' => false));
        $twig->addExtension(new MarkdownExtension($engine));

        $this->assertEquals('<p><em>Test</em><em>Test</em><a href="javascript:alert%281%29">xss</a></p>', $twig->load('index')->render());

        $engine->setSafeMode(true);
        $this->assertEquals('<p><em>Test</em>&lt;em&gt;Test&lt;/em&gt;<a href="javascript%3Aalert%281%29">xss</a></p>', $twig->load('index')->render());
        $engine->setSafeMode(false);
    }

    public function testMarkupEscape()
    {
        $engine = $this->getEngine();
        $loader = new \Twig\Loader\ArrayLoader(array('index' => '{{ "_Test_<em>Test</em>[xss](javascript:alert%281%29)"|markdown }}'));
        $twig = new \Twig\Environment($loader, array('debug' => true, 'cache' => false));
        $twig->addExtension(new MarkdownExtension($engine));

        $this->assertEquals('<p><em>Test</em><em>Test</em><a href="javascript:alert%281%29">xss</a></p>', $twig->load('index')->render());

        $engine->setMarkupEscaped(true);
        $this->assertEquals('<p><em>Test</em>&lt;em&gt;Test&lt;/em&gt;<a href="javascript:alert%281%29">xss</a></p>', $twig->load('index')->render());        
        $engine->setMarkupEscaped(false);
    }
}


================================================
FILE: tests/Aptoma/Twig/Extension/MarkdownExtensionTest.php
================================================
<?php

namespace Aptoma\Twig\Extension;

use Aptoma\Twig\Extension\MarkdownEngine\MichelfMarkdownEngine;
use PHPUnit\Framework\TestCase;

/**
 * @author Gunnar Liun <gunnar@aptoma.com>
 */
class MarkdownExtensionTest extends TestCase
{
    /**
     * @dataProvider getParseMarkdownTests
     */
    public function testParseMarkdown($template, $expected, $context = array())
    {
        $this->assertEquals($expected, $this->getTemplate($template)->render($context));
    }

    public function getParseMarkdownTests()
    {
        return array(
            array('{{ "# Main Title"|markdown }}', '<h1>Main Title</h1>' . PHP_EOL),
            array('{{ content|markdown }}', '<h1>Main Title</h1>' . PHP_EOL, array('content' => '# Main Title'))
        );
    }

    protected function getEngine()
    {
        return new MichelfMarkdownEngine();
    }

    protected function getTemplate($template)
    {
        $loader = new \Twig\Loader\ArrayLoader(array('index' => $template));
        $twig = new \Twig\Environment($loader, array('debug' => true, 'cache' => false));
        $twig->addExtension(new MarkdownExtension($this->getEngine()));

        return $twig->load('index');
    }
}


================================================
FILE: tests/Aptoma/Twig/TokenParser/MarkdownTokenParserTest.php
================================================
<?php

namespace Aptoma\Twig\TokenParser;

use Aptoma\Twig\Extension\MarkdownEngine\MichelfMarkdownEngine;
use Aptoma\Twig\Node\MarkdownNode;
use PHPUnit\Framework\TestCase;
use Twig\Compiler;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
use Twig\Node\Node;
use Twig\Node\TextNode;

/**
 * @author Gunnar Lium <gunnar@aptoma.com>
 */
class MarkdownTokenParserTest extends TestCase
{
    public function testConstructor()
    {
        $body = new Node(array(new TextNode("#Title\n\nparagraph\n", 1)));
        $node = new MarkdownNode($body, 1);

        $this->assertEquals($body, $node->getNode('body'));
    }

    /**
     * Test that the generated code actually do what we expect
     *
     * The contents of this test is the same that we write in the compile method.
     * This requires manual synchronization, which we should probably not rely on.
     */
    public function testMarkdownPrepareBehavior()
    {
        $body = "    #Title\n\n    paragraph\n\n        code";
        $bodyPrepared = "#Title\n\nparagraph\n\n    code";

        ob_start();
        echo $body;
        $content = ob_get_clean();
        preg_match("/^\s*/", $content, $matches);
        $lines = explode("\n", $content);
        $content = preg_replace('/^' . $matches[0]. '/', "", $lines);
        $content = join("\n", $content);

        // Assert prepared content looks right
        $this->assertEquals($bodyPrepared, $content);

        // Assert Markdown output
        $expectedOutput = "<h1>Title</h1>\n\n<p>paragraph</p>\n\n<pre><code>code\n</code></pre>\n";
        $this->assertEquals($expectedOutput, $this->getEngine()->transform($content));
    }

    /**
     * Test that the generated code looks as expected
     *
     * @dataProvider getTests
     */
    public function testCompile($node, $source, $environment = null, $isPattern = false)
    {
        $this->assertNodeCompilation($source, $node, $environment, $isPattern = false);
    }

    protected function getEngine()
    {
        return new MichelfMarkdownEngine();
    }

    public function getTests()
    {
        $tests = array();

        $body = new Node(array(new TextNode("#Title\n\nparagraph\n", 1)));
        $node = new MarkdownNode($body, 1);

        $tests['simple text'] = array($node, <<<EOF
// line 1
ob_start();
echo "#Title

paragraph
";
\$content = ob_get_clean();
preg_match("/^\s*/", \$content, \$matches);
\$lines = explode("\\n", \$content);
\$content = preg_replace('/^' . \$matches[0]. '/', "", \$lines);
\$content = join("\\n", \$content);
echo \$this->env->getExtension('Aptoma\Twig\Extension\MarkdownExtension')->parseMarkdown(\$content);
EOF
            );

        $body = new Node(array(new TextNode("    #Title\n\n    paragraph\n\n        code\n", 1)));
        $node = new MarkdownNode($body, 1);

        $tests['text with leading indent'] = array($node, <<<EOF
// line 1
ob_start();
echo "    #Title

    paragraph

        code
";
\$content = ob_get_clean();
preg_match("/^\s*/", \$content, \$matches);
\$lines = explode("\\n", \$content);
\$content = preg_replace('/^' . \$matches[0]. '/', "", \$lines);
\$content = join("\\n", \$content);
echo \$this->env->getExtension('Aptoma\Twig\Extension\MarkdownExtension')->parseMarkdown(\$content);
EOF
        );

        return $tests;
    }

    public function assertNodeCompilation($source, Node $node, Environment $environment = null, $isPattern = false)
    {
        $compiler = $this->getCompiler($environment);
        $compiler->compile($node);

        if ($isPattern) {
            $this->assertStringMatchesFormat($source, trim($compiler->getSource()));
        } else {
            $this->assertEquals($source, trim($compiler->getSource()));
        }
    }

    protected function getCompiler(Environment $environment = null)
    {
        return new Compiler(null === $environment ? $this->getEnvironment() : $environment);
    }

    protected function getEnvironment()
    {
        return new Environment(new ArrayLoader(array()));
    }
}
Download .txt
gitextract_3um_xo79/

├── .github/
│   └── workflows/
│       └── test.yml
├── .gitignore
├── CHANGELOG.md
├── README.md
├── composer.json
├── phpunit.xml.dist
├── src/
│   └── Aptoma/
│       └── Twig/
│           ├── Extension/
│           │   ├── MarkdownEngine/
│           │   │   ├── GitHubMarkdownEngine.php
│           │   │   ├── MichelfMarkdownEngine.php
│           │   │   ├── PHPLeagueCommonMarkEngine.php
│           │   │   └── ParsedownEngine.php
│           │   ├── MarkdownEngineInterface.php
│           │   └── MarkdownExtension.php
│           ├── Node/
│           │   └── MarkdownNode.php
│           └── TokenParser/
│               └── MarkdownTokenParser.php
└── tests/
    └── Aptoma/
        └── Twig/
            ├── Extension/
            │   ├── MarkdownEngine/
            │   │   ├── GithubMarkdownEngineTest.php
            │   │   ├── PHPLeagueCommonMarkEngineTest.php
            │   │   └── ParsedownEngineTest.php
            │   └── MarkdownExtensionTest.php
            └── TokenParser/
                └── MarkdownTokenParserTest.php
Download .txt
SYMBOL INDEX (58 symbols across 13 files)

FILE: src/Aptoma/Twig/Extension/MarkdownEngine/GitHubMarkdownEngine.php
  class GitHubMarkdownEngine (line 14) | class GitHubMarkdownEngine implements MarkdownEngineInterface
    method __construct (line 30) | public function __construct($contextRepo = null, $gfm = true, $cacheDi...
    method transform (line 51) | public function transform($content)
    method getName (line 66) | public function getName()
    method getCachePath (line 71) | private function getCachePath($content)

FILE: src/Aptoma/Twig/Extension/MarkdownEngine/MichelfMarkdownEngine.php
  class MichelfMarkdownEngine (line 15) | class MichelfMarkdownEngine implements MarkdownEngineInterface
    method transform (line 20) | public function transform($content)
    method getName (line 28) | public function getName()

FILE: src/Aptoma/Twig/Extension/MarkdownEngine/PHPLeagueCommonMarkEngine.php
  class PHPLeagueCommonMarkEngine (line 15) | class PHPLeagueCommonMarkEngine implements MarkdownEngineInterface
    method __construct (line 29) | public function __construct(CommonMarkConverter $converter = null)
    method transform (line 37) | public function transform($content)
    method getName (line 45) | public function getName()

FILE: src/Aptoma/Twig/Extension/MarkdownEngine/ParsedownEngine.php
  class ParsedownEngine (line 15) | class ParsedownEngine implements MarkdownEngineInterface
    method __construct (line 25) | public function __construct($instanceName = null)
    method transform (line 33) | public function transform($content)
    method getName (line 41) | public function getName()
    method setSafeMode (line 52) | public function setSafeMode($bool)
    method setMarkupEscaped (line 62) | public function setMarkupEscaped($bool)

FILE: src/Aptoma/Twig/Extension/MarkdownEngineInterface.php
  type MarkdownEngineInterface (line 12) | interface MarkdownEngineInterface
    method transform (line 20) | public function transform($content);
    method getName (line 27) | public function getName();

FILE: src/Aptoma/Twig/Extension/MarkdownExtension.php
  class MarkdownExtension (line 13) | class MarkdownExtension extends \Twig\Extension\AbstractExtension implem...
    method __construct (line 24) | public function __construct(MarkdownEngineInterface $markdownEngine)
    method getFilters (line 32) | public function getFilters()
    method parseMarkdown (line 49) | public function parseMarkdown($content)
    method getTokenParsers (line 57) | public function getTokenParsers()

FILE: src/Aptoma/Twig/Node/MarkdownNode.php
  class MarkdownNode (line 13) | class MarkdownNode extends \Twig\Node\Node
    method __construct (line 15) | public function __construct(\Twig\Node\Node $body, $lineno, $tag = 'ma...
    method compile (line 25) | public function compile(\Twig\Compiler $compiler)

FILE: src/Aptoma/Twig/TokenParser/MarkdownTokenParser.php
  class MarkdownTokenParser (line 11) | class MarkdownTokenParser extends \Twig\TokenParser\AbstractTokenParser
    method parse (line 16) | public function parse(\Twig\Token $token)
    method decideMarkdownEnd (line 33) | public function decideMarkdownEnd(\Twig\Token $token)
    method getTag (line 41) | public function getTag()

FILE: tests/Aptoma/Twig/Extension/MarkdownEngine/GithubMarkdownEngineTest.php
  class GitHubMarkdownEngineTest (line 15) | class GitHubMarkdownEngineTest extends MarkdownExtensionTest
    method testParseMarkdown (line 20) | public function testParseMarkdown($template, $expected, $context = arr...
    method getParseMarkdownTests (line 29) | public function getParseMarkdownTests()
    method getEngine (line 40) | protected function getEngine()

FILE: tests/Aptoma/Twig/Extension/MarkdownEngine/PHPLeagueCommonMarkEngineTest.php
  class PHPLeagueCommonMarkEngineTest (line 17) | class PHPLeagueCommonMarkEngineTest extends MarkdownExtensionTest
    method getEngine (line 19) | protected function getEngine()

FILE: tests/Aptoma/Twig/Extension/MarkdownEngine/ParsedownEngineTest.php
  class ParsedownEngineTest (line 18) | class ParsedownEngineTest extends MarkdownExtensionTest
    method getParseMarkdownTests (line 20) | public function getParseMarkdownTests()
    method getEngine (line 29) | protected function getEngine()
    method testSafeMode (line 34) | public function testSafeMode()
    method testMarkupEscape (line 48) | public function testMarkupEscape()

FILE: tests/Aptoma/Twig/Extension/MarkdownExtensionTest.php
  class MarkdownExtensionTest (line 11) | class MarkdownExtensionTest extends TestCase
    method testParseMarkdown (line 16) | public function testParseMarkdown($template, $expected, $context = arr...
    method getParseMarkdownTests (line 21) | public function getParseMarkdownTests()
    method getEngine (line 29) | protected function getEngine()
    method getTemplate (line 34) | protected function getTemplate($template)

FILE: tests/Aptoma/Twig/TokenParser/MarkdownTokenParserTest.php
  class MarkdownTokenParserTest (line 17) | class MarkdownTokenParserTest extends TestCase
    method testConstructor (line 19) | public function testConstructor()
    method testMarkdownPrepareBehavior (line 33) | public function testMarkdownPrepareBehavior()
    method testCompile (line 59) | public function testCompile($node, $source, $environment = null, $isPa...
    method getEngine (line 64) | protected function getEngine()
    method getTests (line 69) | public function getTests()
    method assertNodeCompilation (line 116) | public function assertNodeCompilation($source, Node $node, Environment...
    method getCompiler (line 128) | protected function getCompiler(Environment $environment = null)
    method getEnvironment (line 133) | protected function getEnvironment()
Condensed preview — 19 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (31K chars).
[
  {
    "path": ".github/workflows/test.yml",
    "chars": 537,
    "preview": "name: Test\n\non: [push, pull_request]\n\njobs:\n  run:\n    runs-on: 'ubuntu-latest'\n    strategy:\n      matrix:\n        php-"
  },
  {
    "path": ".gitignore",
    "chars": 69,
    "preview": "vendor\ncomposer.phar\ncomposer.lock\nphpunit.xml\n.phpunit.result.cache\n"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 905,
    "preview": "CHANGELOG\n=========\n\n3.4.1\n-----\n\n- **Added**: Define implements \\Twig\\Extension\\ExtensionInterface\n\n3.4.0\n-----\n\n - **A"
  },
  {
    "path": "README.md",
    "chars": 5353,
    "preview": "Twig Markdown Extension\n=======================\n\n[![Build Status](https://github.com/aptoma/twig-markdown/workflows/Test"
  },
  {
    "path": "composer.json",
    "chars": 1085,
    "preview": "{\n    \"name\": \"aptoma/twig-markdown\",\n    \"description\": \"Twig extension to work with Markdown content\",\n    \"keywords\":"
  },
  {
    "path": "phpunit.xml.dist",
    "chars": 643,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit backupGlobals=\"false\"\n         backupStaticAttributes=\"false\"\n         c"
  },
  {
    "path": "src/Aptoma/Twig/Extension/MarkdownEngine/GitHubMarkdownEngine.php",
    "chars": 2505,
    "preview": "<?php\nnamespace Aptoma\\Twig\\Extension\\MarkdownEngine;\n\nuse Aptoma\\Twig\\Extension\\MarkdownEngineInterface;\n\n/**\n * Github"
  },
  {
    "path": "src/Aptoma/Twig/Extension/MarkdownEngine/MichelfMarkdownEngine.php",
    "chars": 620,
    "preview": "<?php\n\nnamespace Aptoma\\Twig\\Extension\\MarkdownEngine;\n\nuse Aptoma\\Twig\\Extension\\MarkdownEngineInterface;\nuse Michelf\\M"
  },
  {
    "path": "src/Aptoma/Twig/Extension/MarkdownEngine/PHPLeagueCommonMarkEngine.php",
    "chars": 1083,
    "preview": "<?php\n\nnamespace Aptoma\\Twig\\Extension\\MarkdownEngine;\n\nuse Aptoma\\Twig\\Extension\\MarkdownEngineInterface;\nuse League\\Co"
  },
  {
    "path": "src/Aptoma/Twig/Extension/MarkdownEngine/ParsedownEngine.php",
    "chars": 1377,
    "preview": "<?php\n\nnamespace Aptoma\\Twig\\Extension\\MarkdownEngine;\n\nuse Aptoma\\Twig\\Extension\\MarkdownEngineInterface;\nuse Parsedown"
  },
  {
    "path": "src/Aptoma/Twig/Extension/MarkdownEngineInterface.php",
    "chars": 533,
    "preview": "<?php\n\nnamespace Aptoma\\Twig\\Extension;\n\n/**\n * MarkdownEngineInterface.php\n *\n * Provide software interface to maps var"
  },
  {
    "path": "src/Aptoma/Twig/Extension/MarkdownExtension.php",
    "chars": 1439,
    "preview": "<?php\n\nnamespace Aptoma\\Twig\\Extension;\n\nuse Aptoma\\Twig\\TokenParser\\MarkdownTokenParser;\n\n/**\n * MarkdownExtension prov"
  },
  {
    "path": "src/Aptoma/Twig/Node/MarkdownNode.php",
    "chars": 1251,
    "preview": "<?php\n\nnamespace Aptoma\\Twig\\Node;\n\n/**\n * Represents a markdown node.\n *\n * It parses content as Markdown.\n *\n * @autho"
  },
  {
    "path": "src/Aptoma/Twig/TokenParser/MarkdownTokenParser.php",
    "chars": 1040,
    "preview": "<?php\n\nnamespace Aptoma\\Twig\\TokenParser;\n\nuse Aptoma\\Twig\\Node\\MarkdownNode;\n\n/**\n * @author Gunnar Lium <gunnar@aptoma"
  },
  {
    "path": "tests/Aptoma/Twig/Extension/MarkdownEngine/GithubMarkdownEngineTest.php",
    "chars": 1458,
    "preview": "<?php\n\nnamespace Aptoma\\Twig\\Extension\\MarkdownEngine;\n\nuse Aptoma\\Twig\\Extension\\MarkdownExtensionTest;\nuse Github\\Clie"
  },
  {
    "path": "tests/Aptoma/Twig/Extension/MarkdownEngine/PHPLeagueCommonMarkEngineTest.php",
    "chars": 546,
    "preview": "<?php\n\nnamespace Aptoma\\Twig\\Extension\\MarkdownEngine;\n\nuse Aptoma\\Twig\\Extension\\MarkdownExtensionTest;\n\n// Require par"
  },
  {
    "path": "tests/Aptoma/Twig/Extension/MarkdownEngine/ParsedownEngineTest.php",
    "chars": 2465,
    "preview": "<?php\n\nnamespace Aptoma\\Twig\\Extension\\MarkdownEngine;\n\nuse Aptoma\\Twig\\Extension\\MarkdownExtension;\nuse Aptoma\\Twig\\Ext"
  },
  {
    "path": "tests/Aptoma/Twig/Extension/MarkdownExtensionTest.php",
    "chars": 1194,
    "preview": "<?php\n\nnamespace Aptoma\\Twig\\Extension;\n\nuse Aptoma\\Twig\\Extension\\MarkdownEngine\\MichelfMarkdownEngine;\nuse PHPUnit\\Fra"
  },
  {
    "path": "tests/Aptoma/Twig/TokenParser/MarkdownTokenParserTest.php",
    "chars": 4016,
    "preview": "<?php\n\nnamespace Aptoma\\Twig\\TokenParser;\n\nuse Aptoma\\Twig\\Extension\\MarkdownEngine\\MichelfMarkdownEngine;\nuse Aptoma\\Tw"
  }
]

About this extraction

This page contains the full source code of the aptoma/twig-markdown GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 19 files (27.5 KB), approximately 7.7k tokens, and a symbol index with 58 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!