Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions .docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Extra contribution to [`nette/latte`](https://github.com/nette/latte).
- [Setup](#setup)
- [VersionExtension - revision macros for assets](#versions-extension)
- [CdnExtension - CDN support for assets](#cdn-extension)
- [ParsedownExtension - markdown parsing support](#parsedown-extension)
- [FiltersExtension - install filters easily](#filters-extension)
- [RuntimeFilters - collection of prepared filters](#runtimefilters)
- [Formatters - collection of prepared formatters](#formatters)
Expand Down Expand Up @@ -92,6 +93,59 @@ cdn:
https://cdn.example.com/assets/style.css?time=123456789
```

## Parsedown Extension

This extension provides markdown parsing support via the `|parsedown` filter using [ParsedownExtra](https://github.com/erusev/parsedown-extra).

### Requirements

The `erusev/parsedown-extra` package is an optional dependency. Install it first:

```bash
composer require erusev/parsedown-extra
```

### Install

```neon
extensions:
parsedown: Contributte\Latte\DI\ParsedownExtension
```

### Configuration

```neon
parsedown:
filter: parsedown # default filter name, can be changed to e.g. "markdown"
```

### Usage

```latte
{* Filter syntax *}
{$markdownContent|parsedown}

{* Block syntax *}
{block|parsedown}
# Hello World

This is **markdown** content.
{/block}
```

### Advanced Usage

You can use the `ParsedownExtraAdapter` directly with callbacks for custom processing:

```php
use Contributte\Latte\Filters\ParsedownExtraAdapter;

$adapter = $container->getByType(ParsedownExtraAdapter::class);
$adapter->onProcess[] = function (string $text, ParsedownExtraAdapter $adapter): void {
// Custom processing before markdown parsing
};
```

## Filters Extension

Install filters by single extension and simple `FiltersProvider` implementation.
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/codesniffer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ jobs:
name: "Codesniffer"
uses: contributte/.github/.github/workflows/codesniffer.yml@master
with:
php: "8.2"
php: "8.3"
2 changes: 1 addition & 1 deletion .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ jobs:
name: "Nette Tester"
uses: contributte/.github/.github/workflows/nette-tester-coverage-v2.yml@master
with:
php: "8.2"
php: "8.3"
2 changes: 1 addition & 1 deletion .github/workflows/phpstan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ jobs:
name: "Phpstan"
uses: contributte/.github/.github/workflows/phpstan.yml@master
with:
php: "8.2"
php: "8.3"
15 changes: 5 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,31 +1,26 @@
.PHONY: install
.PHONY: install qa cs csf phpstan tests coverage

install:
composer update

.PHONY: qa
qa: phpstan cs

.PHONY: cs
cs:
ifdef GITHUB_ACTION
vendor/bin/phpcs --standard=ruleset.xml --encoding=utf-8 --extensions="php,phpt" --colors -nsp -q --report=checkstyle src tests | cs2pr
vendor/bin/phpcs --standard=ruleset.xml --encoding=utf-8 --colors -nsp --extensions=php,phpt -q --report=checkstyle src tests | cs2pr
else
vendor/bin/phpcs --standard=ruleset.xml --encoding=utf-8 --extensions="php,phpt" --colors -nsp src tests
vendor/bin/phpcs --standard=ruleset.xml --encoding=utf-8 --colors -nsp --extensions=php,phpt src tests
endif

.PHONY: csf
csf:
vendor/bin/phpcbf --standard=ruleset.xml --encoding=utf-8 --extensions="php,phpt" --colors -nsp src tests
vendor/bin/phpcbf --standard=ruleset.xml --encoding=utf-8 --colors -nsp --extensions=php,phpt src tests

.PHONY: phpstan
phpstan:
vendor/bin/phpstan analyse -c phpstan.neon

.PHONY: tests
tests:
vendor/bin/tester -s -p php --colors 1 -C tests/Cases

.PHONY: coverage
coverage:
ifdef GITHUB_ACTION
vendor/bin/tester -s -p phpdbg --colors 1 -C --coverage coverage.xml --coverage-src src tests/Cases
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ For details on how to use this package, check out our [documentation](.docs).

## Versions

| State | Version | Branch | Nette | PHP |
|-------------|---------|----------|-------|----------|
| dev | `^0.7` | `master` | 3.2+ | `>=8.1+` |
| stable | `^0.6` | `master` | 3.2+ | `>=8.1+` |
| State | Version | Branch | Nette | PHP |
|-------------|---------|----------|-------|---------|
| dev | `^0.7` | `master` | 3.2+ | `>=8.2` |
| stable | `^0.6` | `master` | 3.2+ | `>=8.1` |

## Development

Expand Down
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
],
"require": {
"php": ">=8.2",
"latte/latte": "^3.0.12"
"latte/latte": "^3.1.0"
},
"require-dev": {
"nette/application": "^3.1.14",
Expand All @@ -27,7 +27,8 @@
"contributte/phpstan": "^0.1"
},
"suggest": {
"nette/di": "to use VersionExtension[CompilerExtension]"
"nette/di": "to use VersionExtension[CompilerExtension]",
"erusev/parsedown-extra": "to use ParsedownExtension[CompilerExtension]"
},
"autoload": {
"psr-4": {
Expand Down
6 changes: 5 additions & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ includes:

parameters:
level: 9
phpVersion: 80100
phpVersion: 80200

scanDirectories:
- src
Expand All @@ -16,3 +16,7 @@ parameters:
- .docs

ignoreErrors:
# ParsedownExtra is an optional dependency
- '#unknown class ParsedownExtra#i'
- '#invalid type ParsedownExtra#i'
- '#Instantiated class ParsedownExtra not found#'
2 changes: 1 addition & 1 deletion ruleset.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ruleset name="Contributte" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="vendor/squizlabs/php_codesniffer/phpcs.xsd">
<!-- Rulesets -->
<rule ref="./vendor/contributte/qa/ruleset-8.0.xml"/>
<rule ref="./vendor/contributte/qa/ruleset-8.2.xml"/>

<!-- Rules -->
<rule ref="SlevomatCodingStandard.Files.TypeNameMatchesFileName">
Expand Down
58 changes: 58 additions & 0 deletions src/DI/ParsedownExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php declare(strict_types = 1);

namespace Contributte\Latte\DI;

use Contributte\Latte\Exception\LogicalException;
use Contributte\Latte\Filters\ParsedownExtraAdapter;
use Contributte\Latte\Filters\ParsedownFilter;
use Nette\Bridges\ApplicationLatte\LatteFactory;
use Nette\DI\CompilerExtension;
use Nette\DI\Definitions\FactoryDefinition;
use Nette\DI\Definitions\Statement;
use Nette\Schema\Expect;
use Nette\Schema\Schema;
use stdClass;

/**
* @property-read stdClass $config
*/
class ParsedownExtension extends CompilerExtension
{

public function getConfigSchema(): Schema
{
return Expect::structure([
'filter' => Expect::string('parsedown'),
]);
}

public function loadConfiguration(): void
{
if (!class_exists('ParsedownExtra')) {
throw new LogicalException('ParsedownExtra class not found. Install erusev/parsedown-extra package.');
}

$builder = $this->getContainerBuilder();

$builder->addDefinition($this->prefix('adapter'))
->setFactory(ParsedownExtraAdapter::class);
}

public function beforeCompile(): void
{
$builder = $this->getContainerBuilder();
$config = $this->config;

if ($builder->getByType(LatteFactory::class) === null) {
throw new LogicalException('You have to register LatteFactory first.');
}

$factoryDefinition = $builder->getDefinitionByType(LatteFactory::class);
assert($factoryDefinition instanceof FactoryDefinition);

$factoryDefinition
->getResultDefinition()
->addSetup('addFilter', [$config->filter, [new Statement(ParsedownFilter::class), 'apply']]);
}

}
2 changes: 1 addition & 1 deletion src/Extensions/Node/CdnNode.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public static function create(Tag $tag): self
public function print(PrintContext $context): string
{
return $context->format(
'echo LR\Filters::escapeHtmlAttr(call_user_func($this->global->cdnBuilder, %0.node)) %1.line;',
'echo LR\HtmlHelpers::escapeAttr(call_user_func($this->global->cdnBuilder, %0.node)) %1.line;',
$this->path,
$this->position,
);
Expand Down
43 changes: 43 additions & 0 deletions src/Filters/ParsedownExtraAdapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php declare(strict_types = 1);

namespace Contributte\Latte\Filters;

use ParsedownExtra;

/**
* ParsedownExtra Adapter
*
* @method void onProcess(string $text, ParsedownExtraAdapter $adapter)
*/
class ParsedownExtraAdapter
{

/** @var callable[] */
public array $onProcess = [];

private ParsedownExtra $parsedown;

public function __construct(?ParsedownExtra $parsedown = null)
{
$this->parsedown = $parsedown ?? new ParsedownExtra();
}

public function process(mixed $text): mixed
{
foreach ($this->onProcess as $callback) {
$callback($text, $this);
}

return $this->parsedown->parse($text);
}

public function processLine(mixed $line): string
{
foreach ($this->onProcess as $callback) {
$callback($line, $this);
}

return $this->parsedown->line($line);
}

}
30 changes: 30 additions & 0 deletions src/Filters/ParsedownFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php declare(strict_types = 1);

namespace Contributte\Latte\Filters;

use Contributte\Latte\Exception\LogicalException;
use Latte\ContentType;
use Latte\Runtime\FilterInfo;

class ParsedownFilter
{

protected ParsedownExtraAdapter $adapter;

public function __construct(ParsedownExtraAdapter $adapter)
{
$this->adapter = $adapter;
}

public function apply(FilterInfo $info, mixed $text): mixed
{
if ($info->contentType !== null && $info->contentType !== ContentType::Html && $info->contentType !== ContentType::Text) {
throw new LogicalException('Filter |parsedown used in incompatible content type.');
}

$info->contentType = ContentType::Html;

return $this->adapter->process($text);
}

}
Loading