Skip to content

Commit 7eaf2f4

Browse files
authored
Merge pull request #212 from owenvoke/feature/http-language
feat: add support for HTTP language
2 parents ad74f09 + 43641c8 commit 7eaf2f4

12 files changed

Lines changed: 325 additions & 0 deletions

File tree

src/Highlighter.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Tempest\Highlight\Languages\Gdscript\GdscriptLanguage;
1919
use Tempest\Highlight\Languages\Graphql\GraphqlLanguage;
2020
use Tempest\Highlight\Languages\Html\HtmlLanguage;
21+
use Tempest\Highlight\Languages\Http\HttpLanguage;
2122
use Tempest\Highlight\Languages\Ini\IniLanguage;
2223
use Tempest\Highlight\Languages\JavaScript\JavaScriptLanguage;
2324
use Tempest\Highlight\Languages\Json\JsonLanguage;
@@ -73,6 +74,7 @@ public function __construct(
7374
->addLanguage(new GdscriptLanguage())
7475
->addLanguage(new GraphqlLanguage())
7576
->addLanguage(new HtmlLanguage())
77+
->addLanguage(new HttpLanguage())
7678
->addLanguage(new JavaScriptLanguage())
7779
->addLanguage(new JsonLanguage())
7880
->addLanguage(new MarkdownLanguage())
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tempest\Highlight\Languages\Http;
6+
7+
use Tempest\Highlight\Languages\Base\BaseLanguage;
8+
use Tempest\Highlight\Languages\Http\Patterns\HttpAttributePattern;
9+
use Tempest\Highlight\Languages\Http\Patterns\HttpCommentPattern;
10+
use Tempest\Highlight\Languages\Http\Patterns\HttpMethodPattern;
11+
use Tempest\Highlight\Languages\Http\Patterns\HttpStatusPattern;
12+
use Tempest\Highlight\Languages\Http\Patterns\HttpUrlPattern;
13+
use Tempest\Highlight\Languages\Http\Patterns\HttpVersionPattern;
14+
15+
class HttpLanguage extends BaseLanguage
16+
{
17+
public function getName(): string
18+
{
19+
return 'http';
20+
}
21+
22+
public function getAliases(): array
23+
{
24+
return ['https'];
25+
}
26+
27+
public function getPatterns(): array
28+
{
29+
return [
30+
...parent::getPatterns(),
31+
32+
// HTTP Comments
33+
new HttpCommentPattern(),
34+
35+
// Start Line: Methods (GET, POST)
36+
new HttpMethodPattern(),
37+
38+
// Start Line: HTTP Version (HTTP/1.1, HTTP/2)
39+
new HttpVersionPattern(),
40+
41+
// Start Line: URL/Path
42+
new HttpUrlPattern(),
43+
44+
// Response: Status Codes (200, 404)
45+
new HttpStatusPattern(),
46+
47+
// Headers: Attribute names
48+
new HttpAttributePattern(),
49+
];
50+
}
51+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tempest\Highlight\Languages\Http\Patterns;
6+
7+
use Tempest\Highlight\IsPattern;
8+
use Tempest\Highlight\Pattern;
9+
use Tempest\Highlight\PatternTest;
10+
use Tempest\Highlight\Tokens\TokenTypeEnum;
11+
12+
#[PatternTest(input: 'Content-Type: application/json', output: 'Content-Type')]
13+
#[PatternTest(input: 'x-frame-options: SAMEORIGIN', output: 'x-frame-options')]
14+
final class HttpAttributePattern implements Pattern
15+
{
16+
use IsPattern;
17+
18+
public function getPattern(): string
19+
{
20+
return '(?<match>(?m)^[A-Za-z][A-Za-z0-9-]*(?=\:))';
21+
}
22+
23+
public function getTokenType(): TokenTypeEnum
24+
{
25+
return TokenTypeEnum::ATTRIBUTE;
26+
}
27+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tempest\Highlight\Languages\Http\Patterns;
6+
7+
use Tempest\Highlight\IsPattern;
8+
use Tempest\Highlight\Pattern;
9+
use Tempest\Highlight\PatternTest;
10+
use Tempest\Highlight\Tokens\TokenType;
11+
use Tempest\Highlight\Tokens\TokenTypeEnum;
12+
13+
#[PatternTest(input: '# Test Comment', output: '# Test Comment')]
14+
#[PatternTest(input: '// Test Comment', output: '// Test Comment')]
15+
final class HttpCommentPattern implements Pattern
16+
{
17+
use IsPattern;
18+
19+
public function getPattern(): string
20+
{
21+
return '/(?<match>(?m)^(\/\/|\#).*)/';
22+
}
23+
24+
public function getTokenType(): TokenType
25+
{
26+
return TokenTypeEnum::COMMENT;
27+
}
28+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tempest\Highlight\Languages\Http\Patterns;
6+
7+
use Tempest\Highlight\IsPattern;
8+
use Tempest\Highlight\Pattern;
9+
use Tempest\Highlight\PatternTest;
10+
use Tempest\Highlight\Tokens\TokenTypeEnum;
11+
12+
#[PatternTest(input: 'GET /index.html HTTP/1.1', output: 'GET')]
13+
#[PatternTest(input: 'DELETE /user/1 HTTP/1.1', output: 'DELETE')]
14+
#[PatternTest(input: 'POSTAL /a HTTP/1.1', output: null)]
15+
final class HttpMethodPattern implements Pattern
16+
{
17+
use IsPattern;
18+
19+
public function getPattern(): string
20+
{
21+
return '(?<match>(?m)^(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS|CONNECT|TRACE)\b)';
22+
}
23+
24+
public function getTokenType(): TokenTypeEnum
25+
{
26+
return TokenTypeEnum::KEYWORD;
27+
}
28+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tempest\Highlight\Languages\Http\Patterns;
6+
7+
use Tempest\Highlight\IsPattern;
8+
use Tempest\Highlight\Pattern;
9+
use Tempest\Highlight\PatternTest;
10+
use Tempest\Highlight\Tokens\TokenTypeEnum;
11+
12+
#[PatternTest(input: 'HTTP/2 301', output: '301')]
13+
#[PatternTest(input: 'HTTP/1.1 200 OK', output: '200')]
14+
#[PatternTest(input: 'content-length: 220', output: null)]
15+
final class HttpStatusPattern implements Pattern
16+
{
17+
use IsPattern;
18+
19+
public function getPattern(): string
20+
{
21+
// Only match the status code on a response start line (e.g. `HTTP/2 301`),
22+
// never a three-digit value within a header (e.g. `content-length: 220`).
23+
return '/(?m)(?<=^HTTP\/[32] |^HTTP\/1\.[01] )(?<match>\d{3})/';
24+
}
25+
26+
public function getTokenType(): TokenTypeEnum
27+
{
28+
return TokenTypeEnum::NUMBER;
29+
}
30+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tempest\Highlight\Languages\Http\Patterns;
6+
7+
use Tempest\Highlight\IsPattern;
8+
use Tempest\Highlight\Pattern;
9+
use Tempest\Highlight\PatternTest;
10+
use Tempest\Highlight\Tokens\TokenTypeEnum;
11+
12+
#[PatternTest(input: 'POST /task?id=1 HTTP/1.1', output: '/task?id=1')]
13+
#[PatternTest(input: 'POST https://api.example.com/users HTTP/2', output: 'https://api.example.com/users')]
14+
final class HttpUrlPattern implements Pattern
15+
{
16+
use IsPattern;
17+
18+
public function getPattern(): string
19+
{
20+
return '(?<=\s)(?<match>\/[^\s]*|\w+:\/\/[^\s]*)(?=\sHTTP)';
21+
}
22+
23+
public function getTokenType(): TokenTypeEnum
24+
{
25+
return TokenTypeEnum::VALUE;
26+
}
27+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tempest\Highlight\Languages\Http\Patterns;
6+
7+
use Tempest\Highlight\IsPattern;
8+
use Tempest\Highlight\Pattern;
9+
use Tempest\Highlight\PatternTest;
10+
use Tempest\Highlight\Tokens\TokenTypeEnum;
11+
12+
#[PatternTest(input: 'GET /index.html HTTP/1.1', output: 'HTTP/1.1')]
13+
#[PatternTest(input: 'HTTP/2 301', output: 'HTTP/2')]
14+
#[PatternTest(input: 'HTTP/3 200', output: 'HTTP/3')]
15+
final class HttpVersionPattern implements Pattern
16+
{
17+
use IsPattern;
18+
19+
public function getPattern(): string
20+
{
21+
return '(?<match>HTTP\/([32]|1\.[01]))';
22+
}
23+
24+
public function getTokenType(): TokenTypeEnum
25+
{
26+
return TokenTypeEnum::PROPERTY;
27+
}
28+
}

tests/Bench/Fixtures/http.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
### Get all users
2+
GET https://api.example.com/users
3+
Accept: application/json
4+
5+
### Create a new user
6+
POST https://api.example.com/users
7+
Content-Type: application/json
8+
9+
{
10+
"name": "Jane Doe",
11+
"email": "jane@example.com"
12+
}

tests/Bench/HighlighterBench.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ final class HighlighterBench
2828
'gdscript' => 'gdscript.txt',
2929
'graphql' => 'graphql.txt',
3030
'html' => 'html.txt',
31+
'http' => 'http.txt',
3132
'ini' => 'ini.txt',
3233
'javascript' => 'javascript.txt',
3334
'json' => 'json.txt',

0 commit comments

Comments
 (0)