diff --git a/src/Highlighter.php b/src/Highlighter.php index 843cf5b6..3dbc5141 100644 --- a/src/Highlighter.php +++ b/src/Highlighter.php @@ -36,6 +36,7 @@ use Tempest\Highlight\Languages\Terminal\TerminalLanguage; use Tempest\Highlight\Languages\Terraform\TerraformLanguage; use Tempest\Highlight\Languages\Text\TextLanguage; +use Tempest\Highlight\Languages\Toml\TomlLanguage; use Tempest\Highlight\Languages\Tsx\TsxLanguage; use Tempest\Highlight\Languages\Twig\TwigLanguage; use Tempest\Highlight\Languages\TypeScript\TypeScriptLanguage; @@ -94,6 +95,7 @@ public function __construct( ->addLanguage(new TerminalLanguage()) ->addLanguage(new TextLanguage()) ->addLanguage(new TerraformLanguage()) + ->addLanguage(new TomlLanguage()) ->addLanguage(new TypeScriptLanguage()) ->addLanguage(new XmlLanguage()) ->addLanguage(new YamlLanguage()) diff --git a/src/Languages/Toml/Patterns/TomlBooleanPattern.php b/src/Languages/Toml/Patterns/TomlBooleanPattern.php new file mode 100644 index 00000000..850e531b --- /dev/null +++ b/src/Languages/Toml/Patterns/TomlBooleanPattern.php @@ -0,0 +1,28 @@ +true|false)(?![A-Za-z0-9_-])/'; + } + + public function getTokenType(): TokenType + { + return TokenTypeEnum::LITERAL; + } +} diff --git a/src/Languages/Toml/Patterns/TomlCommentPattern.php b/src/Languages/Toml/Patterns/TomlCommentPattern.php new file mode 100644 index 00000000..63c655a9 --- /dev/null +++ b/src/Languages/Toml/Patterns/TomlCommentPattern.php @@ -0,0 +1,27 @@ +#[^\r\n]*)/'; + } + + public function getTokenType(): TokenType + { + return TokenTypeEnum::COMMENT; + } +} diff --git a/src/Languages/Toml/Patterns/TomlDateTimePattern.php b/src/Languages/Toml/Patterns/TomlDateTimePattern.php new file mode 100644 index 00000000..65baa7fc --- /dev/null +++ b/src/Languages/Toml/Patterns/TomlDateTimePattern.php @@ -0,0 +1,28 @@ +(?:\d{4}-\d{2}-\d{2}(?:[Tt ]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:[Zz]|[+-]\d{2}:\d{2})?)?|\d{2}:\d{2}:\d{2}(?:\.\d+)?))(?![A-Za-z0-9_-])/'; + } + + public function getTokenType(): TokenType + { + return TokenTypeEnum::VALUE; + } +} diff --git a/src/Languages/Toml/Patterns/TomlKeyPattern.php b/src/Languages/Toml/Patterns/TomlKeyPattern.php new file mode 100644 index 00000000..0f19991c --- /dev/null +++ b/src/Languages/Toml/Patterns/TomlKeyPattern.php @@ -0,0 +1,30 @@ +(?:"(?:\\(?:["\\bfnrt]|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})|[^"\\\r\n])*"|'[^'\r\n]*'|[A-Za-z0-9_-]+)(?:[\t ]*\.[\t ]*(?:"(?:\\(?:["\\bfnrt]|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})|[^"\\\r\n])*"|'[^'\r\n]*'|[A-Za-z0-9_-]+))*)(?=[\t ]*=)/m +REGEX; + } + + public function getTokenType(): TokenType + { + return TokenTypeEnum::PROPERTY; + } +} diff --git a/src/Languages/Toml/Patterns/TomlNumberPattern.php b/src/Languages/Toml/Patterns/TomlNumberPattern.php new file mode 100644 index 00000000..e4b63b10 --- /dev/null +++ b/src/Languages/Toml/Patterns/TomlNumberPattern.php @@ -0,0 +1,31 @@ +[+-]?(?:inf|nan)|0x[0-9A-Fa-f](?:_?[0-9A-Fa-f])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*|[+-]?(?:\d(?:_?\d)*\.\d(?:_?\d)*(?:[eE][+-]?\d(?:_?\d)*)?|\d(?:_?\d)*[eE][+-]?\d(?:_?\d)*|\d(?:_?\d)*))(?![A-Za-z0-9_.-])/ +REGEX; + } + + public function getTokenType(): TokenType + { + return TokenTypeEnum::NUMBER; + } +} diff --git a/src/Languages/Toml/Patterns/TomlOperatorPattern.php b/src/Languages/Toml/Patterns/TomlOperatorPattern.php new file mode 100644 index 00000000..51a204ec --- /dev/null +++ b/src/Languages/Toml/Patterns/TomlOperatorPattern.php @@ -0,0 +1,28 @@ +\[\[|\]\]|\[|\]|\{|\}|=|,)/'; + } + + public function getTokenType(): TokenType + { + return TokenTypeEnum::OPERATOR; + } +} diff --git a/src/Languages/Toml/Patterns/TomlStringPattern.php b/src/Languages/Toml/Patterns/TomlStringPattern.php new file mode 100644 index 00000000..a6d79fd8 --- /dev/null +++ b/src/Languages/Toml/Patterns/TomlStringPattern.php @@ -0,0 +1,30 @@ +"""(?:\\[\s\S]|"{1,2}(?!")|[^"\\])*"""|'''(?:'{1,2}(?!')|[^'])*'''|"(?:\\(?:["\\bfnrt]|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})|[^"\\\r\n])*"|'[^'\r\n]*')/ +REGEX; + } + + public function getTokenType(): TokenType + { + return TokenTypeEnum::VALUE; + } +} diff --git a/src/Languages/Toml/Patterns/TomlTablePattern.php b/src/Languages/Toml/Patterns/TomlTablePattern.php new file mode 100644 index 00000000..86c4c357 --- /dev/null +++ b/src/Languages/Toml/Patterns/TomlTablePattern.php @@ -0,0 +1,30 @@ +(?:"(?:\\(?:["\\bfnrt]|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})|[^"\\\r\n])*"|'[^'\r\n]*'|[A-Za-z0-9_-]+)(?:[\t ]*\.[\t ]*(?:"(?:\\(?:["\\bfnrt]|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})|[^"\\\r\n])*"|'[^'\r\n]*'|[A-Za-z0-9_-]+))*)(?=[\t ]*\]{1,2})/m +REGEX; + } + + public function getTokenType(): TokenType + { + return TokenTypeEnum::TYPE; + } +} diff --git a/src/Languages/Toml/TomlLanguage.php b/src/Languages/Toml/TomlLanguage.php new file mode 100644 index 00000000..45ffea52 --- /dev/null +++ b/src/Languages/Toml/TomlLanguage.php @@ -0,0 +1,40 @@ + 'swift.txt', 'terminal' => 'terminal.txt', 'terraform' => 'terraform.txt', + 'toml' => 'toml.txt', 'typescript' => 'typescript.txt', 'txt' => 'text.txt', 'twig' => 'twig.txt', diff --git a/tests/Languages/Toml/TomlLanguageTest.php b/tests/Languages/Toml/TomlLanguageTest.php new file mode 100644 index 00000000..7bd0405f --- /dev/null +++ b/tests/Languages/Toml/TomlLanguageTest.php @@ -0,0 +1,116 @@ +assertContains('toml', $highlighter->getSupportedLanguageNames()); + + $highlighter->parse('', 'toml'); + + $this->assertInstanceOf(TomlLanguage::class, $highlighter->getCurrentLanguage()); + } + + #[Test] + public function it_escapes_html_and_strips_reserved_markers(): void + { + $source = "title = \"<©> ❷img src=x onerror=alert(1)❸ ❶❹❿\"\r\n" + . "script = \"\"\r" + . "enabled = true\r\n"; + + $highlighted = (new Highlighter())->parse($source, 'toml'); + $renderedSource = html_entity_decode(strip_tags($highlighted), ENT_QUOTES | ENT_HTML5); + + $expectedSource = str_replace(["\r\n", "\r"], "\n", str_replace(['❶', '❷', '❸', '❹', '❿'], '', $source)); + + $this->assertSame($expectedSource, $renderedSource); + $this->assertStringNotContainsString('