Skip to content

Commit d499fe3

Browse files
authored
Merge pull request #205 from DorZuberi/add-nginx-langauge-support
2 parents c7eed7e + 4f14a78 commit d499fe3

9 files changed

Lines changed: 379 additions & 0 deletions

File tree

src/Highlighter.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use Tempest\Highlight\Languages\JavaScript\JavaScriptLanguage;
2323
use Tempest\Highlight\Languages\Json\JsonLanguage;
2424
use Tempest\Highlight\Languages\Markdown\MarkdownLanguage;
25+
use Tempest\Highlight\Languages\Nginx\NginxLanguage;
2526
use Tempest\Highlight\Languages\Php\PhpLanguage;
2627
use Tempest\Highlight\Languages\Python\PythonLanguage;
2728
use Tempest\Highlight\Languages\Scss\ScssLanguage;
@@ -71,6 +72,7 @@ public function __construct(private readonly Theme $theme = new CssTheme())
7172
->addLanguage(new JavaScriptLanguage())
7273
->addLanguage(new JsonLanguage())
7374
->addLanguage(new MarkdownLanguage())
75+
->addLanguage(new NginxLanguage())
7476
->addLanguage(new PhpLanguage())
7577
->addLanguage(new PythonLanguage())
7678
->addLanguage(new ScssLanguage())
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tempest\Highlight\Languages\Nginx;
6+
7+
use Override;
8+
use Tempest\Highlight\Languages\Base\BaseLanguage;
9+
use Tempest\Highlight\Languages\Bash\Patterns\BashCommentPattern;
10+
use Tempest\Highlight\Languages\Bash\Patterns\BashNumberPattern;
11+
use Tempest\Highlight\Languages\Nginx\Patterns\NginxBooleanPattern;
12+
use Tempest\Highlight\Languages\Nginx\Patterns\NginxDirectivePattern;
13+
use Tempest\Highlight\Languages\Nginx\Patterns\NginxOperatorPattern;
14+
use Tempest\Highlight\Languages\Nginx\Patterns\NginxVariablePattern;
15+
use Tempest\Highlight\Languages\Php\Patterns\DoubleQuoteValuePattern;
16+
use Tempest\Highlight\Languages\Php\Patterns\SingleQuoteValuePattern;
17+
18+
class NginxLanguage extends BaseLanguage
19+
{
20+
public function getName(): string
21+
{
22+
return 'nginx';
23+
}
24+
25+
#[Override]
26+
public function getAliases(): array
27+
{
28+
return ['nginxconf'];
29+
}
30+
31+
#[Override]
32+
public function getInjections(): array
33+
{
34+
return [
35+
...parent::getInjections(),
36+
];
37+
}
38+
39+
#[Override]
40+
public function getPatterns(): array
41+
{
42+
return [
43+
...parent::getPatterns(),
44+
45+
// COMMENTS
46+
new BashCommentPattern(),
47+
48+
// VALUES
49+
new SingleQuoteValuePattern(),
50+
new DoubleQuoteValuePattern(),
51+
52+
// DIRECTIVES
53+
new NginxDirectivePattern(),
54+
55+
// BOOLEANS
56+
new NginxBooleanPattern(),
57+
58+
// VARIABLES
59+
new NginxVariablePattern(),
60+
61+
// OPERATORS
62+
new NginxOperatorPattern(),
63+
64+
// NUMBERS
65+
new BashNumberPattern(),
66+
];
67+
}
68+
}
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\Nginx\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: 'gzip on;', output: 'on')]
13+
#[PatternTest(input: 'autoindex off;', output: 'off')]
14+
final readonly class NginxBooleanPattern implements Pattern
15+
{
16+
use IsPattern;
17+
18+
public function getPattern(): string
19+
{
20+
return '\b(?<match>on|off)\b';
21+
}
22+
23+
public function getTokenType(): TokenTypeEnum
24+
{
25+
return TokenTypeEnum::VALUE;
26+
}
27+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tempest\Highlight\Languages\Nginx\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: 'server {', output: 'server')]
13+
#[PatternTest(input: 'listen 80;', output: 'listen')]
14+
#[PatternTest(input: ' proxy_pass http://backend;', output: 'proxy_pass')]
15+
final readonly class NginxDirectivePattern implements Pattern
16+
{
17+
use IsPattern;
18+
19+
public function getPattern(): string
20+
{
21+
$directives = implode('|', [
22+
'server', 'location', 'listen', 'root', 'index', 'proxy_pass',
23+
'upstream', 'http', 'events', 'worker_processes', 'worker_connections',
24+
'error_log', 'access_log', 'ssl_certificate', 'ssl_certificate_key',
25+
'try_files', 'return', 'rewrite', 'if', 'set', 'map', 'include',
26+
'server_name', 'client_max_body_size', 'keepalive_timeout',
27+
'gzip', 'gzip_types', 'add_header', 'deny', 'allow',
28+
'fastcgi_pass', 'fastcgi_param', 'proxy_set_header',
29+
'proxy_http_version', 'proxy_cache', 'proxy_cache_valid',
30+
'sendfile', 'tcp_nopush', 'tcp_nodelay', 'types', 'default_type',
31+
'log_format', 'expires', 'autoindex', 'charset', 'resolver',
32+
'ssl', 'ssl_protocols', 'ssl_ciphers', 'ssl_prefer_server_ciphers',
33+
'ssl_session_cache', 'ssl_session_timeout',
34+
'limit_req', 'limit_req_zone', 'limit_conn', 'limit_conn_zone',
35+
'geo', 'stub_status',
36+
]);
37+
38+
return "\b(?<match>(?:{$directives}))\b";
39+
}
40+
41+
public function getTokenType(): TokenTypeEnum
42+
{
43+
return TokenTypeEnum::KEYWORD;
44+
}
45+
}
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\Nginx\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: 'listen 80;', output: ';')]
13+
#[PatternTest(input: 'location = /health {', output: '=')]
14+
final readonly class NginxOperatorPattern implements Pattern
15+
{
16+
use IsPattern;
17+
18+
public function getPattern(): string
19+
{
20+
return '(?<match>~\*|[;{}~=^])';
21+
}
22+
23+
public function getTokenType(): TokenTypeEnum
24+
{
25+
return TokenTypeEnum::OPERATOR;
26+
}
27+
}
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\Nginx\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: 'proxy_set_header Host $host;', output: '$host')]
13+
#[PatternTest(input: 'return 301 $scheme://example.com;', output: '$scheme')]
14+
final readonly class NginxVariablePattern implements Pattern
15+
{
16+
use IsPattern;
17+
18+
public function getPattern(): string
19+
{
20+
return '(?<match>\$[a-zA-Z_]\w*)';
21+
}
22+
23+
public function getTokenType(): TokenTypeEnum
24+
{
25+
return TokenTypeEnum::VARIABLE;
26+
}
27+
}

tests/Bench/Fixtures/nginx.txt

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Main Nginx configuration
2+
worker_processes auto;
3+
error_log /var/log/nginx/error.log;
4+
5+
events {
6+
worker_connections 1024;
7+
}
8+
9+
http {
10+
include /etc/nginx/mime.types;
11+
default_type application/octet-stream;
12+
13+
sendfile on;
14+
tcp_nopush on;
15+
tcp_nodelay on;
16+
keepalive_timeout 65;
17+
gzip on;
18+
gzip_types text/plain application/json;
19+
20+
log_format main '$remote_addr - $remote_user [$time_local] '
21+
'"$request" $status $body_bytes_sent';
22+
23+
upstream backend {
24+
server 127.0.0.1:8080;
25+
server 127.0.0.1:8081;
26+
}
27+
28+
server {
29+
listen 80;
30+
server_name example.com www.example.com;
31+
return 301 https://$host$request_uri;
32+
}
33+
34+
server {
35+
listen 443 ssl;
36+
server_name example.com;
37+
38+
ssl_certificate /etc/ssl/certs/example.pem;
39+
ssl_certificate_key /etc/ssl/private/example.key;
40+
ssl_protocols TLSv1.2 TLSv1.3;
41+
42+
root /var/www/html;
43+
index index.html index.htm;
44+
45+
add_header X-Frame-Options "SAMEORIGIN";
46+
add_header X-Content-Type-Options "nosniff";
47+
48+
location / {
49+
try_files $uri $uri/ =404;
50+
}
51+
52+
location /api {
53+
proxy_pass http://backend;
54+
proxy_set_header Host $host;
55+
proxy_set_header X-Real-IP $remote_addr;
56+
proxy_http_version 1.1;
57+
}
58+
59+
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
60+
expires 30d;
61+
access_log off;
62+
}
63+
64+
location = /health {
65+
stub_status;
66+
allow 127.0.0.1;
67+
deny all;
68+
}
69+
70+
if ($request_uri ~* "^/old-path") {
71+
rewrite ^/old-path(.*)$ /new-path$1 permanent;
72+
}
73+
}
74+
}

tests/Bench/HighlighterBench.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ final class HighlighterBench
3232
'javascript' => 'javascript.txt',
3333
'json' => 'json.txt',
3434
'markdown' => 'markdown.txt',
35+
'nginx' => 'nginx.txt',
3536
'php' => 'php.txt',
3637
'python' => 'python.txt',
3738
'scss' => 'scss.txt',

0 commit comments

Comments
 (0)