Feature/ai post suggestions (#40)

* feat: first cut on ai suggestion system for title and summary

* feat: completion of titling/excerpt/slug-suggestion AI quick action

* feat: feeds use existing excerpts. also documentation.

---------

Co-authored-by: hugo <hugoms@me.com>
This commit is contained in:
Georg Bauer
2026-03-07 09:54:13 +01:00
committed by GitHub
parent 72b21ddba7
commit 9871cb827f
30 changed files with 1270 additions and 245 deletions

View File

@@ -183,4 +183,56 @@ describe('GenerationSitemapFeedService', () => {
expect(result.atomXml).toContain('xml:lang="en"');
expect(result.atomXml).toContain('xml:lang="de"');
});
it('uses excerpt instead of full body in feed entry content when excerpt is available', () => {
const publishedPosts = [
makePost({
id: '1',
slug: 'excerpt-post',
title: 'Excerpt Post',
excerpt: 'Short feed summary.',
content: '# Excerpt Post\n\nVery long body that should not appear in feed content.',
}),
];
const result = buildSitemapAndFeeds({
baseUrl: 'https://example.com',
projectName: 'Test Blog',
maxPostsPerPage: 10,
publishedPosts,
publishedListPosts: publishedPosts,
postIndex: buildIndex(publishedPosts),
includeFeeds: true,
});
expect(result.rssXml).toContain('<content:encoded><![CDATA[<p>Short feed summary.</p>]]></content:encoded>');
expect(result.rssXml).not.toContain('Very long body that should not appear in feed content.');
expect(result.atomXml).toContain('<content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Short feed summary.</p></div></content>');
expect(result.atomXml).not.toContain('Very long body that should not appear in feed content.');
});
it('falls back to the post body in feed entry content when excerpt is missing', () => {
const publishedPosts = [
makePost({
id: '1',
slug: 'body-post',
title: 'Body Post',
content: '# Body Post\n\nBody paragraph used in feed content.',
}),
];
const result = buildSitemapAndFeeds({
baseUrl: 'https://example.com',
projectName: 'Test Blog',
maxPostsPerPage: 10,
publishedPosts,
publishedListPosts: publishedPosts,
postIndex: buildIndex(publishedPosts),
includeFeeds: true,
});
expect(result.rssXml).toContain('Body paragraph used in feed content.');
expect(result.atomXml).toContain('Body paragraph used in feed content.');
});
});