Skip to content

Commit 3683bb4

Browse files
committed
test markdown changelogs, refine filter elements plugin
1 parent d77aaaf commit 3683bb4

File tree

6 files changed

+154
-12
lines changed

6 files changed

+154
-12
lines changed

package-lock.json

Lines changed: 77 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,15 @@
8484
"react-icons": "5.4.0",
8585
"react-markdown": "9.0.3",
8686
"redirects-in-workers": "0.0.5",
87-
"rehype": "13.0.2",
8887
"rehype-autolink-headings": "7.1.0",
8988
"rehype-external-links": "3.0.0",
89+
"rehype-parse": "9.0.1",
90+
"rehype-remark": "10.0.0",
91+
"rehype-stringify": "10.0.1",
9092
"rehype-title-figure": "0.1.2",
9193
"remark": "15.0.1",
94+
"remark-gfm": "4.0.0",
95+
"remark-stringify": "11.0.0",
9296
"sharp": "0.33.5",
9397
"solarflare-theme": "0.0.2",
9498
"starlight-image-zoom": "0.10.1",
@@ -102,6 +106,7 @@
102106
"tsx": "4.19.2",
103107
"typescript": "5.7.3",
104108
"typescript-eslint": "8.20.0",
109+
"unified": "11.0.5",
105110
"unist-util-visit": "5.0.0",
106111
"vitest": "2.1.9",
107112
"wrangler": "3.103.2"
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import rss from "@astrojs/rss";
2+
import type { APIRoute } from "astro";
3+
import { getChangelogs, getRSSItems } from "~/util/changelogs";
4+
5+
export const GET: APIRoute = async ({ locals }) => {
6+
const notes = await getChangelogs({});
7+
8+
const items = await getRSSItems({
9+
notes,
10+
locals,
11+
markdown: true,
12+
});
13+
14+
return rss({
15+
title: "Changelogs",
16+
description: `Cloudflare changelogs - If you would like content as HTML, rather than Markdown, please use https://developers.cloudflare.com/changelog-next/index.xml`,
17+
site: "https://developers.cloudflare.com/changelog-next/",
18+
items,
19+
});
20+
};

src/pages/changelog-next/rss/index.xml.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export const GET: APIRoute = async ({ locals }) => {
1212

1313
return rss({
1414
title: "Changelogs",
15-
description: `Cloudflare changelogs`,
15+
description: `Cloudflare changelogs - If you would like content as Markdown, rather than HTML, please use https://developers.cloudflare.com/changelog-next/index.md.xml`,
1616
site: "https://developers.cloudflare.com/changelog-next/",
1717
items,
1818
});

src/plugins/rehype/filter-elements.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ const ALLOWED_ATTRIBUTES: Record<string, string[]> = {
101101

102102
const UNWRAP_CLASS_NAMES = ["heading-wrapper"];
103103

104-
const DISALLOWED_CLASS_NAMES = ["external-link"];
104+
const DISALLOWED_CLASS_NAMES = ["external-link", "anchor-link"];
105105

106106
export default function () {
107107
return function (tree: Root) {
@@ -114,14 +114,14 @@ export default function () {
114114
return remove(index, parent);
115115
}
116116

117-
if (UNWRAP_CLASS_NAMES.some((v) => classNames.includes(v))) {
118-
return unwrap(index, parent, element);
119-
}
120-
121117
if (DISALLOWED_CLASS_NAMES.some((v) => classNames.includes(v))) {
122118
return remove(index, parent);
123119
}
124120

121+
if (UNWRAP_CLASS_NAMES.some((v) => classNames.includes(v))) {
122+
return unwrap(index, parent, element);
123+
}
124+
125125
for (const key of Object.keys(element.properties)) {
126126
if (!ALLOWED_ATTRIBUTES[tag]?.includes(key)) {
127127
delete element.properties[key];

src/util/changelogs.ts

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
import type { RSSFeedItem } from "@astrojs/rss";
22
import { getCollection, getEntries, type CollectionEntry } from "astro:content";
3-
import { rehype } from "rehype";
43
import { entryToString } from "~/util/container";
4+
5+
import { unified, type PluggableList } from "unified";
6+
7+
import rehypeParse from "rehype-parse";
8+
import rehypeStringify from "rehype-stringify";
9+
import rehypeBaseUrl from "~/plugins/rehype/base-url";
510
import rehypeFilterElements from "~/plugins/rehype/filter-elements";
611

12+
import rehypeRemark from "rehype-remark";
13+
import remarkGfm from "remark-gfm";
14+
import remarkStringify from "remark-stringify";
15+
716
type DocsToChangelogOptions = {
817
name: string;
918
product: string;
@@ -114,13 +123,32 @@ export async function getChangelogs({
114123
}
115124

116125
type GetRSSItemsOptions = {
126+
/**
127+
* An array of changelog entries from the `getChangelogs({})` function.
128+
* @see {@link getChangelogs}
129+
*/
117130
notes: Array<CollectionEntry<"changelogs-next">>;
131+
/**
132+
* `locals`, either from `Astro.locals` in custom pages or
133+
* `context.locals` in endpoints.
134+
* @see {@link https://docs.astro.build/en/reference/api-reference/#locals}
135+
*/
118136
locals: App.Locals;
137+
/**
138+
* Returns Markdown in the `<content:encoded>` field instead of HTML.
139+
* Markdown will contain `\n` in the output, as fast-xml-parser outputs
140+
* single-line strings.
141+
*
142+
* @example
143+
* # heading\n\ntext\ntext
144+
*/
145+
markdown?: boolean;
119146
};
120147

121148
export async function getRSSItems({
122149
notes,
123150
locals,
151+
markdown,
124152
}: GetRSSItemsOptions): Promise<Array<RSSFeedItem>> {
125153
return await Promise.all(
126154
notes.map(async (note) => {
@@ -130,14 +158,27 @@ export async function getRSSItems({
130158
const productTitles = productEntries.map((p) => p.data.name);
131159

132160
const html = await entryToString(note, locals);
133-
const file = await rehype()
161+
162+
let plugins: PluggableList = [
163+
rehypeParse,
164+
rehypeBaseUrl,
165+
rehypeFilterElements,
166+
];
167+
168+
if (markdown) {
169+
plugins = plugins.concat([rehypeRemark, remarkGfm, remarkStringify]);
170+
} else {
171+
plugins = plugins.concat([rehypeStringify]);
172+
}
173+
174+
const file = await unified()
134175
.data("settings", {
135176
fragment: true,
136177
})
137-
.use(rehypeFilterElements)
178+
.use(plugins)
138179
.process(html);
139180

140-
const content = String(file);
181+
const content = String(file).trim();
141182

142183
return {
143184
title: `${productTitles.join(", ")} - ${title}`,

0 commit comments

Comments
 (0)