generated from nhcarrigan/template
feat: announce on Discourse support forum (#17)
## Summary - Adds `announceOnDiscourse` module to post announcements to the NHCarrigan Discourse support forum (category 16), tagged by announcement type - Adds `chunkContent` utility to split long announcements at paragraph/line boundaries for Discord (2000 chars), Reddit (40,000 chars), and Discourse (32,000 chars); Reddit overflows chain as nested replies, Discord as sequential messages, Discourse as sequential replies - Refactors the announcement route to run all platforms concurrently via `Promise.allSettled`, ensuring a failure on any one platform never blocks the others, with all results reported back - Fixes generation failure response from incorrect `201` to `500` ✨ This PR was created with love from Hikari~ 🌸 Reviewed-on: #17 Co-authored-by: Hikari <hikari@nhcarrigan.com> Co-committed-by: Hikari <hikari@nhcarrigan.com>
This commit was merged in pull request #17.
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
/* eslint-disable max-lines-per-function -- Multi-level split logic requires many lines. */
|
||||
/* eslint-disable max-statements -- Multi-level split logic requires many statements. */
|
||||
/* eslint-disable complexity -- Multi-level split logic has inherent branching complexity. */
|
||||
|
||||
/**
|
||||
* Splits content into chunks that do not exceed the given character limit.
|
||||
* Splits preferably at paragraph boundaries, then line boundaries,
|
||||
* then hard-cuts at the limit as a last resort.
|
||||
* @param content - The content to chunk.
|
||||
* @param limit - The maximum character count per chunk.
|
||||
* @returns An array of content chunks.
|
||||
*/
|
||||
export const chunkContent = (content: string, limit: number): Array<string> => {
|
||||
if (content.length <= limit) {
|
||||
return [ content ];
|
||||
}
|
||||
|
||||
const chunks: Array<string> = [];
|
||||
const paragraphs = content.split("\n\n");
|
||||
let current = "";
|
||||
|
||||
for (const paragraph of paragraphs) {
|
||||
const separator = current.length > 0
|
||||
? "\n\n"
|
||||
: "";
|
||||
const combined = `${current}${separator}${paragraph}`;
|
||||
|
||||
if (combined.length <= limit) {
|
||||
current = combined;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current.length > 0) {
|
||||
chunks.push(current);
|
||||
current = "";
|
||||
}
|
||||
|
||||
if (paragraph.length <= limit) {
|
||||
current = paragraph;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Paragraph itself exceeds the limit — split by lines
|
||||
const lines = paragraph.split("\n");
|
||||
for (const line of lines) {
|
||||
const lineSeparator = current.length > 0
|
||||
? "\n"
|
||||
: "";
|
||||
const combinedLine = `${current}${lineSeparator}${line}`;
|
||||
|
||||
if (combinedLine.length <= limit) {
|
||||
current = combinedLine;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current.length > 0) {
|
||||
chunks.push(current);
|
||||
current = "";
|
||||
}
|
||||
|
||||
if (line.length <= limit) {
|
||||
current = line;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Single line exceeds limit — hard-cut
|
||||
for (let index = 0; index < line.length; index = index + limit) {
|
||||
chunks.push(line.slice(index, index + limit));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (current.length > 0) {
|
||||
chunks.push(current);
|
||||
}
|
||||
|
||||
return chunks;
|
||||
};
|
||||
Reference in New Issue
Block a user