diff --git a/antora-playbook-local.yml b/antora-playbook-local.yml
index 3f6ce3c0fe..b683a22556 100644
--- a/antora-playbook-local.yml
+++ b/antora-playbook-local.yml
@@ -17,5 +17,10 @@ ui:
asciidoc:
extensions:
- '@tinymce/antora-extension-livedemos'
+antora:
+ extensions:
+ - require: './extensions/rssfeed.cjs'
+ input_file: 'changelog.adoc'
+ output_file: 'rss.xml'
runtime:
fetch: true
diff --git a/antora-playbook.yml b/antora-playbook.yml
index c5fc872959..4e6b70065b 100644
--- a/antora-playbook.yml
+++ b/antora-playbook.yml
@@ -19,5 +19,10 @@ ui:
asciidoc:
extensions:
- '@tinymce/antora-extension-livedemos'
+antora:
+ extensions:
+ - require: './extensions/rssfeed.cjs'
+ input_file: 'changelog.adoc'
+ output_file: 'rss.xml'
runtime:
fetch: true
diff --git a/extensions/rssfeed.cjs b/extensions/rssfeed.cjs
new file mode 100644
index 0000000000..fa639e6a41
--- /dev/null
+++ b/extensions/rssfeed.cjs
@@ -0,0 +1,119 @@
+"use strict";
+
+const cheerio = require("cheerio");
+
+module.exports.register = function ({ config }) {
+ this.on("beforePublish", ({ siteCatalog, contentCatalog, playbook }) => {
+ const startTime = Date.now(); // Start the timer
+
+ try {
+ // Find the changelog page
+ const page = contentCatalog.findBy({
+ basename: config.inputFile,
+ })[0];
+
+ if (!page) {
+ throw new Error(`${config.inputFile} page not found.`);
+ }
+
+ // Destructure page attributes
+ const {
+ productname: productName,
+ productmajorversion: productMajorVersion,
+ doctitle: pageTitle,
+ description: pageDescription,
+ docname: pageName,
+ "page-component-name": pageComponentName,
+ "page-component-version": pageComponentVersion,
+ } = page.asciidoc.attributes;
+
+ // Construct site links
+ const siteLink = playbook.site.url;
+ const siteLinkWithVersion = `${siteLink}/${pageComponentName}/${pageComponentVersion}`;
+ const filePath = `${pageComponentName}/${pageComponentVersion}/${config.outputFile}`;
+
+ // Load page content with cheerio
+ const $ = cheerio.load(page.contents.toString());
+
+ // Extract releases
+ const releases = $(".sect1")
+ .map((_, element) => {
+ const $element = $(element);
+ const linkElement = $element.find("a.xref");
+ let [version, date] = linkElement.text().split(" - ");
+
+ // Normalize version if it's missing the minor or patch version
+ const versionParts = version.split(".");
+ if (versionParts.length === 1) {
+ version += ".0.0";
+ } else if (versionParts.length === 2) {
+ version += ".0";
+ }
+
+ // Remove
tags inside
tags to fix rendering issues
+ const contentElement = $element.find(".sectionbody");
+ contentElement.find("li > p").each((_, pElem) => {
+ $(pElem).replaceWith($(pElem).html());
+ });
+ const content = contentElement.html();
+
+ return {
+ title: linkElement.text(),
+ link: `${siteLinkWithVersion}/${linkElement
+ .attr("href")
+ .replace(/\.\.\//g, "")}`,
+ description: `Changelog for TinyMCE ${version}`,
+ guid: version,
+ pubDate: new Date(date).toUTCString(),
+ content,
+ };
+ })
+ .get();
+
+ // Generate RSS feed items
+ const rssItems = releases
+ .map(
+ ({ title, link, description, guid, pubDate, content }) => `
+ -
+ ${title}
+ ${link}
+ ${description}
+ ${guid}
+ ${pubDate}
+
+
`
+ )
+ .join("\n");
+
+ // Assemble the complete RSS feed
+ const rss = `
+
+
+ ${productName} ${productMajorVersion} ${pageTitle}
+ ${siteLinkWithVersion}/${pageName}
+ ${pageDescription}
+ en
+ Creative Commons Legal Code - Attribution-NonCommercial-ShareAlike 3.0 Unported
+
+ ${rssItems}
+
+ `;
+
+ // Add RSS feed to site catalog
+ siteCatalog.addFile({
+ contents: Buffer.from(rss),
+ out: { path: filePath },
+ });
+
+ const endTime = Date.now(); // End the timer
+ const duration = endTime - startTime; // Calculate the duration
+ console.log(`RSS feed generated at ${filePath} in ${duration}ms`);
+ } catch (error) {
+ // Catch any errors to allow the build to continue
+ console.error("Error generating RSS feed:", error);
+ }
+ });
+};
diff --git a/modules/ROOT/pages/changelog.adoc b/modules/ROOT/pages/changelog.adoc
index f634eb7061..38ae934c63 100644
--- a/modules/ROOT/pages/changelog.adoc
+++ b/modules/ROOT/pages/changelog.adoc
@@ -4,6 +4,8 @@
NOTE: This is the {productname} Community version changelog. For information about the latest {cloudname} or {enterpriseversion} Release, see: xref:release-notes.adoc[{productname} Release Notes].
+TIP: For an RSS feed of the {productname} Changelog, use the following URL: {site-url}/{page-component-name}/{page-component-version}/rss.xml
+
== xref:7.6.0-release-notes.adoc[7.6.0 - 2024-12-11]
=== Added
diff --git a/package.json b/package.json
index 9a24a18b76..0f6474e17f 100644
--- a/package.json
+++ b/package.json
@@ -36,6 +36,7 @@
"@antora/site-generator-default": "^3.0.1",
"@tinymce/antora-extension-livedemos": "^0.1.0",
"@tinymce/moxiedoc": "^0.3.0",
+ "cheerio": "^1.0.0",
"dotenv": "^16.0.0",
"ecstatic": "^4.1.4",
"http-server": "^0.12.3",
diff --git a/yarn.lock b/yarn.lock
index 847402296c..526ad33ef2 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -330,6 +330,11 @@ binary-extensions@^2.0.0:
resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz"
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
+boolbase@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
+ integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
+
boxen@^5.0.0:
version "5.1.2"
resolved "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz"
@@ -439,6 +444,35 @@ charset@^1.0.1:
resolved "https://registry.npmjs.org/charset/-/charset-1.0.1.tgz"
integrity sha512-6dVyOOYjpfFcL1Y4qChrAoQLRHvj2ziyhcm0QJlhOcAhykL/k1kTUPbeo+87MNRTRdk2OIIsIXbuF3x2wi5EXg==
+cheerio-select@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/cheerio-select/-/cheerio-select-2.1.0.tgz#4d8673286b8126ca2a8e42740d5e3c4884ae21b4"
+ integrity sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==
+ dependencies:
+ boolbase "^1.0.0"
+ css-select "^5.1.0"
+ css-what "^6.1.0"
+ domelementtype "^2.3.0"
+ domhandler "^5.0.3"
+ domutils "^3.0.1"
+
+cheerio@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0.tgz#1ede4895a82f26e8af71009f961a9b8cb60d6a81"
+ integrity sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==
+ dependencies:
+ cheerio-select "^2.1.0"
+ dom-serializer "^2.0.0"
+ domhandler "^5.0.3"
+ domutils "^3.1.0"
+ encoding-sniffer "^0.2.0"
+ htmlparser2 "^9.1.0"
+ parse5 "^7.1.2"
+ parse5-htmlparser2-tree-adapter "^7.0.0"
+ parse5-parser-stream "^7.1.2"
+ undici "^6.19.5"
+ whatwg-mimetype "^4.0.0"
+
chokidar@^3.5.2:
version "3.5.2"
resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz"
@@ -621,6 +655,22 @@ crypto-random-string@^2.0.0:
resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz"
integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
+css-select@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/css-select/-/css-select-5.1.0.tgz#b8ebd6554c3637ccc76688804ad3f6a6fdaea8a6"
+ integrity sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==
+ dependencies:
+ boolbase "^1.0.0"
+ css-what "^6.1.0"
+ domhandler "^5.0.2"
+ domutils "^3.0.1"
+ nth-check "^2.0.1"
+
+css-what@^6.1.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4"
+ integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==
+
d@1, d@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a"
@@ -684,6 +734,36 @@ diff3@0.0.3:
resolved "https://registry.yarnpkg.com/diff3/-/diff3-0.0.3.tgz#d4e5c3a4cdf4e5fe1211ab42e693fcb4321580fc"
integrity sha1-1OXDpM305f4SEatC5pP8tDIVgPw=
+dom-serializer@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53"
+ integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==
+ dependencies:
+ domelementtype "^2.3.0"
+ domhandler "^5.0.2"
+ entities "^4.2.0"
+
+domelementtype@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d"
+ integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
+
+domhandler@^5.0.2, domhandler@^5.0.3:
+ version "5.0.3"
+ resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31"
+ integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==
+ dependencies:
+ domelementtype "^2.3.0"
+
+domutils@^3.0.1, domutils@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.1.0.tgz#c47f551278d3dc4b0b1ab8cbb42d751a6f0d824e"
+ integrity sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==
+ dependencies:
+ dom-serializer "^2.0.0"
+ domelementtype "^2.3.0"
+ domhandler "^5.0.3"
+
dot-prop@^5.2.0:
version "5.3.0"
resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz"
@@ -753,6 +833,14 @@ emoji-regex@^8.0.0:
resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz"
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
+encoding-sniffer@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz#799569d66d443babe82af18c9f403498365ef1d5"
+ integrity sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==
+ dependencies:
+ iconv-lite "^0.6.3"
+ whatwg-encoding "^3.1.1"
+
end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1:
version "1.4.4"
resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz"
@@ -760,6 +848,11 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1:
dependencies:
once "^1.4.0"
+entities@^4.2.0, entities@^4.5.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
+ integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
+
error-ex@^1.3.1:
version "1.3.2"
resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz"
@@ -1185,6 +1278,16 @@ hpagent@~0.1.0:
resolved "https://registry.yarnpkg.com/hpagent/-/hpagent-0.1.2.tgz#cab39c66d4df2d4377dbd212295d878deb9bdaa9"
integrity sha512-ePqFXHtSQWAFXYmj+JtOTHr84iNrII4/QRlAAPPE+zqnKy4xJo7Ie1Y4kC7AdB+LxLxSTTzBMASsEcy0q8YyvQ==
+htmlparser2@^9.1.0:
+ version "9.1.0"
+ resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-9.1.0.tgz#cdb498d8a75a51f739b61d3f718136c369bc8c23"
+ integrity sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==
+ dependencies:
+ domelementtype "^2.3.0"
+ domhandler "^5.0.3"
+ domutils "^3.1.0"
+ entities "^4.5.0"
+
http-cache-semantics@^4.0.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a"
@@ -1215,6 +1318,13 @@ http-server@^0.12.3:
secure-compare "3.0.1"
union "~0.5.0"
+iconv-lite@0.6.3, iconv-lite@^0.6.3:
+ version "0.6.3"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
+ integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
+ dependencies:
+ safer-buffer ">= 2.1.2 < 3.0.0"
+
ignore-by-default@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz"
@@ -1829,6 +1939,13 @@ npm-run-all@^4.1.5:
shell-quote "^1.6.1"
string.prototype.padend "^3.0.0"
+nth-check@^2.0.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d"
+ integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==
+ dependencies:
+ boolbase "^1.0.0"
+
object-inspect@^1.11.0:
version "1.12.0"
resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz"
@@ -1913,6 +2030,28 @@ parse-json@^4.0.0:
error-ex "^1.3.1"
json-parse-better-errors "^1.0.1"
+parse5-htmlparser2-tree-adapter@^7.0.0:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz#b5a806548ed893a43e24ccb42fbb78069311e81b"
+ integrity sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==
+ dependencies:
+ domhandler "^5.0.3"
+ parse5 "^7.0.0"
+
+parse5-parser-stream@^7.1.2:
+ version "7.1.2"
+ resolved "https://registry.yarnpkg.com/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz#d7c20eadc37968d272e2c02660fff92dd27e60e1"
+ integrity sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==
+ dependencies:
+ parse5 "^7.0.0"
+
+parse5@^7.0.0, parse5@^7.1.2:
+ version "7.2.1"
+ resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.2.1.tgz#8928f55915e6125f430cc44309765bf17556a33a"
+ integrity sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==
+ dependencies:
+ entities "^4.5.0"
+
path-dirname@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
@@ -2263,6 +2402,11 @@ safe-stable-stringify@^2.1.0:
resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.3.1.tgz#ab67cbe1fe7d40603ca641c5e765cb942d04fc73"
integrity sha512-kYBSfT+troD9cDA85VDnHZ1rpHC50O0g1e6WlGHVCz/g+JS+9WKLj+XwFYyR8UbrZN8ll9HUpDAAddY58MGisg==
+"safer-buffer@>= 2.1.2 < 3.0.0":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+ integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+
secure-compare@3.0.1:
version "3.0.1"
resolved "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz"
@@ -2635,6 +2779,11 @@ undefsafe@^2.0.5:
resolved "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz"
integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==
+undici@^6.19.5:
+ version "6.21.0"
+ resolved "https://registry.yarnpkg.com/undici/-/undici-6.21.0.tgz#4b3d3afaef984e07b48e7620c34ed8a285ed4cd4"
+ integrity sha512-BUgJXc752Kou3oOIuU1i+yZZypyZRqNPW0vqoMPl8VaoalSfeR0D8/t4iAS3yirs79SSMTxTag+ZC86uswv+Cw==
+
union@~0.5.0:
version "0.5.0"
resolved "https://registry.npmjs.org/union/-/union-0.5.0.tgz"
@@ -2765,6 +2914,18 @@ vinyl@^2.0.0, vinyl@^2.0.2, vinyl@~2.2:
remove-trailing-separator "^1.0.1"
replace-ext "^1.0.0"
+whatwg-encoding@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz#d0f4ef769905d426e1688f3e34381a99b60b76e5"
+ integrity sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==
+ dependencies:
+ iconv-lite "0.6.3"
+
+whatwg-mimetype@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz#bc1bf94a985dc50388d54a9258ac405c3ca2fc0a"
+ integrity sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==
+
which-boxed-primitive@^1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz"