This is an automated email from the ASF dual-hosted git repository.
fmariani pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-website.git
The following commit(s) were added to refs/heads/main by this push:
new e080a1a1 feat: Expose llms.txt and markdown content that is easily
accessible to LLMs
e080a1a1 is described below
commit e080a1a1733536d41a3d2f0a3c3a94674f8af0a2
Author: Croway <[email protected]>
AuthorDate: Mon Nov 10 09:53:29 2025 +0100
feat: Expose llms.txt and markdown content that is easily accessible to LLMs
---
gulp/helpers/html-index.js | 180 ++++++++++++++
gulp/helpers/llms-txt.js | 22 ++
gulp/helpers/rss-feed.js | 106 ++++++++
gulp/helpers/toon-format.js | 73 ++++++
gulp/helpers/turndown-config.js | 87 +++++++
gulp/tasks/generate-markdown.js | 124 ++++++++++
gulpfile.js | 6 +-
llms-txt-template.md | 62 +++++
package.json | 11 +-
yarn.lock | 534 ++++++++++++++++++++++++++++++++++++++--
10 files changed, 1175 insertions(+), 30 deletions(-)
diff --git a/gulp/helpers/html-index.js b/gulp/helpers/html-index.js
new file mode 100644
index 00000000..4409a8d5
--- /dev/null
+++ b/gulp/helpers/html-index.js
@@ -0,0 +1,180 @@
+const fs = require('fs');
+const { parse } = require('node-html-parser');
+const { createTurndownService } = require('./turndown-config');
+
+/**
+ * Generic function to generate markdown from HTML index pages.
+ *
+ * @param {Object} config - Configuration object
+ * @param {string} config.htmlPath - Path to the HTML file (e.g.,
'public/components/next/index.html')
+ * @param {string} config.title - Title for the markdown file (e.g.,
'Components Index')
+ * @param {string} config.description - Description text (e.g., 'List of all
Camel components')
+ */
+async function generateHtmlIndex(config) {
+ const { htmlPath, title, description } = config;
+ const mdPath = htmlPath.replace(/\.html$/, '.md');
+
+ try {
+ // Check if file exists
+ if (!fs.existsSync(htmlPath)) {
+ return;
+ }
+
+ const htmlContent = fs.readFileSync(htmlPath, 'utf8');
+ const root = parse(htmlContent);
+
+ // Create turndown service
+ const turndownService = createTurndownService();
+
+ // Extract only the main article content
+ let mainContent = root.querySelector('article.doc') ||
+ root.querySelector('main') ||
+ root.querySelector('.article') ||
+ root.querySelector('article');
+
+ if (!mainContent) {
+ return;
+ }
+
+ // Remove navigation elements
+ const elementsToRemove = mainContent.querySelectorAll('nav, header,
footer, .nav, .navbar, .toolbar');
+ elementsToRemove.forEach(el => el.remove());
+
+ // Remove anchor links
+ const anchors = mainContent.querySelectorAll('a.anchor');
+ anchors.forEach(el => el.remove());
+
+ // Clean up table cells by unwrapping div.content and div.paragraph
wrappers
+ const tableCells = mainContent.querySelectorAll('td.tableblock,
th.tableblock');
+ tableCells.forEach(cell => {
+ let html = cell.innerHTML;
+ // Unwrap <div class="content"><div
class="paragraph"><p>...</p></div></div>
+ html = html.replace(/<div class="content"><div
class="paragraph">\s*<p>(.*?)<\/p>\s*<\/div><\/div>/gs, '$1');
+ // Unwrap <div class="content"><div id="..."
class="paragraph"><p>...</p></div></div>
+ html = html.replace(/<div
class="content"><div[^>]*class="paragraph"[^>]*>\s*<p>(.*?)<\/p>\s*<\/div><\/div>/gs,
'$1');
+ // Also handle simple <p class="tableblock">...</p> wrappers
+ html = html.replace(/<p class="tableblock">(.*?)<\/p>/gs, '$1');
+ cell.set_content(html);
+ });
+
+ // Convert to Markdown
+ let markdown = turndownService.turndown(mainContent.innerHTML);
+
+ // Update links to point to .md files instead of .html
+ // Replace https://camel.apache.org/**/*.html with
https://camel.apache.org/**/*.md
+ markdown =
markdown.replace(/(https:\/\/camel\.apache\.org\/[^)\s]*?)\.html/g, '$1.md');
+ // Replace relative links *.html with *.md
+ markdown = markdown.replace(/\[([^\]]+)\]\(([^)]+?)\.html\)/g,
'[$1]($2.md)');
+
+ // Add header if title and description provided
+ if (title && description) {
+ markdown = `# ${title}\n\n${description}\n\n${markdown}`;
+ }
+
+ // Write markdown file
+ fs.writeFileSync(mdPath, markdown, 'utf8');
+ } catch (error) {
+ console.error(`Error generating markdown for ${htmlPath}:`, error.message);
+ }
+}
+
+/**
+ * Generates markdown for all index files (HTML index pages).
+ * This function processes all the index files specified in the configuration.
+ */
+async function generateAllIndexes() {
+ console.log('\nGenerating markdown for all index files...');
+
+ const glob = require('glob');
+
+ // Define all HTML index files to process
+ const htmlIndexes = [
+ {
+ htmlPath: 'public/camel-k/next/index.html',
+ title: 'Camel K Documentation Index',
+ description: 'Index of Camel K documentation pages.'
+ },
+ {
+ htmlPath: 'public/camel-kafka-connector/next/index.html',
+ title: 'Camel Kafka Connector Documentation Index',
+ description: 'Index of Camel Kafka Connector documentation pages.'
+ },
+ {
+ htmlPath: 'public/camel-kamelets/next/index.html',
+ title: 'Camel Kamelets Documentation Index',
+ description: 'Index of Camel Kamelets documentation pages.'
+ },
+ {
+ htmlPath: 'public/camel-quarkus/next/index.html',
+ title: 'Camel Quarkus Documentation Index',
+ description: 'Index of Camel Quarkus documentation pages.'
+ },
+ {
+ htmlPath: 'public/camel-spring-boot/next/index.html',
+ title: 'Camel Spring Boot Documentation Index',
+ description: 'Index of Camel Spring Boot documentation pages.'
+ },
+ {
+ htmlPath: 'public/components/next/index.html',
+ title: 'Components Index',
+ description: 'Index of all Camel components.'
+ },
+ {
+ htmlPath: 'public/components/next/others/index.html',
+ title: 'Other Components Index',
+ description: 'Index of other Camel components.'
+ },
+ {
+ htmlPath: 'public/components/next/languages/index.html',
+ title: 'Languages Index',
+ description: 'Index of Camel expression and predicate languages.'
+ },
+ {
+ htmlPath: 'public/components/next/eips/index.html',
+ title: 'Enterprise Integration Patterns Index',
+ description: 'Index of Enterprise Integration Patterns (EIPs).'
+ },
+ {
+ htmlPath: 'public/components/next/dataformats/index.html',
+ title: 'Data Formats Index',
+ description: 'Index of Camel data formats.'
+ },
+ {
+ htmlPath: 'public/manual/index.html',
+ title: 'User Manual Index',
+ description: 'Index of Apache Camel user manual pages.'
+ },
+ {
+ htmlPath: 'public/manual/faq/index.html',
+ title: 'FAQ Index',
+ description: 'Frequently Asked Questions about Apache Camel.'
+ },
+ {
+ htmlPath: 'public/releases/index.html',
+ title: 'Releases Index',
+ description: 'Apache Camel version releases Index.'
+ }
+ ];
+
+ // Process all HTML indexes
+ for (const config of htmlIndexes) {
+ await generateHtmlIndex(config);
+ }
+
+ // Find all index.html files under public/releases/**/
+ console.log('\nGenerating markdown for all release index files...');
+ const releaseIndexFiles = glob.sync('public/releases/**/index.html');
+ console.log(`Found ${releaseIndexFiles.length} release index files to
process`);
+
+ // Process each release index file without custom title/description
+ for (const htmlPath of releaseIndexFiles) {
+ await generateHtmlIndex({ htmlPath });
+ }
+
+ console.log('All index files generation complete');
+}
+
+module.exports = {
+ generateHtmlIndex,
+ generateAllIndexes
+};
diff --git a/gulp/helpers/llms-txt.js b/gulp/helpers/llms-txt.js
new file mode 100644
index 00000000..8f23afdc
--- /dev/null
+++ b/gulp/helpers/llms-txt.js
@@ -0,0 +1,22 @@
+const fs = require('fs');
+const path = require('path');
+
+/**
+ * Generates the /llms.txt file as per https://llmstxt.org/ specification.
+ * This file helps LLMs discover and understand the structure of the
documentation.
+ * Reads from llms-txt-template.md and uses it as content.
+ *
+ * @param {Array<string>} pages - Array of page URLs that were converted to
markdown
+ */
+function generateLlmsTxt(pages) {
+ // Read the template file
+ const templatePath = path.join(__dirname, '../../llms-txt-template.md');
+ let llmsTxtContent = fs.readFileSync(templatePath, 'utf8');
+
+ fs.writeFileSync('public/llms.txt', llmsTxtContent, 'utf8');
+ console.log('Generated /llms.txt');
+}
+
+module.exports = {
+ generateLlmsTxt
+};
diff --git a/gulp/helpers/rss-feed.js b/gulp/helpers/rss-feed.js
new file mode 100644
index 00000000..a8578909
--- /dev/null
+++ b/gulp/helpers/rss-feed.js
@@ -0,0 +1,106 @@
+const fs = require('fs');
+const xml2js = require('xml2js');
+
+/**
+ * Generic function to generate toon format markdown from RSS XML feeds.
+ * Converts RSS feeds to plain text files (.md) as per
https://github.com/toon-format/toon specification.
+ *
+ * @param {Object} config - Configuration object
+ * @param {string} config.xmlPath - Path to the XML file (e.g.,
'public/blog/index.xml')
+ * @param {string} config.title - Title for the markdown file (e.g., 'Apache
Camel Blog')
+ * @param {string} config.description - Description text (e.g., 'Blog posts
about Apache Camel')
+ * @param {string} config.itemsName - Name for the items collection (e.g.,
'posts', 'releases')
+ */
+async function generateRssFeedIndex(config) {
+ const parser = new xml2js.Parser();
+
+ const { xmlPath, title, description, itemsName } = config;
+ const mdPath = xmlPath.replace(/\.xml$/, '.md');
+
+ try {
+ // Check if file exists
+ if (!fs.existsSync(xmlPath)) {
+ return;
+ }
+
+ // Read XML file
+ const xmlContent = fs.readFileSync(xmlPath, 'utf8');
+
+ // Parse XML to JavaScript object
+ const result = await parser.parseStringPromise(xmlContent);
+
+ let toonContent = '';
+
+ // Check if it's an RSS feed
+ if (result.rss && result.rss.channel && result.rss.channel[0]) {
+ const channel = result.rss.channel[0];
+ const items = channel.item || [];
+
+ // Create toon format header
+ toonContent = `# ${title}\n\n`;
+ toonContent += `${description}\n\n`;
+ toonContent +=
`${itemsName}[${items.length}]{title,link,pubDate,description}:\n`;
+
+ // Add each item
+ for (const item of items) {
+ const itemTitle = item.title ? item.title[0] : '';
+ const link = item.link ? item.link[0] : '';
+ const pubDate = item.pubDate ? item.pubDate[0] : '';
+ const itemDesc = item.description ? item.description[0].replace(/\n/g,
' ').substring(0, 200) : '';
+
+ // Convert links to markdown format
+ let mdLink = link;
+ if (mdLink.endsWith('/')) {
+ mdLink = mdLink + 'index.md';
+ } else {
+ mdLink = mdLink.replace(/\.html$/, '.md');
+ }
+
+ toonContent += ` ${itemTitle}|${mdLink}|${pubDate}|${itemDesc}\n`;
+ }
+ }
+
+ // Write toon format file
+ fs.writeFileSync(mdPath, toonContent, 'utf8');
+ } catch (error) {
+ console.error(`Error generating toon format for ${xmlPath}:`,
error.message);
+ }
+}
+
+/**
+ * Generates toon format markdown for the Releases category RSS feed.
+ * Converts public/categories/Releases/index.xml to index.md
+ * as per https://github.com/toon-format/toon specification.
+ */
+async function generateReleasesIndex() {
+ console.log('\nGenerating toon format for Releases index...');
+ await generateRssFeedIndex({
+ xmlPath: 'public/categories/Releases/index.xml',
+ title: 'Apache Camel Releases',
+ description: 'Release feed for Apache Camel and related projects.',
+ itemsName: 'releases'
+ });
+ console.log('Releases index toon format generation complete');
+}
+
+/**
+ * Generates toon format markdown for the Blog RSS feed.
+ * Converts public/blog/index.xml to index.md
+ * as per https://github.com/toon-format/toon specification.
+ */
+async function generateBlogIndex() {
+ console.log('\nGenerating toon format for Blog index...');
+ await generateRssFeedIndex({
+ xmlPath: 'public/blog/index.xml',
+ title: 'Apache Camel Blog',
+ description: 'Blog posts about Apache Camel and related topics.',
+ itemsName: 'posts'
+ });
+ console.log('Blog index toon format generation complete');
+}
+
+module.exports = {
+ generateRssFeedIndex,
+ generateReleasesIndex,
+ generateBlogIndex
+};
diff --git a/gulp/helpers/toon-format.js b/gulp/helpers/toon-format.js
new file mode 100644
index 00000000..ccde19a0
--- /dev/null
+++ b/gulp/helpers/toon-format.js
@@ -0,0 +1,73 @@
+const fs = require('fs');
+const path = require('path');
+const xml2js = require('xml2js');
+
+/**
+ * Generates toon format sitemaps from XML sitemaps.
+ * Converts all sitemap*.xml files to toon format (.md files)
+ * as per https://github.com/toon-format/toon specification.
+ */
+async function generateToonSitemaps() {
+ const parser = new xml2js.Parser();
+ const glob = require('glob');
+
+ console.log('\nGenerating toon format sitemaps...');
+
+ // Find all sitemap*.xml files in the public directory
+ const sitemapFiles = glob.sync('public/sitemap*.xml');
+
+ if (sitemapFiles.length === 0) {
+ return;
+ }
+
+ for (const xmlPath of sitemapFiles) {
+ const sitemapFile = path.basename(xmlPath);
+ const toonPath = xmlPath.replace(/\.xml$/, '.md');
+
+ try {
+ // Read XML file
+ const xmlContent = fs.readFileSync(xmlPath, 'utf8');
+
+ // Parse XML to JavaScript object
+ const result = await parser.parseStringPromise(xmlContent);
+
+ let toonContent = '';
+
+ // Check if it's a sitemap index or a urlset
+ if (result.sitemapindex) {
+ // This is a sitemap index (sitemap.xml)
+ const sitemaps = result.sitemapindex.sitemap || [];
+ toonContent = `sitemaps[${sitemaps.length}]{loc}:\n`;
+ for (const sitemap of sitemaps) {
+ let loc = sitemap.loc ? sitemap.loc[0] : '';
+ // Convert .xml URLs to .md
+ loc = loc.replace(/\.xml$/, '.md');
+ toonContent += ` ${loc}\n`;
+ }
+ } else if (result.urlset) {
+ // This is a regular sitemap with URLs
+ const urls = result.urlset.url || [];
+ toonContent = `urls[${urls.length}]{loc,lastmod}:\n`;
+ for (const url of urls) {
+ let loc = url.loc ? url.loc[0] : '';
+ const lastmod = url.lastmod ? url.lastmod[0] : '';
+ // Convert .html URLs to .md
+ loc = loc.replace(/\.html$/, '.md');
+ toonContent += ` ${loc},${lastmod}\n`;
+ }
+ }
+
+ // Write toon format file
+ fs.writeFileSync(toonPath, toonContent, 'utf8');
+ console.log(`Generated ${sitemapFile.replace('.xml', '.md')}`);
+ } catch (error) {
+ console.error(`Error generating toon sitemap for ${sitemapFile}:`,
error.message);
+ }
+ }
+
+ console.log(`Toon format sitemaps generation complete -
${sitemapFiles.length} files converted`);
+}
+
+module.exports = {
+ generateToonSitemaps
+};
diff --git a/gulp/helpers/turndown-config.js b/gulp/helpers/turndown-config.js
new file mode 100644
index 00000000..7b503ab8
--- /dev/null
+++ b/gulp/helpers/turndown-config.js
@@ -0,0 +1,87 @@
+const TurndownService = require('turndown');
+const turndownPluginGfm = require('turndown-plugin-gfm');
+
+/**
+ * Creates and configures a TurndownService instance for converting HTML to
Markdown.
+ * Includes custom rules for Asciidoctor admonition blocks, table wrappers,
and icons.
+ *
+ * @returns {TurndownService} Configured Turndown service instance
+ */
+function createTurndownService() {
+ const turndownService = new TurndownService({
+ headingStyle: 'atx',
+ codeBlockStyle: 'fenced',
+ bulletListMarker: '-',
+ emDelimiter: '_',
+ });
+
+ // Use GitHub-flavored Markdown for tables, strikethrough, etc.
+ const gfm = turndownPluginGfm.gfm;
+ turndownService.use(gfm);
+
+ // Custom rule to convert Asciidoctor admonition blocks to readable Markdown
+ turndownService.addRule('admonitionBlocks', {
+ filter: function (node) {
+ return node.classList && node.classList.contains('admonitionblock');
+ },
+ replacement: function (content, node) {
+ // Extract the icon type (tip, note, important, warning, caution)
+ const iconElement = node.querySelector('.icon i');
+ let admonitionType = 'Note';
+
+ if (iconElement) {
+ const title = iconElement.getAttribute('title') || '';
+ admonitionType = title || 'Note';
+ }
+
+ // Extract the content text
+ const contentDiv = node.querySelector('.content');
+ if (!contentDiv) return '';
+
+ // Convert the content div to markdown
+ const contentHtml = contentDiv.innerHTML;
+ const contentMarkdown = turndownService.turndown(contentHtml);
+
+ // Format as a blockquote with the admonition type
+ const lines = contentMarkdown.split('\n');
+ const quotedLines = lines.map(line => line ? `> ${line}` : '>');
+
+ return `\n> **${admonitionType}**\n${quotedLines.join('\n')}\n\n`;
+ }
+ });
+
+ // Custom rule to handle table-wrapper divs
+ turndownService.addRule('tableWrapper', {
+ filter: function (node) {
+ return node.classList && node.classList.contains('table-wrapper');
+ },
+ replacement: function (content, node) {
+ // Just extract the table inside
+ const table = node.querySelector('table');
+ if (table) {
+ return turndownService.turndown(table.outerHTML);
+ }
+ return content;
+ }
+ });
+
+ // Custom rule to clean up icon elements and other UI-only content
+ turndownService.addRule('removeIcons', {
+ filter: function (node) {
+ // Remove icon elements, anchors without text, etc.
+ if (node.classList) {
+ return node.classList.contains('icon') ||
+ node.classList.contains('anchor') ||
+ (node.tagName === 'I' && node.classList.contains('fa'));
+ }
+ return false;
+ },
+ replacement: function () {
+ return '';
+ }
+ });
+
+ return turndownService;
+}
+
+module.exports = { createTurndownService };
diff --git a/gulp/tasks/generate-markdown.js b/gulp/tasks/generate-markdown.js
new file mode 100644
index 00000000..cc5964e8
--- /dev/null
+++ b/gulp/tasks/generate-markdown.js
@@ -0,0 +1,124 @@
+const fs = require('fs');
+const { parse } = require('node-html-parser');
+const { createTurndownService } = require('../helpers/turndown-config');
+const { generateToonSitemaps } = require('../helpers/toon-format');
+const { generateLlmsTxt } = require('../helpers/llms-txt');
+const { generateReleasesIndex, generateBlogIndex } =
require('../helpers/rss-feed');
+const { generateAllIndexes } = require('../helpers/html-index');
+
+/**
+ * Generates Markdown (.md) files from HTML files for LLM consumption.
+ * This task converts HTML documentation pages to Markdown format, making them
+ * accessible to LLMs as per https://llmstxt.org/ specification.
+ *
+ * For each .html file, it creates a corresponding .md file with:
+ * - Only the main article content (excluding nav, header, footer)
+ * - Clean Markdown formatting using Turndown
+ * - GitHub-flavored Markdown for tables and code blocks
+ */
+async function generateMarkdown(done) {
+ const turndownService = createTurndownService();
+
+ // Keep track of processed files for llms.txt
+ const processedPages = [];
+
+ const glob = require('glob');
+
+ // Get all HTML files
+ const htmlFiles = glob.sync('public/**/*.html', {
+ ignore: ['public/404.html', 'public/**/index.html'] // Skip error pages
and index pages
+ });
+
+ let processedCount = 0;
+ const totalFiles = htmlFiles.length;
+ const BATCH_SIZE = 500; // Process in batches to avoid memory issues
+
+ console.log(`Found ${totalFiles} HTML files to convert`);
+
+ // Process files in batches
+ for (let i = 0; i < htmlFiles.length; i += BATCH_SIZE) {
+ const batch = htmlFiles.slice(i, i + BATCH_SIZE);
+
+ for (const htmlFile of batch) {
+ try {
+ const htmlContent = fs.readFileSync(htmlFile, 'utf8');
+ const root = parse(htmlContent);
+
+ // Extract only the main article content
+ // Try different selectors based on Antora and Hugo structure
+ let mainContent = root.querySelector('article.doc') ||
+ root.querySelector('main') ||
+ root.querySelector('.article') ||
+ root.querySelector('article');
+
+ if (!mainContent) {
+ // Silently skip files without main content
+ continue;
+ }
+
+ // Remove navigation elements, headers, and footers from the content
+ const elementsToRemove = mainContent.querySelectorAll('nav, header,
footer, .nav, .navbar, .toolbar');
+ elementsToRemove.forEach(el => el.remove());
+
+ // Remove anchor links (they are just UI navigation aids)
+ const anchors = mainContent.querySelectorAll('a.anchor');
+ anchors.forEach(el => el.remove());
+
+ // Clean up table cells by unwrapping div.content and div.paragraph
wrappers
+ const tableCells = mainContent.querySelectorAll('td.tableblock,
th.tableblock');
+ tableCells.forEach(cell => {
+ let html = cell.innerHTML;
+ // Unwrap <div class="content"><div
class="paragraph"><p>...</p></div></div>
+ html = html.replace(/<div class="content"><div
class="paragraph">\s*<p>(.*?)<\/p>\s*<\/div><\/div>/gs, '$1');
+ // Unwrap <div class="content"><div id="..."
class="paragraph"><p>...</p></div></div>
+ html = html.replace(/<div
class="content"><div[^>]*class="paragraph"[^>]*>\s*<p>(.*?)<\/p>\s*<\/div><\/div>/gs,
'$1');
+ // Also handle simple <p class="tableblock">...</p> wrappers
+ html = html.replace(/<p class="tableblock">(.*?)<\/p>/gs, '$1');
+ cell.set_content(html);
+ });
+
+ // Convert to Markdown
+ let markdown = turndownService.turndown(mainContent.innerHTML);
+
+ // Update links to point to .md files instead of .html
+ // Replace https://camel.apache.org/**/*.html with
https://camel.apache.org/**/*.md
+ markdown =
markdown.replace(/(https:\/\/camel\.apache\.org\/[^)\s]*?)\.html/g, '$1.md');
+ // Replace relative links *.html with *.md
+ markdown = markdown.replace(/\[([^\]]+)\]\(([^)]+?)\.html\)/g,
'[$1]($2.md)');
+
+ // Write .md file (replace .html extension with .md)
+ const mdFile = htmlFile.replace(/\.html$/, '.md');
+ fs.writeFileSync(mdFile, markdown, 'utf8');
+
+ // Track for llms.txt (convert to URL path)
+ const urlPath = htmlFile.replace('public/', '/').replace('.html',
'.md');
+ processedPages.push(urlPath);
+
+ processedCount++;
+ } catch (error) {
+ console.error(`Error processing ${htmlFile}:`, error.message);
+ }
+ }
+ }
+
+ console.log(`\nSuccessfully generated ${processedCount} Markdown files`);
+
+ // Generate llms.txt file
+ generateLlmsTxt(processedPages);
+
+ // Generate toon format sitemaps
+ await generateToonSitemaps();
+
+ // Generate toon format for releases RSS feed
+ await generateReleasesIndex();
+
+ // Generate toon format for blog RSS feed
+ await generateBlogIndex();
+
+ // Generate all other index files
+ await generateAllIndexes();
+
+ done();
+}
+
+module.exports = generateMarkdown;
diff --git a/gulpfile.js b/gulpfile.js
index 853e669f..5e704165 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -2,7 +2,8 @@ const cheerio = require('gulp-cheerio');
const env = process.env.CAMEL_ENV || 'development';
const gulp = require('gulp');
const htmlmin = require('gulp-htmlmin');
-const inject = require('gulp-inject')
+const inject = require('gulp-inject');
+const generateMarkdown = require('./gulp/tasks/generate-markdown');
/**
* We minify all HTML files using htmlmin, this is to make them smaller in size
@@ -113,6 +114,9 @@ function versionlessRedirects (text) {
return processed.join('\n')
}
+// Register the generate-markdown task
+gulp.task('generate-markdown', generateMarkdown);
+
/*
* Removes the content from the `public` directory.
*/
diff --git a/llms-txt-template.md b/llms-txt-template.md
new file mode 100644
index 00000000..5216e3f2
--- /dev/null
+++ b/llms-txt-template.md
@@ -0,0 +1,62 @@
+# Apache Camel
+
+> Apache Camel is an open source integration framework that empowers you to
quickly and easily integrate various systems consuming or producing data. It
provides 300+ components, Enterprise Integration Patterns (EIPs), multiple
DSLs, and runs on various runtimes including Spring Boot, Quarkus, and
Kubernetes.
+
+All Apache Camel documentation pages are available in LLM-friendly Markdown
format by replacing `.html` with `.md` in any URL.
+For example:
+- HTML:
`https://camel.apache.org/components/next/languages/simple-language.html`
+- Markdown:
`https://camel.apache.org/components/next/languages/simple-language.md`
+
+## Overview
+
+- [Getting Started](https://camel.apache.org/manual/getting-started.md): Quick
start guide for Apache Camel.
+- [User Manual](https://camel.apache.org/manual/index.md): Complete user guide
and reference documentation.
+- [FAQ](https://camel.apache.org/manual/faq/index.md): Frequently Asked
Questions about Apache Camel.
+- [Releases](https://camel.apache.org/releases/index.md): Apache Camel
Releases and version history.
+- [Blog](https://camel.apache.org/blog/index.md): Latest blog posts about
Apache Camel.
+
+## Components
+
+- [Components Index](https://camel.apache.org/components/next/index.md):
Complete list of all Camel components (300+).
+- [Languages](https://camel.apache.org/components/next/languages/index.md):
Expression and predicate languages (Simple, XPath, JSONPath, etc.).
+- [Enterprise Integration Patterns
(EIPs)](https://camel.apache.org/components/next/eips/index.md): Message
routing and transformation patterns.
+- [Data
Formats](https://camel.apache.org/components/next/dataformats/index.md): Data
marshalling and unmarshalling formats.
+- [Other
Components](https://camel.apache.org/components/next/others/index.md):
Additional Camel components and utilities.
+
+## Runtimes & Frameworks
+
+- [Camel Quarkus](https://camel.apache.org/camel-quarkus/next/index.md): Camel
extensions for Quarkus runtime.
+- [Camel Spring
Boot](https://camel.apache.org/camel-spring-boot/next/index.md): Camel
integration with Spring Boot.
+- [Camel K](https://camel.apache.org/camel-k/next/index.md): Lightweight
integration framework for Kubernetes.
+- [Camel Kafka
Connector](https://camel.apache.org/camel-kafka-connector/next/index.md): Kafka
Connect connectors based on Camel.
+- [Camel Kamelets](https://camel.apache.org/camel-kamelets/next/index.md):
Route snippets for common integration scenarios.
+
+## Examples
+
+- [Camel
Examples](https://github.com/apache/camel-examples/blob/main/README.adoc): Core
Camel examples repository.
+- [Camel JBang Examples](https://github.com/apache/camel-jbang-examples):
Examples using Camel JBang.
+- [Camel Quarkus
Examples](https://camel.apache.org/camel-quarkus/next/user-guide/examples.md):
Quarkus integration examples.
+- [Camel Spring Boot
Examples](https://github.com/apache/camel-spring-boot-examples/blob/main/README.adoc):
Spring Boot integration examples.
+- [Camel K
Examples](https://github.com/apache/camel-k-examples/blob/main/generic-examples/README.md):
Kubernetes integration examples.
+- [Camel Kamelets
Examples](https://github.com/apache/camel-kamelets-examples): Kamelets usage
examples.
+- [Camel Kafka Connector
Examples](https://github.com/apache/camel-kafka-connector-examples/blob/main/README.adoc):
Kafka Connect examples.
+
+## Sitemaps
+
+- [Main Sitemap](https://camel.apache.org/sitemap.md): Complete sitemap index.
+- [Camel Core](https://camel.apache.org/sitemap-camel-core.md): Core Camel
documentation sitemap.
+- [Camel K](https://camel.apache.org/sitemap-camel-k.md): Camel K
documentation sitemap.
+- [Camel Kafka
Connector](https://camel.apache.org/sitemap-camel-kafka-connector.md): Camel
Kafka Connector sitemap.
+- [Camel Kamelets](https://camel.apache.org/sitemap-camel-kamelets.md): Camel
Kamelets sitemap.
+- [Camel Quarkus](https://camel.apache.org/sitemap-camel-quarkus.md): Camel
Quarkus sitemap.
+- [Camel Spring Boot](https://camel.apache.org/sitemap-camel-spring-boot.md):
Camel Spring Boot sitemap.
+- [Components](https://camel.apache.org/sitemap-components.md): Components
documentation sitemap.
+- [Manual](https://camel.apache.org/sitemap-manual.md): User manual sitemap.
+
+## Additional Resources
+
+- [Migration and Upgrade
Guides](https://camel.apache.org/manual/migration-and-upgrade.md): Apache Camel
Migration and Upgrade Guides
+- [Camel Update Recipes](https://github.com/apache/camel-upgrade-recipes):
Open rewrite recipes that can be used to automatically update Camel applications
+- [GitHub](https://github.com/apache/camel): Source code repository.
+- [Community](https://camel.apache.org/community/): Community resources and
how to contribute.
+- [Camel JBang](https://camel.apache.org/manual/camel-jbang.md): Run Camel
routes from the command line.
diff --git a/package.json b/package.json
index fcbedee2..d4a5b24b 100644
--- a/package.json
+++ b/package.json
@@ -3,12 +3,13 @@
"version": "1.0.0-SNAPSHOT",
"license": "Apache-2.0",
"scripts": {
- "build": "run-s -l build:antora build:hugo build:sitemap build:htaccess
build:minify",
+ "build": "run-s -l build:antora build:hugo build:sitemap build:htaccess
build:markdown build:minify",
"build-all": "yarn workspaces foreach --all --topological-dev run build",
"build:antora": "run-s -l build:antora-prep build:antora-perf",
"build:antora-prep": "yarn exec
antora-playbook-snippets/assemble-playbook.sh antora-playbook-production.yml
playbook-export-site-manifest.yml",
"build:antora-perf": "antora --clean --fetch
antora-playbook-production.yml --stacktrace",
"build:hugo": "hugo --cacheDir ${HUGO_CACHE_DIR:-$(pwd)/.hugo_data}
${HUGO_OPTIONS:-}",
+ "build:markdown": "gulp generate-markdown",
"build:minify": "gulp minify",
"build:sitemap": "gulp sitemap",
"build:htaccess": "gulp htaccess",
@@ -49,6 +50,7 @@
"chalk": "5.3.0",
"del": "^6.0.0",
"escape-string-regexp": "~2.0",
+ "glob": "^11.0.3",
"gulp": "~4.0",
"gulp-cheerio": "~1.0",
"gulp-htmlmin": "~5.0",
@@ -56,11 +58,16 @@
"html-validate": "^8.9.1",
"hugo-extended": "^0.121.2",
"js-yaml": "~4.1.0",
+ "jsdom": "^27.1.0",
"netlify-cli": "17.26.3",
+ "node-html-parser": "^7.0.1",
"npm-run-all": "~4",
"opal-runtime": "1.0.11",
"pino-pretty": "^5.0.0",
- "toml": "~3.0"
+ "toml": "~3.0",
+ "turndown": "^7.2.2",
+ "turndown-plugin-gfm": "^1.0.2",
+ "xml2js": "^0.6.2"
},
"workspaces": [
"antora-ui-camel",
diff --git a/yarn.lock b/yarn.lock
index b97f8cab..a406ea53 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5,6 +5,13 @@ __metadata:
version: 8
cacheKey: 10
+"@acemir/cssom@npm:^0.9.19":
+ version: 0.9.23
+ resolution: "@acemir/cssom@npm:0.9.23"
+ checksum:
10/752294359ddf691f402bf871f347c1d5ea8532ead5e197cf60eeb7ab25bdd6f6e98fc7fad74042f2e423bb45fe7e4a049db645e01fa0781a0ed4ea2cec911047
+ languageName: node
+ linkType: hard
+
"@algolia/cache-browser-local-storage@npm:4.5.1":
version: 4.5.1
resolution: "@algolia/cache-browser-local-storage@npm:4.5.1"
@@ -348,6 +355,39 @@ __metadata:
languageName: node
linkType: hard
+"@asamuzakjp/css-color@npm:^4.0.3":
+ version: 4.0.5
+ resolution: "@asamuzakjp/css-color@npm:4.0.5"
+ dependencies:
+ "@csstools/css-calc": "npm:^2.1.4"
+ "@csstools/css-color-parser": "npm:^3.1.0"
+ "@csstools/css-parser-algorithms": "npm:^3.0.5"
+ "@csstools/css-tokenizer": "npm:^3.0.4"
+ lru-cache: "npm:^11.2.1"
+ checksum:
10/7021b5f200793a652fa64e181c6233b5910002575be2bff9d1bc63fcc8198837bab2bee36bf309a26f433ac006fb1b2869217d8198c901c89d79e47e8dd9d805
+ languageName: node
+ linkType: hard
+
+"@asamuzakjp/dom-selector@npm:^6.7.3":
+ version: 6.7.4
+ resolution: "@asamuzakjp/dom-selector@npm:6.7.4"
+ dependencies:
+ "@asamuzakjp/nwsapi": "npm:^2.3.9"
+ bidi-js: "npm:^1.0.3"
+ css-tree: "npm:^3.1.0"
+ is-potential-custom-element-name: "npm:^1.0.1"
+ lru-cache: "npm:^11.2.2"
+ checksum:
10/dc550a4e32b956bfc820795e73bb3cae963496101a6dc1ebbd0cad409e734dadbcfbac22a44034c28ec401ee1454a379c64cc02d11eb2186e74c638482d8b2e1
+ languageName: node
+ linkType: hard
+
+"@asamuzakjp/nwsapi@npm:^2.3.9":
+ version: 2.3.9
+ resolution: "@asamuzakjp/nwsapi@npm:2.3.9"
+ checksum:
10/95a6d1c102e1117fe818da087fcc5b914d23e0699855991bae50b891435dd1945ad7d384198f8bcf616207fd85b7ec32e3db6b96e9309d84c6903b8dc4151e34
+ languageName: node
+ linkType: hard
+
"@asciidoctor/core@npm:^3.0.2":
version: 3.0.2
resolution: "@asciidoctor/core@npm:3.0.2"
@@ -517,6 +557,36 @@ __metadata:
languageName: node
linkType: hard
+"@csstools/color-helpers@npm:^5.1.0":
+ version: 5.1.0
+ resolution: "@csstools/color-helpers@npm:5.1.0"
+ checksum:
10/0138b3d5ccbe77aeccf6721fd008a53523c70e932f0c82dca24a1277ca780447e1d8357da47512ebf96358476f8764de57002f3e491920d67e69202f5a74c383
+ languageName: node
+ linkType: hard
+
+"@csstools/css-calc@npm:^2.1.4":
+ version: 2.1.4
+ resolution: "@csstools/css-calc@npm:2.1.4"
+ peerDependencies:
+ "@csstools/css-parser-algorithms": ^3.0.5
+ "@csstools/css-tokenizer": ^3.0.4
+ checksum:
10/06975b650c0f44c60eeb7afdb3fd236f2dd607b2c622e0bc908d3f54de39eb84e0692833320d03dac04bd6c1ab0154aa3fa0dd442bd9e5f917cf14d8e2ba8d74
+ languageName: node
+ linkType: hard
+
+"@csstools/css-color-parser@npm:^3.1.0":
+ version: 3.1.0
+ resolution: "@csstools/css-color-parser@npm:3.1.0"
+ dependencies:
+ "@csstools/color-helpers": "npm:^5.1.0"
+ "@csstools/css-calc": "npm:^2.1.4"
+ peerDependencies:
+ "@csstools/css-parser-algorithms": ^3.0.5
+ "@csstools/css-tokenizer": ^3.0.4
+ checksum:
10/4741095fdc4501e8e7ada4ed14fbf9dbbe6fea9b989818790ebca15657c29c62defbebacf18592cde2aa638a1d098bbe86d742d2c84ba932fbc00fac51cb8805
+ languageName: node
+ linkType: hard
+
"@csstools/css-parser-algorithms@npm:^2.3.1":
version: 2.5.0
resolution: "@csstools/css-parser-algorithms@npm:2.5.0"
@@ -526,6 +596,22 @@ __metadata:
languageName: node
linkType: hard
+"@csstools/css-parser-algorithms@npm:^3.0.5":
+ version: 3.0.5
+ resolution: "@csstools/css-parser-algorithms@npm:3.0.5"
+ peerDependencies:
+ "@csstools/css-tokenizer": ^3.0.4
+ checksum:
10/e93083b5cb36a3c1e7a47ce10cf62961d05bd1e4c608bb3ee50186ff740157ab0ec16a3956f7b86251efd10703034d849693201eea858ae904848c68d2d46ada
+ languageName: node
+ linkType: hard
+
+"@csstools/css-syntax-patches-for-csstree@npm:^1.0.14":
+ version: 1.0.15
+ resolution: "@csstools/css-syntax-patches-for-csstree@npm:1.0.15"
+ checksum:
10/73526cc73df98a2bf1dc0ec63e489d775131e92397e994d04843b7cd5da0ed2c9a849f5262005630f10cb41a5d1f28d0a22a496654c8941fd7bf41f3e83b734c
+ languageName: node
+ linkType: hard
+
"@csstools/css-tokenizer@npm:^2.2.0":
version: 2.2.3
resolution: "@csstools/css-tokenizer@npm:2.2.3"
@@ -533,6 +619,13 @@ __metadata:
languageName: node
linkType: hard
+"@csstools/css-tokenizer@npm:^3.0.4":
+ version: 3.0.4
+ resolution: "@csstools/css-tokenizer@npm:3.0.4"
+ checksum:
10/eb6c84c086312f6bb8758dfe2c85addd7475b0927333c5e39a4d59fb210b9810f8c346972046f95e60a721329cffe98895abe451e51de753ad1ca7a8c24ec65f
+ languageName: node
+ linkType: hard
+
"@csstools/media-query-list-parser@npm:^2.1.4":
version: 2.1.7
resolution: "@csstools/media-query-list-parser@npm:2.1.7"
@@ -1129,6 +1222,22 @@ __metadata:
languageName: node
linkType: hard
+"@isaacs/balanced-match@npm:^4.0.1":
+ version: 4.0.1
+ resolution: "@isaacs/balanced-match@npm:4.0.1"
+ checksum:
10/102fbc6d2c0d5edf8f6dbf2b3feb21695a21bc850f11bc47c4f06aa83bd8884fde3fe9d6d797d619901d96865fdcb4569ac2a54c937992c48885c5e3d9967fe8
+ languageName: node
+ linkType: hard
+
+"@isaacs/brace-expansion@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "@isaacs/brace-expansion@npm:5.0.0"
+ dependencies:
+ "@isaacs/balanced-match": "npm:^4.0.1"
+ checksum:
10/cf3b7f206aff12128214a1df764ac8cdbc517c110db85249b945282407e3dfc5c6e66286383a7c9391a059fc8e6e6a8ca82262fc9d2590bd615376141fbebd2d
+ languageName: node
+ linkType: hard
+
"@isaacs/cliui@npm:^8.0.2":
version: 8.0.2
resolution: "@isaacs/cliui@npm:8.0.2"
@@ -1251,6 +1360,13 @@ __metadata:
languageName: node
linkType: hard
+"@mixmark-io/domino@npm:^2.2.0":
+ version: 2.2.0
+ resolution: "@mixmark-io/domino@npm:2.2.0"
+ checksum:
10/839624ba6baab655c4f7393e8b8561516849926651e02f40484729b9869436b1e077906810bcac0bba4762448512d3ebd2f6d9b463d8ab0d5f54d75ca5306519
+ languageName: node
+ linkType: hard
+
"@netlify/binary-info@npm:^1.0.0":
version: 1.0.0
resolution: "@netlify/binary-info@npm:1.0.0"
@@ -3153,12 +3269,10 @@ __metadata:
languageName: node
linkType: hard
-"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0":
- version: 7.1.0
- resolution: "agent-base@npm:7.1.0"
- dependencies:
- debug: "npm:^4.3.4"
- checksum:
10/f7828f991470a0cc22cb579c86a18cbae83d8a3cbed39992ab34fc7217c4d126017f1c74d0ab66be87f71455318a8ea3e757d6a37881b8d0f2a2c6aa55e5418f
+"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.2":
+ version: 7.1.4
+ resolution: "agent-base@npm:7.1.4"
+ checksum:
10/79bef167247789f955aaba113bae74bf64aa1e1acca4b1d6bb444bdf91d82c3e07e9451ef6a6e2e35e8f71a6f97ce33e3d855a5328eb9fad1bc3cc4cfd031ed8
languageName: node
linkType: hard
@@ -3588,6 +3702,7 @@ __metadata:
chalk: "npm:5.3.0"
del: "npm:^6.0.0"
escape-string-regexp: "npm:~2.0"
+ glob: "npm:^11.0.3"
gulp: "npm:~4.0"
gulp-cheerio: "npm:~1.0"
gulp-htmlmin: "npm:~5.0"
@@ -3595,11 +3710,16 @@ __metadata:
html-validate: "npm:^8.9.1"
hugo-extended: "npm:^0.121.2"
js-yaml: "npm:~4.1.0"
+ jsdom: "npm:^27.1.0"
netlify-cli: "npm:17.26.3"
+ node-html-parser: "npm:^7.0.1"
npm-run-all: "npm:~4"
opal-runtime: "npm:1.0.11"
pino-pretty: "npm:^5.0.0"
toml: "npm:~3.0"
+ turndown: "npm:^7.2.2"
+ turndown-plugin-gfm: "npm:^1.0.2"
+ xml2js: "npm:^0.6.2"
languageName: unknown
linkType: soft
@@ -4253,6 +4373,15 @@ __metadata:
languageName: node
linkType: hard
+"bidi-js@npm:^1.0.3":
+ version: 1.0.3
+ resolution: "bidi-js@npm:1.0.3"
+ dependencies:
+ require-from-string: "npm:^2.0.2"
+ checksum:
10/c4341c7a98797efe3d186cd99d6f97e9030a4f959794ca200ef2ec0a678483a916335bba6c2c0608a21d04a221288a31c9fd0faa0cd9b3903b93594b42466a6a
+ languageName: node
+ linkType: hard
+
"bin-build@npm:^3.0.0":
version: 3.0.0
resolution: "bin-build@npm:3.0.0"
@@ -6306,14 +6435,14 @@ __metadata:
languageName: node
linkType: hard
-"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.3":
- version: 7.0.3
- resolution: "cross-spawn@npm:7.0.3"
+"cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6":
+ version: 7.0.6
+ resolution: "cross-spawn@npm:7.0.6"
dependencies:
path-key: "npm:^3.1.0"
shebang-command: "npm:^2.0.0"
which: "npm:^2.0.1"
- checksum:
10/e1a13869d2f57d974de0d9ef7acbf69dc6937db20b918525a01dacb5032129bd552d290d886d981e99f1b624cb03657084cc87bd40f115c07ecf376821c729ce
+ checksum:
10/0d52657d7ae36eb130999dffff1168ec348687b48dd38e2ff59992ed916c88d328cf1d07ff4a4a10bc78de5e1c23f04b306d569e42f7a2293915c081e4dfee86
languageName: node
linkType: hard
@@ -6468,6 +6597,16 @@ __metadata:
languageName: node
linkType: hard
+"css-tree@npm:^3.1.0":
+ version: 3.1.0
+ resolution: "css-tree@npm:3.1.0"
+ dependencies:
+ mdn-data: "npm:2.12.2"
+ source-map-js: "npm:^1.0.1"
+ checksum:
10/e8c5c8e98e3aa4a620fda0b813ce57ccf99281652bf9d23e5cdfc9961c9a93a6769941f9a92e31e65d90f446f42fa83879ab0185206dc7a178d9f656d0913e14
+ languageName: node
+ linkType: hard
+
"css-tree@npm:~2.2.0":
version: 2.2.1
resolution: "css-tree@npm:2.2.1"
@@ -6613,6 +6752,17 @@ __metadata:
languageName: node
linkType: hard
+"cssstyle@npm:^5.3.2":
+ version: 5.3.3
+ resolution: "cssstyle@npm:5.3.3"
+ dependencies:
+ "@asamuzakjp/css-color": "npm:^4.0.3"
+ "@csstools/css-syntax-patches-for-csstree": "npm:^1.0.14"
+ css-tree: "npm:^3.1.0"
+ checksum:
10/8c6133761395f03d50e74ff4c05473b4835b79013efed3f4b79dc452d94a7122082887d89c3c1164bba0e8919be209b75e4f4706197c086fc9f4b50182ab03d6
+ languageName: node
+ linkType: hard
+
"cuint@npm:^0.2.2":
version: 0.2.2
resolution: "cuint@npm:0.2.2"
@@ -6651,6 +6801,16 @@ __metadata:
languageName: node
linkType: hard
+"data-urls@npm:^6.0.0":
+ version: 6.0.0
+ resolution: "data-urls@npm:6.0.0"
+ dependencies:
+ whatwg-mimetype: "npm:^4.0.0"
+ whatwg-url: "npm:^15.0.0"
+ checksum:
10/a47f0dde184337c4f168d455aedf0b486fed87b6ca583b4b9ad55d1515f4836b418d4bdc5b5b6fc55e321feb826029586a0d47e1c9a9e7ac4d52a78faceb7fb0
+ languageName: node
+ linkType: hard
+
"date-time@npm:^3.1.0":
version: 3.1.0
resolution: "date-time@npm:3.1.0"
@@ -6742,6 +6902,13 @@ __metadata:
languageName: node
linkType: hard
+"decimal.js@npm:^10.6.0":
+ version: 10.6.0
+ resolution: "decimal.js@npm:10.6.0"
+ checksum:
10/c0d45842d47c311d11b38ce7ccc911121953d4df3ebb1465d92b31970eb4f6738a065426a06094af59bee4b0d64e42e7c8984abd57b6767c64ea90cf90bb4a69
+ languageName: node
+ linkType: hard
+
"decode-uri-component@npm:^0.2.0":
version: 0.2.2
resolution: "decode-uri-component@npm:0.2.2"
@@ -7698,6 +7865,13 @@ __metadata:
languageName: node
linkType: hard
+"entities@npm:^6.0.0":
+ version: 6.0.1
+ resolution: "entities@npm:6.0.1"
+ checksum:
10/62af1307202884349d2867f0aac5c60d8b57102ea0b0e768b16246099512c28e239254ad772d6834e7e14cb1b6f153fc3d0c031934e3183b086c86d3838d874a
+ languageName: node
+ linkType: hard
+
"env-paths@npm:3.0.0, env-paths@npm:^3.0.0":
version: 3.0.0
resolution: "env-paths@npm:3.0.0"
@@ -9664,13 +9838,13 @@ __metadata:
languageName: node
linkType: hard
-"foreground-child@npm:^3.1.0":
- version: 3.1.1
- resolution: "foreground-child@npm:3.1.1"
+"foreground-child@npm:^3.1.0, foreground-child@npm:^3.3.1":
+ version: 3.3.1
+ resolution: "foreground-child@npm:3.3.1"
dependencies:
- cross-spawn: "npm:^7.0.0"
+ cross-spawn: "npm:^7.0.6"
signal-exit: "npm:^4.0.1"
- checksum:
10/087edd44857d258c4f73ad84cb8df980826569656f2550c341b27adf5335354393eec24ea2fabd43a253233fb27cee177ebe46bd0b7ea129c77e87cb1e9936fb
+ checksum:
10/427b33f997a98073c0424e5c07169264a62cda806d8d2ded159b5b903fdfc8f0a1457e06b5fc35506497acb3f1e353f025edee796300209ac6231e80edece835
languageName: node
linkType: hard
@@ -10272,6 +10446,22 @@ __metadata:
languageName: node
linkType: hard
+"glob@npm:^11.0.3":
+ version: 11.0.3
+ resolution: "glob@npm:11.0.3"
+ dependencies:
+ foreground-child: "npm:^3.3.1"
+ jackspeak: "npm:^4.1.1"
+ minimatch: "npm:^10.0.3"
+ minipass: "npm:^7.1.2"
+ package-json-from-dist: "npm:^1.0.0"
+ path-scurry: "npm:^2.0.0"
+ bin:
+ glob: dist/esm/bin.mjs
+ checksum:
10/2ae536c1360c0266b523b2bfa6aadc10144a8b7e08869b088e37ac3c27cd30774f82e4bfb291cde796776e878f9e13200c7ff44010eb7054e00f46f649397893
+ languageName: node
+ linkType: hard
+
"glob@npm:^7.1.0, glob@npm:^7.1.1, glob@npm:^7.1.2, glob@npm:^7.1.3,
glob@npm:^7.2.0":
version: 7.2.0
resolution: "glob@npm:7.2.0"
@@ -11025,7 +11215,7 @@ __metadata:
languageName: node
linkType: hard
-"he@npm:1.2.x":
+"he@npm:1.2.0, he@npm:1.2.x":
version: 1.2.0
resolution: "he@npm:1.2.0"
bin:
@@ -11143,6 +11333,15 @@ __metadata:
languageName: node
linkType: hard
+"html-encoding-sniffer@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "html-encoding-sniffer@npm:4.0.0"
+ dependencies:
+ whatwg-encoding: "npm:^3.1.1"
+ checksum:
10/e86efd493293a5671b8239bd099d42128433bb3c7b0fdc7819282ef8e118a21f5dead0ad6f358e024a4e5c84f17ebb7a9b36075220fac0a6222b207248bede6f
+ languageName: node
+ linkType: hard
+
"html-minifier@npm:^3.5.20":
version: 3.5.21
resolution: "html-minifier@npm:3.5.21"
@@ -11275,13 +11474,13 @@ __metadata:
languageName: node
linkType: hard
-"http-proxy-agent@npm:^7.0.0":
- version: 7.0.0
- resolution: "http-proxy-agent@npm:7.0.0"
+"http-proxy-agent@npm:^7.0.0, http-proxy-agent@npm:^7.0.2":
+ version: 7.0.2
+ resolution: "http-proxy-agent@npm:7.0.2"
dependencies:
agent-base: "npm:^7.1.0"
debug: "npm:^4.3.4"
- checksum:
10/dbaaf3d9f3fc4df4a5d7ec45d456ec50f575240b557160fa63427b447d1f812dd7fe4a4f17d2e1ba003d231f07edf5a856ea6d91cb32d533062ff20a7803ccac
+ checksum:
10/d062acfa0cb82beeb558f1043c6ba770ea892b5fb7b28654dbc70ea2aeea55226dd34c02a294f6c1ca179a5aa483c4ea641846821b182edbd9cc5d89b54c6848
languageName: node
linkType: hard
@@ -11348,7 +11547,7 @@ __metadata:
languageName: node
linkType: hard
-"https-proxy-agent@npm:7.0.4, https-proxy-agent@npm:^7.0.1":
+"https-proxy-agent@npm:7.0.4":
version: 7.0.4
resolution: "https-proxy-agent@npm:7.0.4"
dependencies:
@@ -11368,6 +11567,16 @@ __metadata:
languageName: node
linkType: hard
+"https-proxy-agent@npm:^7.0.1, https-proxy-agent@npm:^7.0.6":
+ version: 7.0.6
+ resolution: "https-proxy-agent@npm:7.0.6"
+ dependencies:
+ agent-base: "npm:^7.1.2"
+ debug: "npm:4"
+ checksum:
10/784b628cbd55b25542a9d85033bdfd03d4eda630fb8b3c9477959367f3be95dc476ed2ecbb9836c359c7c698027fc7b45723a302324433590f45d6c1706e8c13
+ languageName: node
+ linkType: hard
+
"hugo-extended@npm:^0.121.2":
version: 0.121.2
resolution: "hugo-extended@npm:0.121.2"
@@ -11412,7 +11621,7 @@ __metadata:
languageName: node
linkType: hard
-"iconv-lite@npm:^0.6.2":
+"iconv-lite@npm:0.6.3, iconv-lite@npm:^0.6.2":
version: 0.6.3
resolution: "iconv-lite@npm:0.6.3"
dependencies:
@@ -12339,6 +12548,13 @@ __metadata:
languageName: node
linkType: hard
+"is-potential-custom-element-name@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "is-potential-custom-element-name@npm:1.0.1"
+ checksum:
10/ced7bbbb6433a5b684af581872afe0e1767e2d1146b2207ca0068a648fb5cab9d898495d1ac0583524faaf24ca98176a7d9876363097c2d14fee6dd324f3a1ab
+ languageName: node
+ linkType: hard
+
"is-promise@npm:^2.1.0":
version: 2.1.0
resolution: "is-promise@npm:2.1.0"
@@ -12666,6 +12882,15 @@ __metadata:
languageName: node
linkType: hard
+"jackspeak@npm:^4.1.1":
+ version: 4.1.1
+ resolution: "jackspeak@npm:4.1.1"
+ dependencies:
+ "@isaacs/cliui": "npm:^8.0.2"
+ checksum:
10/ffceb270ec286841f48413bfb4a50b188662dfd599378ce142b6540f3f0a66821dc9dcb1e9ebc55c6c3b24dc2226c96e5819ba9bd7a241bd29031b61911718c7
+ languageName: node
+ linkType: hard
+
"jest-get-type@npm:^27.5.1":
version: 27.5.1
resolution: "jest-get-type@npm:27.5.1"
@@ -12759,6 +12984,39 @@ __metadata:
languageName: node
linkType: hard
+"jsdom@npm:^27.1.0":
+ version: 27.1.0
+ resolution: "jsdom@npm:27.1.0"
+ dependencies:
+ "@acemir/cssom": "npm:^0.9.19"
+ "@asamuzakjp/dom-selector": "npm:^6.7.3"
+ cssstyle: "npm:^5.3.2"
+ data-urls: "npm:^6.0.0"
+ decimal.js: "npm:^10.6.0"
+ html-encoding-sniffer: "npm:^4.0.0"
+ http-proxy-agent: "npm:^7.0.2"
+ https-proxy-agent: "npm:^7.0.6"
+ is-potential-custom-element-name: "npm:^1.0.1"
+ parse5: "npm:^8.0.0"
+ saxes: "npm:^6.0.0"
+ symbol-tree: "npm:^3.2.4"
+ tough-cookie: "npm:^6.0.0"
+ w3c-xmlserializer: "npm:^5.0.0"
+ webidl-conversions: "npm:^8.0.0"
+ whatwg-encoding: "npm:^3.1.1"
+ whatwg-mimetype: "npm:^4.0.0"
+ whatwg-url: "npm:^15.1.0"
+ ws: "npm:^8.18.3"
+ xml-name-validator: "npm:^5.0.0"
+ peerDependencies:
+ canvas: ^3.0.0
+ peerDependenciesMeta:
+ canvas:
+ optional: true
+ checksum:
10/9e2bd9824abed594da64fc58f1bdb817c7f82ba3025cef4817e6709807f886ac71b7b6a0f4f69ba604e9137bbcd6b7246b98dec53bde95500f5ac4b39a8ebb00
+ languageName: node
+ linkType: hard
+
"json-buffer@npm:3.0.0":
version: 3.0.0
resolution: "json-buffer@npm:3.0.0"
@@ -13671,6 +13929,13 @@ __metadata:
languageName: node
linkType: hard
+"lru-cache@npm:^11.0.0, lru-cache@npm:^11.2.1, lru-cache@npm:^11.2.2":
+ version: 11.2.2
+ resolution: "lru-cache@npm:11.2.2"
+ checksum:
10/fa7919fbf068a739f79a1ad461eb273514da7246cebb9dca68e3cd7ba19e3839e7e2aaecd9b72867e08038561eeb96941189e89b3d4091c75ced4f56c71c80db
+ languageName: node
+ linkType: hard
+
"lru-cache@npm:^4.0.1":
version: 4.1.5
resolution: "lru-cache@npm:4.1.5"
@@ -13912,6 +14177,13 @@ __metadata:
languageName: node
linkType: hard
+"mdn-data@npm:2.12.2":
+ version: 2.12.2
+ resolution: "mdn-data@npm:2.12.2"
+ checksum:
10/854e41715a9358e69f9a530117cd6ca7e71d06176469de8d70b1e629753b6827f5bd730995c16ad3750f3c9bad92230f8e4e178de2b34926b05f5205d27d76af
+ languageName: node
+ linkType: hard
+
"media-typer@npm:0.3.0":
version: 0.3.0
resolution: "media-typer@npm:0.3.0"
@@ -14180,6 +14452,15 @@ __metadata:
languageName: node
linkType: hard
+"minimatch@npm:^10.0.3":
+ version: 10.1.1
+ resolution: "minimatch@npm:10.1.1"
+ dependencies:
+ "@isaacs/brace-expansion": "npm:^5.0.0"
+ checksum:
10/110f38921ea527022e90f7a5f43721838ac740d0a0c26881c03b57c261354fb9a0430e40b2c56dfcea2ef3c773768f27210d1106f1f2be19cde3eea93f26f45e
+ languageName: node
+ linkType: hard
+
"minimatch@npm:^5.0.1, minimatch@npm:^5.1.0":
version: 5.1.6
resolution: "minimatch@npm:5.1.6"
@@ -14964,6 +15245,16 @@ __metadata:
languageName: node
linkType: hard
+"node-html-parser@npm:^7.0.1":
+ version: 7.0.1
+ resolution: "node-html-parser@npm:7.0.1"
+ dependencies:
+ css-select: "npm:^5.1.0"
+ he: "npm:1.2.0"
+ checksum:
10/726db99091551ab3620f001892d6afb4c87b505ffc8fc6b8cd7bb225701a805b85615504dd93a0d4ee095ef46d2ec4dabc9b61165d8034704b191601f5bf6936
+ languageName: node
+ linkType: hard
+
"node-pre-gyp@npm:*":
version: 0.16.0
resolution: "node-pre-gyp@npm:0.16.0"
@@ -15977,6 +16268,13 @@ __metadata:
languageName: node
linkType: hard
+"package-json-from-dist@npm:^1.0.0":
+ version: 1.0.1
+ resolution: "package-json-from-dist@npm:1.0.1"
+ checksum:
10/58ee9538f2f762988433da00e26acc788036914d57c71c246bf0be1b60cdbd77dd60b6a3e1a30465f0b248aeb80079e0b34cb6050b1dfa18c06953bb1cbc7602
+ languageName: node
+ linkType: hard
+
"package-json@npm:^8.1.0":
version: 8.1.1
resolution: "package-json@npm:8.1.1"
@@ -16137,6 +16435,15 @@ __metadata:
languageName: node
linkType: hard
+"parse5@npm:^8.0.0":
+ version: 8.0.0
+ resolution: "parse5@npm:8.0.0"
+ dependencies:
+ entities: "npm:^6.0.0"
+ checksum:
10/1973850932bb1cbd52ab64502761489fbe1bb43a52dee7ce41aac0b6c33a51a92aaee04661590b0912b739ae9ee316bce4c78c8ea34af42a7e522c983c3c6cf5
+ languageName: node
+ linkType: hard
+
"parseurl@npm:~1.3.2, parseurl@npm:~1.3.3":
version: 1.3.3
resolution: "parseurl@npm:1.3.3"
@@ -16270,6 +16577,16 @@ __metadata:
languageName: node
linkType: hard
+"path-scurry@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "path-scurry@npm:2.0.1"
+ dependencies:
+ lru-cache: "npm:^11.0.0"
+ minipass: "npm:^7.1.2"
+ checksum:
10/1e9c74e9ccf94d7c16056a5cb2dba9fa23eec1bc221ab15c44765486b9b9975b4cd9a4d55da15b96eadf67d5202e9a2f1cec9023fbb35fe7d9ccd0ff1891f88b
+ languageName: node
+ linkType: hard
+
"path-to-regexp@npm:0.1.7":
version: 0.1.7
resolution: "path-to-regexp@npm:0.1.7"
@@ -17451,10 +17768,10 @@ __metadata:
languageName: node
linkType: hard
-"punycode@npm:^2.1.0":
- version: 2.1.1
- resolution: "punycode@npm:2.1.1"
- checksum:
10/939daa010c2cacebdb060c40ecb52fef0a739324a66f7fffe0f94353a1ee83e3b455e9032054c4a0c4977b0a28e27086f2171c392832b59a01bd948fd8e20914
+"punycode@npm:^2.1.0, punycode@npm:^2.3.1":
+ version: 2.3.1
+ resolution: "punycode@npm:2.3.1"
+ checksum:
10/febdc4362bead22f9e2608ff0171713230b57aff9dddc1c273aa2a651fbd366f94b7d6a71d78342a7c0819906750351ca7f2edd26ea41b626d87d6a13d1bd059
languageName: node
linkType: hard
@@ -18443,13 +18760,29 @@ __metadata:
languageName: node
linkType: hard
-"sax@npm:^1.2.4, sax@npm:~1.2.4":
+"sax@npm:>=0.6.0, sax@npm:^1.2.4":
+ version: 1.4.3
+ resolution: "sax@npm:1.4.3"
+ checksum:
10/99161215f23e0b13bc7f94adbaa63a6a2f188fe291c450790d92b5bc3cd7966d574a15dcd5918c30917e17ed68129e34cc3168564263b967f9b8f61869d6ccc4
+ languageName: node
+ linkType: hard
+
+"sax@npm:~1.2.4":
version: 1.2.4
resolution: "sax@npm:1.2.4"
checksum:
10/09b79ff6dc09689a24323352117c94593c69db348997b2af0edbd82fa08aba47d778055bf9616b57285bb73d25d790900c044bf631a8f10c8252412e3f3fe5dd
languageName: node
linkType: hard
+"saxes@npm:^6.0.0":
+ version: 6.0.0
+ resolution: "saxes@npm:6.0.0"
+ dependencies:
+ xmlchars: "npm:^2.2.0"
+ checksum:
10/97b50daf6ca3a153e89842efa18a862e446248296622b7473c169c84c823ee8a16e4a43bac2f73f11fc8cb9168c73fbb0d73340f26552bac17970e9052367aa9
+ languageName: node
+ linkType: hard
+
"scope-analyzer@npm:^2.0.0":
version: 2.1.1
resolution: "scope-analyzer@npm:2.1.1"
@@ -20002,6 +20335,13 @@ __metadata:
languageName: node
linkType: hard
+"symbol-tree@npm:^3.2.4":
+ version: 3.2.4
+ resolution: "symbol-tree@npm:3.2.4"
+ checksum:
10/c09a00aadf279d47d0c5c46ca3b6b2fbaeb45f0a184976d599637d412d3a70bbdc043ff33effe1206dea0e36e0ad226cb957112e7ce9a4bf2daedf7fa4f85c53
+ languageName: node
+ linkType: hard
+
"syntax-error@npm:^1.1.1":
version: 1.4.0
resolution: "syntax-error@npm:1.4.0"
@@ -20373,6 +20713,24 @@ __metadata:
languageName: node
linkType: hard
+"tldts-core@npm:^7.0.17":
+ version: 7.0.17
+ resolution: "tldts-core@npm:7.0.17"
+ checksum:
10/246307f0d1b46ab07fcd00ea1d9afc4de3f1148a35cb0dd637ae04cc525e4ddcc66474b4ba7867d4361fbac70f19ec79db226103142e1d3f63cdd764938608da
+ languageName: node
+ linkType: hard
+
+"tldts@npm:^7.0.5":
+ version: 7.0.17
+ resolution: "tldts@npm:7.0.17"
+ dependencies:
+ tldts-core: "npm:^7.0.17"
+ bin:
+ tldts: bin/cli.js
+ checksum:
10/8730b0c8d2a393e6e6ec061b10f967f4db59ca78ee0c0259feafc311eab9a986138602831b7b886807638e69c525d88964c2056f42be4ca2b95200fe2ac9164c
+ languageName: node
+ linkType: hard
+
"tmp-promise@npm:^3.0.2, tmp-promise@npm:^3.0.3":
version: 3.0.3
resolution: "tmp-promise@npm:3.0.3"
@@ -20532,6 +20890,24 @@ __metadata:
languageName: node
linkType: hard
+"tough-cookie@npm:^6.0.0":
+ version: 6.0.0
+ resolution: "tough-cookie@npm:6.0.0"
+ dependencies:
+ tldts: "npm:^7.0.5"
+ checksum:
10/1b0592241655912eb972e1c284ccf975af154576b8e9912cad4ed7b4b408a60ccfdad1bc53eef10d376f6a5ef9d84e2f8ea0b46c92263d52de855247ff100e27
+ languageName: node
+ linkType: hard
+
+"tr46@npm:^6.0.0":
+ version: 6.0.0
+ resolution: "tr46@npm:6.0.0"
+ dependencies:
+ punycode: "npm:^2.3.1"
+ checksum:
10/e6d402eb2b780a40042f327f77b4ae316da1d2b18a29c16e48c239f5267c6005bbf780f854179cfae62b02dfaa70b0e9aad8f0078ccc4225f5b3b3b131928e8f
+ languageName: node
+ linkType: hard
+
"tr46@npm:~0.0.3":
version: 0.0.3
resolution: "tr46@npm:0.0.3"
@@ -20665,6 +21041,22 @@ __metadata:
languageName: node
linkType: hard
+"turndown-plugin-gfm@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "turndown-plugin-gfm@npm:1.0.2"
+ checksum:
10/07d8520ad4d272da5b69ed8032bf10c4cf5ff605541da0df1ac2c61bd5e0df6e25cbd8395a4f66e5db03cb2c4421d202feeeebb39c59a0fe45966ffcde3c5564
+ languageName: node
+ linkType: hard
+
+"turndown@npm:^7.2.2":
+ version: 7.2.2
+ resolution: "turndown@npm:7.2.2"
+ dependencies:
+ "@mixmark-io/domino": "npm:^2.2.0"
+ checksum:
10/e0a6f7f0c2bc8447ca7ea145348c9e337163a00c9d95f49e5eecdbc9931002aa0253c7561fbc299280c854d5308ed5a0eacfc9b4e399d698fce64be4d2d7bb52
+ languageName: node
+ linkType: hard
+
"type-check@npm:~0.3.2":
version: 0.3.2
resolution: "type-check@npm:0.3.2"
@@ -21559,6 +21951,15 @@ __metadata:
languageName: node
linkType: hard
+"w3c-xmlserializer@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "w3c-xmlserializer@npm:5.0.0"
+ dependencies:
+ xml-name-validator: "npm:^5.0.0"
+ checksum:
10/d78f59e6b4f924aa53b6dfc56949959229cae7fe05ea9374eb38d11edcec01398b7f5d7a12576bd5acc57ff446abb5c9115cd83b9d882555015437cf858d42f0
+ languageName: node
+ linkType: hard
+
"wait-port@npm:1.1.0":
version: 1.1.0
resolution: "wait-port@npm:1.1.0"
@@ -21586,6 +21987,13 @@ __metadata:
languageName: node
linkType: hard
+"webidl-conversions@npm:^8.0.0":
+ version: 8.0.0
+ resolution: "webidl-conversions@npm:8.0.0"
+ checksum:
10/8138d1b291c8f311d93de680653b13b04560aa35d83f9606642e746fca39d7dab9cddd9282ade21774115ea332b8b11f008106b82d4a0125e98a49479381aeee
+ languageName: node
+ linkType: hard
+
"websocket-driver@npm:>=0.5.1":
version: 0.7.4
resolution: "websocket-driver@npm:0.7.4"
@@ -21611,6 +22019,32 @@ __metadata:
languageName: node
linkType: hard
+"whatwg-encoding@npm:^3.1.1":
+ version: 3.1.1
+ resolution: "whatwg-encoding@npm:3.1.1"
+ dependencies:
+ iconv-lite: "npm:0.6.3"
+ checksum:
10/bbef815eb67f91487c7f2ef96329743f5fd8357d7d62b1119237d25d41c7e452dff8197235b2d3c031365a17f61d3bb73ca49d0ed1582475aa4a670815e79534
+ languageName: node
+ linkType: hard
+
+"whatwg-mimetype@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "whatwg-mimetype@npm:4.0.0"
+ checksum:
10/894a618e2d90bf444b6f309f3ceb6e58cf21b2beaa00c8b333696958c4076f0c7b30b9d33413c9ffff7c5832a0a0c8569e5bb347ef44beded72aeefd0acd62e8
+ languageName: node
+ linkType: hard
+
+"whatwg-url@npm:^15.0.0, whatwg-url@npm:^15.1.0":
+ version: 15.1.0
+ resolution: "whatwg-url@npm:15.1.0"
+ dependencies:
+ tr46: "npm:^6.0.0"
+ webidl-conversions: "npm:^8.0.0"
+ checksum:
10/9ae5ce70060f2a9ea73799062af6e796ec2477f44bf1a886953b405700e3ab11d15aa0fe7088c4215f839e56a845d5d1c44584ed292a832837a8c8549c566886
+ languageName: node
+ linkType: hard
+
"whatwg-url@npm:^5.0.0":
version: 5.0.0
resolution: "whatwg-url@npm:5.0.0"
@@ -21860,6 +22294,21 @@ __metadata:
languageName: node
linkType: hard
+"ws@npm:^8.18.3":
+ version: 8.18.3
+ resolution: "ws@npm:8.18.3"
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: ">=5.0.2"
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+ checksum:
10/725964438d752f0ab0de582cd48d6eeada58d1511c3f613485b5598a83680bedac6187c765b0fe082e2d8cc4341fc57707c813ae780feee82d0c5efe6a4c61b6
+ languageName: node
+ linkType: hard
+
"ws@npm:~8.11.0":
version: 8.11.0
resolution: "ws@npm:8.11.0"
@@ -21889,6 +22338,37 @@ __metadata:
languageName: node
linkType: hard
+"xml-name-validator@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "xml-name-validator@npm:5.0.0"
+ checksum:
10/43f30f3f6786e406dd665acf08cd742d5f8a46486bd72517edb04b27d1bcd1599664c2a4a99fc3f1e56a3194bff588b12f178b7972bc45c8047bdc4c3ac8d4a1
+ languageName: node
+ linkType: hard
+
+"xml2js@npm:^0.6.2":
+ version: 0.6.2
+ resolution: "xml2js@npm:0.6.2"
+ dependencies:
+ sax: "npm:>=0.6.0"
+ xmlbuilder: "npm:~11.0.0"
+ checksum:
10/df29de8eeedb762c367d87945c39bcf54db19a2c522607491c266ed6184b5a749e37ff29cfaed0ac149da9ba332ac3dcf8e5ff2bd0a206be3343eca95faa941d
+ languageName: node
+ linkType: hard
+
+"xmlbuilder@npm:~11.0.0":
+ version: 11.0.1
+ resolution: "xmlbuilder@npm:11.0.1"
+ checksum:
10/c8c3d208783718db5b285101a736cd8e6b69a5c265199a0739abaa93d1a1b7de5489fd16df4e776e18b2c98cb91f421a7349e99fd8c1ebeb44ecfed72a25091a
+ languageName: node
+ linkType: hard
+
+"xmlchars@npm:^2.2.0":
+ version: 2.2.0
+ resolution: "xmlchars@npm:2.2.0"
+ checksum:
10/4ad5924974efd004a47cce6acf5c0269aee0e62f9a805a426db3337af7bcbd331099df174b024ace4fb18971b8a56de386d2e73a1c4b020e3abd63a4a9b917f1
+ languageName: node
+ linkType: hard
+
"xmlhttprequest-ssl@npm:~2.0.0":
version: 2.0.0
resolution: "xmlhttprequest-ssl@npm:2.0.0"