Skip to content

Commit 122e010

Browse files
Add Astro lexer (#1296)
Closes #1293. ## Summary Adds a Chroma lexer for Astro components. The lexer supports: - `.astro` filename matching and the `astro` alias - TypeScript frontmatter fences, including CRLF line endings - Astro template expressions such as `{title}` and dynamic attributes - Common Astro attribute/directive forms such as shorthand props, `class:list`, `client:load`, and `set:html` - Embedded `<script>` blocks, including JSON, explicit JavaScript, explicit TypeScript, and default TypeScript - Embedded `<style>` blocks for CSS, SCSS, Sass, and Stylus Also adds lexer fixture coverage and updates the supported language list. ## Tests - [x] `go test ./lexers` - [x] `go test ./...` --------- Co-authored-by: Alec Thomas <alec@swapoff.org>
1 parent deca444 commit 122e010

5 files changed

Lines changed: 517 additions & 1 deletion

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ translators for Pygments lexers and styles.
3939

4040
| Prefix | Language
4141
| :----: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
42-
| A | ABAP, ABNF, ActionScript, ActionScript 3, Ada, Agda, AL, Alloy, AMPL, Angular2, ANTLR, ApacheConf, APL, AppleScript, ArangoDB AQL, Arduino, ArmAsm, Arturo, ATL, AutoHotkey, AutoIt, Awk
42+
| A | ABAP, ABNF, ActionScript, ActionScript 3, Ada, Agda, AL, Alloy, AMPL, Angular2, ANTLR, ApacheConf, APL, AppleScript, ArangoDB AQL, Arduino, ArmAsm, Arturo, Astro, ATL, AutoHotkey, AutoIt, Awk
4343
| B | Ballerina, Bash, Bash Session, Batchfile, Beef, BibTeX, Bicep, BlitzBasic, BNF, BQN, Brainfuck
4444
| C | C, C#, C++, C3, Caddyfile, Caddyfile Directives, Cap'n Proto, Cassandra CQL, Ceylon, CFEngine3, cfstatement, ChaiScript, Chapel, Cheetah, Clojure, CMake, COBOL, CoffeeScript, Common Lisp, Coq, Core, Crystal, CSS, CSV, CUE, Cython
4545
| D | D, Dart, Dax, Desktop file, Devicetree, Diff, Django/Jinja, dns, Docker, DTD, Dylan

lexers/astro.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package lexers
2+
3+
import (
4+
. "github.com/alecthomas/chroma/v3" // nolint
5+
)
6+
7+
// Astro lexer.
8+
var Astro = Register(DelegatingLexer(
9+
HTML,
10+
MustNewXMLLexer(embedded, "embedded/astro.xml"),
11+
))

lexers/embedded/astro.xml

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<lexer>
2+
<config>
3+
<name>Astro</name>
4+
<alias>astro</alias>
5+
<filename>*.astro</filename>
6+
<mime_type>text/x-astro</mime_type>
7+
<case_insensitive>true</case_insensitive>
8+
<dot_all>true</dot_all>
9+
</config>
10+
<rules>
11+
<state name="root">
12+
<rule pattern="(\A---[ \t]*\r?\n)(.*?)(^---[ \t]*(?:\r?\n|$))">
13+
<bygroups>
14+
<token type="CommentPreproc"/>
15+
<using lexer="TypeScript"/>
16+
<token type="CommentPreproc"/>
17+
</bygroups>
18+
</rule>
19+
<rule pattern="&lt;!--">
20+
<token type="Other"/>
21+
<push state="comment"/>
22+
</rule>
23+
<rule pattern="(&lt;\s*script\b(?=[^&gt;]*(?:lang|type)\s*=\s*['&#34;]?(?:json|application/(?:ld\+)?json|importmap|speculationrules)(?:['&#34;]|[\s&gt;]))[^&gt;]*&gt;)(.*?)(&lt;\s*/\s*script\s*&gt;)">
24+
<bygroups>
25+
<token type="Other"/>
26+
<using lexer="JSON"/>
27+
<token type="Other"/>
28+
</bygroups>
29+
</rule>
30+
<rule pattern="(&lt;\s*script\b(?=[^&gt;]*(?:lang|type)\s*=\s*['&#34;]?(?:js|javascript|text/javascript|application/(?:x-)?javascript|text/ecmascript|application/ecmascript|module)(?:['&#34;]|[\s&gt;]))[^&gt;]*&gt;)(.*?)(&lt;\s*/\s*script\s*&gt;)">
31+
<bygroups>
32+
<token type="Other"/>
33+
<using lexer="JavaScript"/>
34+
<token type="Other"/>
35+
</bygroups>
36+
</rule>
37+
<rule pattern="(&lt;\s*script\b(?=[^&gt;]*(?:lang|type)\s*=\s*['&#34;]?(?:ts|typescript|text/typescript|application/typescript)(?:['&#34;]|[\s&gt;]))[^&gt;]*&gt;)(.*?)(&lt;\s*/\s*script\s*&gt;)">
38+
<bygroups>
39+
<token type="Other"/>
40+
<using lexer="TypeScript"/>
41+
<token type="Other"/>
42+
</bygroups>
43+
</rule>
44+
<rule pattern="(&lt;\s*script\b[^&gt;]*&gt;)(.*?)(&lt;\s*/\s*script\s*&gt;)">
45+
<bygroups>
46+
<token type="Other"/>
47+
<using lexer="TypeScript"/>
48+
<token type="Other"/>
49+
</bygroups>
50+
</rule>
51+
<rule pattern="(&lt;\s*style\b(?=[^&gt;]*lang\s*=\s*['&#34;]?(?:scss|source\.scss|source\.css\.scss)(?:['&#34;]|[\s&gt;]))[^&gt;]*&gt;)(.*?)(&lt;\s*/\s*style\s*&gt;)">
52+
<bygroups>
53+
<token type="Other"/>
54+
<using lexer="SCSS"/>
55+
<token type="Other"/>
56+
</bygroups>
57+
</rule>
58+
<rule pattern="(&lt;\s*style\b(?=[^&gt;]*lang\s*=\s*['&#34;]?(?:sass|source\.sass)(?:['&#34;]|[\s&gt;]))[^&gt;]*&gt;)(.*?)(&lt;\s*/\s*style\s*&gt;)">
59+
<bygroups>
60+
<token type="Other"/>
61+
<using lexer="Sass"/>
62+
<token type="Other"/>
63+
</bygroups>
64+
</rule>
65+
<rule pattern="(&lt;\s*style\b(?=[^&gt;]*lang\s*=\s*['&#34;]?(?:stylus|source\.stylus)(?:['&#34;]|[\s&gt;]))[^&gt;]*&gt;)(.*?)(&lt;\s*/\s*style\s*&gt;)">
66+
<bygroups>
67+
<token type="Other"/>
68+
<using lexer="Stylus"/>
69+
<token type="Other"/>
70+
</bygroups>
71+
</rule>
72+
<rule pattern="(&lt;\s*style\b[^&gt;]*&gt;)(.*?)(&lt;\s*/\s*style\s*&gt;)">
73+
<bygroups>
74+
<token type="Other"/>
75+
<using lexer="CSS"/>
76+
<token type="Other"/>
77+
</bygroups>
78+
</rule>
79+
<rule pattern="(\s*)(=)(\s*)({)">
80+
<bygroups>
81+
<token type="Text"/>
82+
<token type="Operator"/>
83+
<token type="Text"/>
84+
<token type="Punctuation"/>
85+
</bygroups>
86+
<push state="expression"/>
87+
</rule>
88+
<rule pattern="{">
89+
<token type="Punctuation"/>
90+
<push state="expression"/>
91+
</rule>
92+
<rule pattern=".+?">
93+
<token type="Other"/>
94+
</rule>
95+
</state>
96+
<state name="comment">
97+
<rule pattern="--&gt;">
98+
<token type="Other"/>
99+
<pop depth="1"/>
100+
</rule>
101+
<rule pattern=".+?">
102+
<token type="Other"/>
103+
</rule>
104+
</state>
105+
<state name="expression">
106+
<rule pattern="}">
107+
<token type="Punctuation"/>
108+
<pop depth="1"/>
109+
</rule>
110+
<rule pattern="(?&lt;!(?&lt;!\\)\\)(['&#34;`]).*?(?&lt;!(?&lt;!\\)\\)\1">
111+
<using lexer="TypeScript"/>
112+
</rule>
113+
<rule pattern="{">
114+
<token type="Punctuation"/>
115+
<push state="expression"/>
116+
</rule>
117+
<rule pattern="[^{}]+">
118+
<using lexer="TypeScript"/>
119+
</rule>
120+
</state>
121+
</rules>
122+
</lexer>

lexers/testdata/astro.actual

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
---
2+
import Layout from "../layouts/Layout.astro";
3+
import Card from "../components/Card.astro";
4+
5+
interface Props {
6+
title: string;
7+
}
8+
9+
const { title } = Astro.props;
10+
const items = ["alpha", "beta"];
11+
---
12+
<!-- Comments with <script> tags stay HTML comments. -->
13+
<Layout title={title}>
14+
<h1 class:list={["title", { active: title.length > 0 }]}>Hello {title}</h1>
15+
<Card {title} client:load data-items={items.join(",")} />
16+
<p set:html={title} />
17+
18+
<ul>
19+
{items.map((item) => (
20+
<li class={`item-${item}`}>{item.toUpperCase()}</li>
21+
))}
22+
</ul>
23+
24+
<script type="application/ld+json">
25+
{ "name": "Astro", "isAccessibleForFree": true }
26+
</script>
27+
28+
<script lang="ts">
29+
const button = document.querySelector("button");
30+
button?.addEventListener("click", () => console.log(title));
31+
</script>
32+
33+
<script>
34+
const message: string = title;
35+
document.body.dataset.message = message;
36+
</script>
37+
38+
<style>
39+
h1 {
40+
color: rebeccapurple;
41+
}
42+
</style>
43+
44+
<style lang="scss">
45+
$title-color: #639;
46+
h1 {
47+
color: $title-color;
48+
}
49+
</style>
50+
</Layout>

0 commit comments

Comments
 (0)