@@ -13,9 +13,32 @@ import rehypeRemark from "rehype-remark";
1313import remarkGfm from "remark-gfm" ;
1414import remarkStringify from "remark-stringify" ;
1515
16+ function toISODate ( date : Date ) {
17+ return date . toISOString ( ) . slice ( 0 , 10 ) ;
18+ }
19+
1620type DocsToChangelogOptions = {
17- name : string ;
21+ /**
22+ * An optional title to be prefixed before the date.
23+ * This is only necessary if you require an extra product name.
24+ *
25+ * @example
26+ * `HTTP DDoS managed ruleset`
27+ */
28+ name ?: string ;
29+ /**
30+ * Name of a product which must match a filename in the
31+ * src/content/products/ collection, without the
32+ * file extension.
33+ *
34+ * @example
35+ * `ddos-protection`
36+ */
1837 product : string ;
38+ /**
39+ * A changelog entry from the `getChangelogs({})` function.
40+ * @see {@link getChangelogs}
41+ */
1942 entry : CollectionEntry < "docs" > ;
2043} ;
2144
@@ -25,23 +48,31 @@ function docsToChangelog({
2548 entry,
2649} : DocsToChangelogOptions ) : CollectionEntry < "changelogs-next" > {
2750 const { data } = entry ;
28- const { title, changelog } = data ;
2951
30- let date ;
31- if ( changelog ?. date ) {
32- date = changelog . date ;
52+ // `data.changelog` will exist as the existence of this
53+ // property is part of the `getChangelogs` filter.
54+ const date = data . changelog ! . date ;
55+ const scheduled = data . changelog ! . scheduled ;
56+
57+ const iso8601 = toISODate ( date ) ;
58+
59+ let title ;
60+ if ( scheduled ) {
61+ title = `Scheduled for ${ toISODate ( scheduled ) } ` ;
3362 } else {
34- date = new Date ( data . title . split ( " " ) [ 0 ] ) ;
63+ title = iso8601 ;
3564 }
3665
37- const iso8601 = date . toISOString ( ) . slice ( 0 , 10 ) ;
66+ if ( name ) {
67+ title = `${ name } - ${ title } ` ;
68+ }
3869
3970 return {
4071 ...entry ,
4172 collection : "changelogs-next" ,
4273 data : {
4374 title,
44- description : `${ name } - ${ iso8601 } ` ,
75+ description : `${ name } - ${ toISODate ( date ) } ` ,
4576 date,
4677 products : [ { collection : "products" , id : product } ] ,
4778 link : `/${ entry . id } /` ,
@@ -66,8 +97,7 @@ export async function getChangelogs({
6697
6798 const ddosHttp = await getCollection ( "docs" , ( e ) => {
6899 return (
69- e . id . startsWith ( "ddos-protection/change-log/http/" ) &&
70- e . data . pcx_content_type === "changelog"
100+ e . id . startsWith ( "ddos-protection/change-log/http/" ) && e . data . changelog
71101 ) ;
72102 } ) ;
73103
@@ -83,8 +113,7 @@ export async function getChangelogs({
83113
84114 const ddosNetwork = await getCollection ( "docs" , ( e ) => {
85115 return (
86- e . id . startsWith ( "ddos-protection/change-log/network/" ) &&
87- e . data . pcx_content_type === "changelog"
116+ e . id . startsWith ( "ddos-protection/change-log/network/" ) && e . data . changelog
88117 ) ;
89118 } ) ;
90119
@@ -99,16 +128,12 @@ export async function getChangelogs({
99128 . forEach ( ( e ) => entries . push ( e ) ) ;
100129
101130 const waf = await getCollection ( "docs" , ( e ) => {
102- return (
103- e . id . startsWith ( "waf/change-log/" ) &&
104- e . data . pcx_content_type === "changelog"
105- ) ;
131+ return e . id . startsWith ( "waf/change-log/" ) && e . data . changelog ;
106132 } ) ;
107133
108134 waf
109135 . map ( ( e ) =>
110136 docsToChangelog ( {
111- name : "WAF" ,
112137 product : "waf" ,
113138 entry : e ,
114139 } ) ,
@@ -136,41 +161,51 @@ type GetRSSItemsOptions = {
136161 locals : App . Locals ;
137162 /**
138163 * 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
144164 */
145165 markdown ?: boolean ;
166+ /**
167+ * Creates items in the same way as historic changelogs. The behaviour of
168+ * this option should not be changed, all improvements should be made
169+ * to the normal RSS feeds.
170+ *
171+ * The differences between normal items and legacy items are:
172+ *
173+ * - HTML is not filtered by our `filter-elements` plugin.
174+ * - HTML is in the `description` element rather than `content:encoded`.
175+ * - Only the first product can be shown in the title and the custom `<product>` element.
176+ */
177+ legacy ?: boolean ;
146178} ;
147179
148180export async function getRSSItems ( {
149181 notes,
150182 locals,
151183 markdown,
184+ legacy,
152185} : GetRSSItemsOptions ) : Promise < Array < RSSFeedItem > > {
153186 return await Promise . all (
154187 notes . map ( async ( note ) => {
155188 const { title, description, date, products, link } = note . data ;
156189
157190 const productEntries = await getEntries ( products ) ;
158- const productTitles = productEntries . map ( ( p ) => p . data . name ) ;
191+ const productTitles = productEntries . map ( ( p ) => p . data . name as string ) ;
159192
160193 const html = await entryToString ( note , locals ) ;
161194
162- let plugins : PluggableList = [
163- rehypeParse ,
164- rehypeBaseUrl ,
165- rehypeFilterElements ,
166- ] ;
195+ const plugins : PluggableList = [ rehypeParse , rehypeBaseUrl ] ;
196+
197+ if ( ! legacy ) {
198+ plugins . push ( ... [ rehypeFilterElements ] ) ;
199+ }
167200
168201 if ( markdown ) {
169- plugins = plugins . concat ( [ rehypeRemark , remarkGfm , remarkStringify ] ) ;
202+ plugins . push ( ... [ rehypeRemark , remarkGfm , remarkStringify ] ) ;
170203 } else {
171- plugins = plugins . concat ( [ rehypeStringify ] ) ;
204+ plugins . push ( ... [ rehypeStringify ] ) ;
172205 }
173206
207+ console . log ( plugins ) ;
208+
174209 const file = await unified ( )
175210 . data ( "settings" , {
176211 fragment : true ,
@@ -180,6 +215,19 @@ export async function getRSSItems({
180215
181216 const content = String ( file ) . trim ( ) ;
182217
218+ if ( legacy ) {
219+ // Only a single product title is supported in legacy items.
220+ const productTitle = productTitles . at ( 0 ) ;
221+
222+ return {
223+ title : `${ productTitle } - ${ title } ` ,
224+ description : content ,
225+ pubDate : date ,
226+ link,
227+ customData : `<product>${ productTitle } </product>` ,
228+ } ;
229+ }
230+
183231 return {
184232 title : `${ productTitles . join ( ", " ) } - ${ title } ` ,
185233 description,
0 commit comments