Skip to content
12 changes: 10 additions & 2 deletions src/Languages/Html/HtmlLanguage.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@
namespace Tempest\Highlight\Languages\Html;

use Override;
use Tempest\Highlight\Languages\Base\BaseLanguage;
use Tempest\Highlight\Languages\Html\Injections\CssAttributeInHtmlInjection;
use Tempest\Highlight\Languages\Html\Injections\CssInHtmlInjection;
use Tempest\Highlight\Languages\Html\Injections\JavaScriptInHtmlInjection;
use Tempest\Highlight\Languages\Html\Injections\PhpInHtmlInjection;
use Tempest\Highlight\Languages\Html\Injections\PhpShortEchoInHtmlInjection;
use Tempest\Highlight\Languages\Xml\XmlLanguage;
use Tempest\Highlight\Languages\Html\Patterns\HtmlAttributePattern;
use Tempest\Highlight\Languages\Html\Patterns\HtmlCloseTagPattern;
use Tempest\Highlight\Languages\Html\Patterns\HtmlOpenTagPattern;
use Tempest\Highlight\Languages\Xml\Patterns\XmlCommentPattern;

class HtmlLanguage extends XmlLanguage
class HtmlLanguage extends BaseLanguage
{
#[Override]
public function getName(): string
Expand All @@ -38,6 +42,10 @@ public function getPatterns(): array
{
return [
...parent::getPatterns(),
new HtmlOpenTagPattern(),
new HtmlCloseTagPattern(),
new HtmlAttributePattern(),
new XmlCommentPattern(),
];
}
}
47 changes: 47 additions & 0 deletions src/Languages/Html/Patterns/HtmlAttributePattern.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

namespace Tempest\Highlight\Languages\Html\Patterns;

use Tempest\Highlight\IsPattern;
use Tempest\Highlight\Pattern;
use Tempest\Highlight\PatternTest;
use Tempest\Highlight\Tokens\TokenTypeEnum;

#[PatternTest(input: '<x-hello attr="">', output: 'attr')]
#[PatternTest(input: '<a href="">', output: 'href')]
#[PatternTest(input: '<a data-type="">', output: 'data-type')]
#[PatternTest(input: '<x-post :foreach="$this->posts as $post">', output: ':foreach')]
#[PatternTest(input: '<xsl xmlns:xsl="http">', output: 'xmlns:xsl')]
#[PatternTest(input: "<item attr='value'>", output: 'attr')]
#[PatternTest(input: "<item simple=value>", output: 'simple')]
#[PatternTest(input: "<item with-hyphen=simple-with-hyphen>", output: 'with-hyphen')]
#[PatternTest(input: "<div class=''><span style=''></span></div>", output: ['class', 'style'])]
#[PatternTest(input: '<item
id =
"multiline-attr">', output: 'id')]
#[PatternTest(input: '<item
type
=
"multiline-attr">', output: 'type')]
#[PatternTest(input: '<item
a
="multiline-attr">', output: 'a')]
#[PatternTest(input: '<p></p>', output: null)]
# Not yet implemented
# #[PatternTest(input: "<script defer>", output: 'defer')]
final readonly class HtmlAttributePattern implements Pattern
{
use IsPattern;

public function getPattern(): string
{
return '(?<match>[\w\-:]+)\s*=\s*(?:["\']|[\w-]+)';
}

public function getTokenType(): TokenTypeEnum
{
return TokenTypeEnum::PROPERTY;
}
}
37 changes: 37 additions & 0 deletions src/Languages/Html/Patterns/HtmlCloseTagPattern.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace Tempest\Highlight\Languages\Html\Patterns;

use Tempest\Highlight\IsPattern;
use Tempest\Highlight\Pattern;
use Tempest\Highlight\PatternTest;
use Tempest\Highlight\Tokens\TokenTypeEnum;

#[PatternTest(input: '</simple>', output: 'simple')]
#[PatternTest(input: '</UPPERCASE>', output: 'UPPERCASE')]
#[PatternTest(input: '</CamelCase>', output: 'CamelCase')]
#[PatternTest(input: '</x-hello>', output: 'x-hello')]
#[PatternTest(input: '</a>', output: 'a')]
# The following are not HTML valid
#[PatternTest(input: '</ns:tag>', output: null)]
#[PatternTest(input: '</point.x>', output: null)]
#[PatternTest(input: '</point_y>', output: null)]
#[PatternTest(input: '</_private>', output: null)]
#[PatternTest(input: '</1tag>', output: null)]
#[PatternTest(input: '</-tag>', output: null)]
final readonly class HtmlCloseTagPattern implements Pattern
{
use IsPattern;

public function getPattern(): string
{
return '<\/(?<match>[a-zA-Z][a-zA-Z0-9\-]*(?![:_\.\w]))';
}

public function getTokenType(): TokenTypeEnum
{
return TokenTypeEnum::KEYWORD;
}
}
37 changes: 37 additions & 0 deletions src/Languages/Html/Patterns/HtmlOpenTagPattern.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace Tempest\Highlight\Languages\Html\Patterns;

use Tempest\Highlight\IsPattern;
use Tempest\Highlight\Pattern;
use Tempest\Highlight\PatternTest;
use Tempest\Highlight\Tokens\TokenTypeEnum;

#[PatternTest(input: '<div>', output: 'div')]
#[PatternTest(input: '<UPPERCASE>', output: 'UPPERCASE')]
#[PatternTest(input: '<CamelCase>', output: 'CamelCase')]
#[PatternTest(input: '<a-component>', output: 'a-component')]
#[PatternTest(input: '<a href="">', output: 'a')]
# The following are not HTML valid
#[PatternTest(input: '<_private>', output: null)]
#[PatternTest(input: '<ns:tag>', output: null)]
#[PatternTest(input: '<point.x>', output: null)]
#[PatternTest(input: '<point_y>', output: null)]
#[PatternTest(input: '<1tag>', output: null)]
#[PatternTest(input: '<-tag>', output: null)]
final readonly class HtmlOpenTagPattern implements Pattern
{
use IsPattern;

public function getPattern(): string
{
return '<(?<match>[a-zA-Z][a-zA-Z0-9\-]*(?![:_\.\w]))';
}

public function getTokenType(): TokenTypeEnum
{
return TokenTypeEnum::KEYWORD;
}
}
13 changes: 12 additions & 1 deletion src/Languages/Xml/Patterns/XmlAttributePattern.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,24 @@
#[PatternTest(input: '<a href="">', output: 'href')]
#[PatternTest(input: '<a data-type="">', output: 'data-type')]
#[PatternTest(input: '<xsl xmlns:xsl="http">', output: 'xmlns:xsl')]
#[PatternTest(input: "<item attr='value'>", output: 'attr')]
#[PatternTest(input: '<item
id =
"multiline-attr">', output: 'id')]
#[PatternTest(input: '<item
type
=
"multiline-attr">', output: 'type')]
#[PatternTest(input: '<item
a
="multiline-attr">', output: 'a')]
final readonly class XmlAttributePattern implements Pattern
{
use IsPattern;

public function getPattern(): string
{
return '(?<match>[\w\-\:]+)="';
return '(?<match>[\w\-\:]+)\s*=\s*["\']';
}

public function getTokenType(): TokenTypeEnum
Expand Down
11 changes: 10 additions & 1 deletion src/Languages/Xml/Patterns/XmlCloseTagPattern.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,25 @@
use Tempest\Highlight\PatternTest;
use Tempest\Highlight\Tokens\TokenTypeEnum;

#[PatternTest(input: '</simple>', output: 'simple')]
#[PatternTest(input: '</UPPERCASE>', output: 'UPPERCASE')]
#[PatternTest(input: '</CamelCase>', output: 'CamelCase')]
#[PatternTest(input: '</x-hello>', output: 'x-hello')]
#[PatternTest(input: '</a>', output: 'a')]
#[PatternTest(input: '</ns:tag>', output: 'ns:tag')]
#[PatternTest(input: '</point.x>', output: 'point.x')]
#[PatternTest(input: '</point_y>', output: 'point_y')]
#[PatternTest(input: '</_private>', output: '_private')]
# The following are not valid XML tags
#[PatternTest(input: '</1tag>', output: null)]
#[PatternTest(input: '</-tag>', output: null)]
final readonly class XmlCloseTagPattern implements Pattern
{
use IsPattern;

public function getPattern(): string
{
return '<\/(?<match>[\w\-\:]+)';
return '<\/(?<match>[a-zA-Z_][\w\-\:\.]*)';
}

public function getTokenType(): TokenTypeEnum
Expand Down
11 changes: 10 additions & 1 deletion src/Languages/Xml/Patterns/XmlOpenTagPattern.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,26 @@
use Tempest\Highlight\PatternTest;
use Tempest\Highlight\Tokens\TokenTypeEnum;

#[PatternTest(input: '<simple>', output: 'simple')]
#[PatternTest(input: '<UPPERCASE>', output: 'UPPERCASE')]
#[PatternTest(input: '<CamelCase>', output: 'CamelCase')]
#[PatternTest(input: '<x-hello attr="">', output: 'x-hello')]
#[PatternTest(input: '<a href="">', output: 'a')]
#[PatternTest(input: '<br/>', output: 'br')]
#[PatternTest(input: '<ns:tag>', output: 'ns:tag')]
#[PatternTest(input: '<point.x>', output: 'point.x')]
#[PatternTest(input: '<point_y>', output: 'point_y')]
#[PatternTest(input: '<_private>', output: '_private')]
# The following are not valid XML tags
#[PatternTest(input: '<1tag>', output: null)]
#[PatternTest(input: '<-tag>', output: null)]
final readonly class XmlOpenTagPattern implements Pattern
{
use IsPattern;

public function getPattern(): string
{
return '<(?<match>[\w\-\:]+)';
return '<(?<match>[a-zA-Z_][\w\-\:\.]*)';
}

public function getTokenType(): TokenTypeEnum
Expand Down
18 changes: 18 additions & 0 deletions tests/targets/blade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
```blade
<!-- resources/views/layouts/app.blade.php -->

<html>
<head>
<title>App Name - @yield('title')</title>
</head>
<body>
@section('sidebar')
This is the master sidebar.
@show

<div class="container">
@yield('content')
</div>
</body>
</html>
```
25 changes: 25 additions & 0 deletions tests/targets/tempest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
```blade
<x-base title="Home">
<x-post :foreach="$this->posts as $post">
{{-- a comment which won't be rendered to HTML --}}

{!! $post->title !!}

<span :if="$this->showDate($post)">
{{ $post->date }}
</span>
<span :else>
-
</span>
</x-post>
<div :forelse>
<form action="…">
<x-csrf-token />
<math-α></math-α>
<emotion-😍></emotion-😍>
</form>
</div>

<x-footer />
</x-base>
```
18 changes: 18 additions & 0 deletions tests/targets/twig.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
```twig
<!DOCTYPE html>
<html>
<head>
<title>My Webpage</title>
</head>
<body>
<ul id="navigation">
{% for item in navigation %}
<li><a href="{{ item.href }}">{{ item.caption }}</a></li>
{% endfor %}
</ul>

<h1>My Webpage</h1>
{{ a_variable }}
</body>
</html>
```
6 changes: 6 additions & 0 deletions tests/targets/xml.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@
</b:nested>
</a:element>

<!-- Default namespace override and undeclaration -->
<coordinates>
<point.x>123.45</point.x>
<point.y>42,15</point.y>
</coordinates>

<!-- Default namespace override and undeclaration -->
<container xmlns="http://example.com/override">
<item xmlns="">Back to no namespace</item>
Expand Down