Skip to content

Commit b82fcc3

Browse files
authored
feat: add Astro-specific review rules (#289)
1 parent 44e4867 commit b82fcc3

3 files changed

Lines changed: 59 additions & 1 deletion

File tree

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#### Obvious Typos or Spelling Errors
2+
- Spelling errors in component names, props, slots, or user-facing strings that affect readability
3+
4+
#### Dead Code
5+
- Unused islands, framework components, scripts, or template branches that add client cost without affecting rendered behavior
6+
7+
#### Astro Component Boundaries
8+
- When frontmatter data reaches client HTML, inline scripts, or hydrated islands, verify whether it was computed at build time or request time and whether exposing non-`PUBLIC_` env values, cookies, headers, sessions, `Astro.locals`, secrets, request-only data, or server-only APIs is intentional
9+
- Flag `.astro` templates that appear to assume frontmatter values are reactive in the browser
10+
- Flag framework components used only to render static markup when plain Astro markup would avoid unnecessary client JavaScript
11+
12+
#### Hydration and Islands
13+
- `client:*` applies only to directly imported UI framework components, not `.astro` components or dynamic tags
14+
- Flag `client:load` on non-critical UI, missed `client:idle` or `client:visible` opportunities, `client:media` where the media query does not actually gate the interaction need, and over-hydration from large or overly numerous islands
15+
- Flag `client:only` without the framework string or without fallback content when the result is blank or confusing pre-hydration UI
16+
17+
#### Server-to-Client Data Transfer
18+
- Flag hydrated framework component props or server-fetched data passed client-side without reducing to the minimal interaction payload; props crossing hydrated boundaries must use Astro-supported serializable types, so flag functions, class instances, circular objects, secrets, and unnecessarily large payloads.
19+
- `<script define:vars>` values are JSON-stringified and inline; flag secrets, large payloads, or repeated per-instance duplication
20+
21+
#### Server Islands
22+
- Flag `server:defer` usage without required adapter support or without a fallback slot when deferred content needs a meaningful loading state
23+
- Props passed into `server:defer` islands must use Astro-supported serializable types; flag functions, circular objects, secrets, and large request objects
24+
- Flag `server:defer` uses that leak request-specific data into cacheable output or weaken privacy assumptions
25+
26+
#### Template Safety
27+
- Treat `set:html` as a high-risk escape hatch; flag it unless the source is clearly trusted or sanitized
28+
- Flag unsafe or insufficiently validated dynamic values inserted into attributes, URLs, or raw markup
29+
- Flag fragile template structures, especially mixed `set:*` usage or conditional markup that changes HTML shape in surprising ways
30+
31+
#### Scripts
32+
- Flag scripts with attributes other than `src` when unprocessed behavior causes avoidable per-instance duplication, bypasses bundling, or relies on server-only values
33+
- Flag framework hydration used for behavior that a small processed Astro script would handle
34+
35+
#### Styles
36+
- Flag unnecessary `is:global` usage when scoped styles or a narrow `:global(...)` escape would do
37+
- Flag selectors that assume scoped CSS can style child component internals across a component boundary
38+
- Flag components that accept parent styling but fail to forward `class` and needed rest props
39+
40+
#### Content and Assets
41+
- For structured Markdown/MDX/JSON content, flag ad hoc loading when Astro content collections would materially improve schema validation, typing, or route generation
42+
- Flag plain `<img>` or `public/` asset usage when the implementation appears to expect Astro image optimization, responsive behavior, fingerprinting, transforms, or import-time validation
43+
44+
#### Markup and Accessibility
45+
- Flag non-semantic or fragile interactive markup, including inaccessible islands before hydration, invalid conditional HTML, or mixed Astro/framework composition that breaks keyboard or focus behavior

internal/config/rules/system_rules.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"**/*.{yaml,yml}": "yaml.md",
1414
"**/*.java": "java.md",
1515
"**/*.ets": "arkts.md",
16+
"**/*.astro": "astro.md",
1617
"**/*.{ts,js,tsx,jsx}": "ts_js_tsx_jsx.md",
1718
"**/*.{kt}": "kotlin.md",
1819
"**/*.rs": "rust.md",

internal/config/rules/system_rules_test.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ func TestResolve_DefaultRules(t *testing.T) {
6767
{"frontend/package.json", "latest"},
6868
{"config/app.yaml", "yaml-key"},
6969
{"deploy/values.yml", "yaml-key"},
70+
{"src/pages/index.astro", "client:*"},
7071
{"src/components/app.tsx", "React"},
7172
{"lib/utils.ts", "TypeScript"},
7273
{"app.kt", "Null Safety"},
@@ -157,12 +158,23 @@ func TestResolve_CaseInsensitive(t *testing.T) {
157158
rule := &SystemRule{
158159
DefaultRule: "default",
159160
PathRules: []PathRule{
161+
{Pattern: "**/*.astro", Rule: "astro-rule"},
160162
{Pattern: "**/*.java", Rule: "java-rule"},
161163
{Pattern: "**/Cargo.toml", Rule: "cargo-rule"},
162164
},
163165
}
164166

165-
got := rule.Resolve("Foo.Java")
167+
got := rule.Resolve("Foo.Astro")
168+
if got != "astro-rule" {
169+
t.Errorf("expected astro-rule for uppercase extension, got %q", got)
170+
}
171+
172+
got = rule.Resolve("foo.astro")
173+
if got != "astro-rule" {
174+
t.Errorf("expected astro-rule for lowercase, got %q", got)
175+
}
176+
177+
got = rule.Resolve("Foo.Java")
166178
if got != "java-rule" {
167179
t.Errorf("expected java-rule for uppercase extension, got %q", got)
168180
}

0 commit comments

Comments
 (0)