Skip to content

Commit 40fef30

Browse files
authored
feat(rules): add no-prerender-export-outside-pages rule (#550)
* feat: add no-prerender-export-outside-pages rule * feat: add docs for no-prerender-export-outside-pages * chore: add changeset
1 parent cf45890 commit 40fef30

File tree

9 files changed

+168
-0
lines changed

9 files changed

+168
-0
lines changed

.changeset/funny-chicken-ring.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"eslint-plugin-astro": minor
3+
---
4+
5+
add `astro/no-prerender-export-outside-pages` rule that disallow `prerender` export outside of pages/ directory
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
title: "astro/no-prerender-export-outside-pages"
3+
description: "disallow `prerender` export outside of pages/ directory"
4+
---
5+
6+
# astro/no-prerender-export-outside-pages
7+
8+
> disallow `prerender` export outside of pages/ directory
9+
10+
## 📖 Rule Details
11+
12+
This rule reports `prerender` exports from Astro files that are not inside a `pages/` directory.
13+
14+
The `prerender` directive only has an effect on page files (files under `src/pages/`). Exporting it from components or layouts has no effect.
15+
16+
<ESLintCodeBlock>
17+
18+
<!--eslint-skip-->
19+
20+
```astro
21+
---
22+
/* eslint astro/no-prerender-export-outside-pages: "error" */
23+
24+
/* ✓ GOOD — in src/pages/index.astro */
25+
export const prerender = true
26+
27+
/* ✗ BAD — in src/components/MyComponent.astro */
28+
export const prerender = true
29+
---
30+
```
31+
32+
</ESLintCodeBlock>
33+
34+
## 🔧 Options
35+
36+
Nothing.
37+
38+
## 🔇 When Not To Use It
39+
40+
If your project doesn't use hybrid rendering or if all files under `src/pages/` don't need prerender exports, you may disable this rule.
41+
42+
## 📚 Further Reading
43+
44+
- [Astro Docs: On-demand Rendering](https://docs.astro.build/en/guides/on-demand-rendering/)
45+
- [Astro Docs: `prerender` export](https://docs.astro.build/en/reference/routing-reference/#prerender)
46+
47+
## 🔍 Implementation
48+
49+
- [Rule source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/src/rules/no-prerender-export-outside-pages.ts)
50+
- [Test source](https://github.com/ota-meshi/eslint-plugin-astro/blob/main/tests/src/rules/no-prerender-export-outside-pages.ts)
51+
- [Test fixture sources](https://github.com/ota-meshi/eslint-plugin-astro/tree/main/tests/fixtures/rules/no-prerender-export-outside-pages)

src/rules/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import noDeprecatedAstroFetchcontent from "./no-deprecated-astro-fetchcontent.ts
88
import noDeprecatedAstroResolve from "./no-deprecated-astro-resolve.ts"
99
import noDeprecatedGetentrybyslug from "./no-deprecated-getentrybyslug.ts"
1010
import noExportsFromComponents from "./no-exports-from-components.ts"
11+
import noPrerenderExportOutsidePages from "./no-prerender-export-outside-pages.ts"
1112
import noSetHtmlDirective from "./no-set-html-directive.ts"
1213
import noSetTextDirective from "./no-set-text-directive.ts"
1314
import noUnsafeInlineScripts from "./no-unsafe-inline-scripts.ts"
@@ -30,6 +31,7 @@ export const originalRules: RuleModule[] = [
3031
noDeprecatedAstroResolve,
3132
noDeprecatedGetentrybyslug,
3233
noExportsFromComponents,
34+
noPrerenderExportOutsidePages,
3335
noSetHtmlDirective,
3436
noSetTextDirective,
3537
noUnsafeInlineScripts,
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import type { TSESTree } from "@typescript-eslint/types"
2+
import type { RuleModule } from "../types.ts"
3+
import { createRule } from "../utils/index.ts"
4+
import { getSourceCode, getFilename } from "../utils/compat.ts"
5+
6+
const PAGES_DIR_PATTERN = /(?:^|[/\\])pages[/\\]/
7+
8+
const rule: RuleModule = createRule("no-prerender-export-outside-pages", {
9+
meta: {
10+
docs: {
11+
description: "disallow `prerender` export outside of pages/ directory",
12+
category: "Possible Errors",
13+
recommended: false,
14+
},
15+
schema: [],
16+
messages: {
17+
disallowPrerenderOutsidePages:
18+
"'prerender' export is only valid inside a pages/ directory.",
19+
},
20+
type: "problem",
21+
},
22+
create(context) {
23+
const sourceCode = getSourceCode(context)
24+
if (!sourceCode.parserServices?.isAstro) {
25+
return {}
26+
}
27+
28+
const filename = getFilename(context)
29+
if (PAGES_DIR_PATTERN.test(filename)) {
30+
return {}
31+
}
32+
33+
/**
34+
* Verify for export declarations
35+
*/
36+
function verifyDeclaration(
37+
node: TSESTree.ExportNamedDeclaration["declaration"],
38+
) {
39+
if (!node) return
40+
if (
41+
node.type === "VariableDeclaration" &&
42+
node.declarations.some(
43+
(decl) =>
44+
decl.id.type === "Identifier" && decl.id.name === "prerender",
45+
)
46+
) {
47+
context.report({
48+
node,
49+
messageId: "disallowPrerenderOutsidePages",
50+
})
51+
}
52+
}
53+
54+
return {
55+
ExportNamedDeclaration(node) {
56+
if (node.exportKind === "type") return
57+
verifyDeclaration(node.declaration)
58+
for (const spec of node.specifiers) {
59+
if (spec.exportKind === "type") continue
60+
if (
61+
spec.exported.type === "Identifier" &&
62+
spec.exported.name === "prerender"
63+
) {
64+
context.report({
65+
node: spec,
66+
messageId: "disallowPrerenderOutsidePages",
67+
})
68+
}
69+
}
70+
},
71+
}
72+
},
73+
})
74+
75+
export default rule
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[
2+
{
3+
"message": "'prerender' export is only valid inside a pages/ directory.",
4+
"line": 2,
5+
"column": 8
6+
}
7+
]
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
export const prerender = true
3+
---
4+
<div>Component</div>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
const foo = "bar"
3+
---
4+
<div>Component</div>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
export const prerender = true
3+
---
4+
<div>Page</div>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { RuleTester } from "../../utils/eslint-compat.ts"
2+
import rule from "../../../src/rules/no-prerender-export-outside-pages.ts"
3+
import { loadTestCases } from "../../utils/utils.ts"
4+
5+
const tester = new RuleTester({
6+
languageOptions: {
7+
ecmaVersion: 2020,
8+
sourceType: "module",
9+
},
10+
})
11+
12+
tester.run(
13+
"no-prerender-export-outside-pages",
14+
rule as any,
15+
loadTestCases("no-prerender-export-outside-pages"),
16+
)

0 commit comments

Comments
 (0)