diff --git a/src/Highlighter.php b/src/Highlighter.php index 30cf229..fc154e6 100644 --- a/src/Highlighter.php +++ b/src/Highlighter.php @@ -31,6 +31,7 @@ use Tempest\Highlight\Languages\Terraform\TerraformLanguage; use Tempest\Highlight\Languages\Text\TextLanguage; use Tempest\Highlight\Languages\Twig\TwigLanguage; +use Tempest\Highlight\Languages\TypeScript\TypeScriptLanguage; use Tempest\Highlight\Languages\Xml\XmlLanguage; use Tempest\Highlight\Languages\Yaml\YamlLanguage; use Tempest\Highlight\Themes\CssTheme; @@ -79,6 +80,7 @@ public function __construct(private readonly Theme $theme = new CssTheme()) ->addLanguage(new SqlLanguage()) ->addLanguage(new TerminalLanguage()) ->addLanguage(new TerraformLanguage()) + ->addLanguage(new TypeScriptLanguage()) ->addLanguage(new XmlLanguage()) ->addLanguage(new YamlLanguage()) ->addLanguage(new DotEnvLanguage()) diff --git a/src/Languages/TypeScript/Patterns/TsBuiltInTypePattern.php b/src/Languages/TypeScript/Patterns/TsBuiltInTypePattern.php new file mode 100644 index 0000000..fb9d8b2 --- /dev/null +++ b/src/Languages/TypeScript/Patterns/TsBuiltInTypePattern.php @@ -0,0 +1,24 @@ +string|number|boolean|any|unknown|never|bigint|symbol|object|undefined)\b/'; + } + + public function getTokenType(): TokenTypeEnum + { + return TokenTypeEnum::TYPE; + } +} diff --git a/src/Languages/TypeScript/Patterns/TsDecoratorPattern.php b/src/Languages/TypeScript/Patterns/TsDecoratorPattern.php new file mode 100644 index 0000000..806f1d0 --- /dev/null +++ b/src/Languages/TypeScript/Patterns/TsDecoratorPattern.php @@ -0,0 +1,24 @@ +@[A-Za-z_][\w]*)/'; + } + + public function getTokenType(): TokenTypeEnum + { + return TokenTypeEnum::ATTRIBUTE; + } +} diff --git a/src/Languages/TypeScript/Patterns/TsGenericPattern.php b/src/Languages/TypeScript/Patterns/TsGenericPattern.php new file mode 100644 index 0000000..51d60bc --- /dev/null +++ b/src/Languages/TypeScript/Patterns/TsGenericPattern.php @@ -0,0 +1,24 @@ +<[A-Z][\w\s,\.\[\]]*>)/'; + } + + public function getTokenType(): TokenTypeEnum + { + return TokenTypeEnum::GENERIC; + } +} diff --git a/src/Languages/TypeScript/Patterns/TsTypeAnnotationPattern.php b/src/Languages/TypeScript/Patterns/TsTypeAnnotationPattern.php new file mode 100644 index 0000000..977f7ad --- /dev/null +++ b/src/Languages/TypeScript/Patterns/TsTypeAnnotationPattern.php @@ -0,0 +1,24 @@ +[A-Z][\w]*(?:\.[A-Z][\w]*)*(?:\[\])?)/'; + } + + public function getTokenType(): TokenTypeEnum + { + return TokenTypeEnum::TYPE; + } +} diff --git a/src/Languages/TypeScript/TypeScriptLanguage.php b/src/Languages/TypeScript/TypeScriptLanguage.php new file mode 100644 index 0000000..566c1b5 --- /dev/null +++ b/src/Languages/TypeScript/TypeScriptLanguage.php @@ -0,0 +1,46 @@ + { + private readonly users: Map = new Map(); + + constructor(private readonly apiUrl: string) {} + + public async findById(id: UserId): Promise { + const user = this.users.get(id); + if (user === undefined) { + return undefined; + } + return user; + } + + public async create(data: Omit): Promise { + const id: number = Math.floor(Math.random() * 1_000_000); + const user = { id, ...data } as T; + this.users.set(id, user); + return user; + } + + public delete(id: UserId): boolean { + return this.users.delete(id); + } + + public list(): readonly T[] { + return Array.from(this.users.values()); + } +} + +const service = new UserService('https://api.example.com'); +const admin: User = { + id: 1, + name: 'Alice', + email: 'alice@example.com', + roles: ['admin'], +}; diff --git a/tests/Bench/HighlighterBench.php b/tests/Bench/HighlighterBench.php index 7a146b9..397d321 100644 --- a/tests/Bench/HighlighterBench.php +++ b/tests/Bench/HighlighterBench.php @@ -39,6 +39,7 @@ final class HighlighterBench 'sql' => 'sql.txt', 'terminal' => 'terminal.txt', 'terraform' => 'terraform.txt', + 'typescript' => 'typescript.txt', 'twig' => 'twig.txt', 'xml' => 'xml.txt', 'yaml' => 'yaml.txt', diff --git a/tests/Languages/TypeScript/TypeScriptLanguageTest.php b/tests/Languages/TypeScript/TypeScriptLanguageTest.php new file mode 100644 index 0000000..c7b12dd --- /dev/null +++ b/tests/Languages/TypeScript/TypeScriptLanguageTest.php @@ -0,0 +1,112 @@ +assertSame( + $expected, + $highlighter->parse($content, 'ts'), + ); + + $this->assertSame( + $expected, + $highlighter->parse($content, 'typescript'), + ); + } + + public static function provide_highlight_cases(): iterable + { + return [ + [ + 'type Alias = string;', + 'type Alias = string;', + ], + [ + <<<'TXT' + interface User { + id: number; + name: string; + } + TXT, + <<<'TXT' + interface User { + id: number; + name: string; + } + TXT, + ], + [ + 'const x: boolean = true;', + 'const x: boolean = true;', + ], + [ + 'readonly name: string;', + 'readonly name: string;', + ], + [ + 'function greet(name: string): void {}', + 'function greet(name: string): void {}', + ], + [ + 'let u: User = getUser();', + 'let u: User = getUser();', + ], + [ + 'function identity(v: T): T {}', + 'function identity<T>(v: T): T {}', + ], + [ + 'class Service {}', + 'class Service<K, V extends Base> {}', + ], + [ + <<<'TXT' + @Component({ selector: 'x' }) + class Foo {} + TXT, + <<<'TXT' + @Component({ selector: 'x' }) + class Foo {} + TXT, + ], + [ + <<<'TXT' + @Injectable + export class Bar {} + TXT, + <<<'TXT' + @Injectable + export class Bar {} + TXT, + ], + [ + <<<'TXT' + /** + * Greet a user. + * @param {string} name + */ + function greet(name: string): void {} + TXT, + <<<'TXT' + /** + * Greet a user. + * @param {string} name + */ + function greet(name: string): void {} + TXT, + ], + ]; + } +}