From 20008d7c2d1c0ac0652f98ee91196f8b08ca0ea3 Mon Sep 17 00:00:00 2001 From: DrMint <29893320+DrMint@users.noreply.github.com> Date: Fri, 19 May 2023 14:48:14 +0200 Subject: [PATCH] Posts now use displayable_description --- src/core/graphql/meiliTypes.ts | 8 ++++++- src/core/helpers/formatters.ts | 43 ++++++++++++++++++++++++++++++++++ src/helpers/meili.ts | 27 +++++++++++++++------ src/syncho.ts | 2 +- 4 files changed, 71 insertions(+), 9 deletions(-) diff --git a/src/core/graphql/meiliTypes.ts b/src/core/graphql/meiliTypes.ts index 5de4d9e..b72e0af 100644 --- a/src/core/graphql/meiliTypes.ts +++ b/src/core/graphql/meiliTypes.ts @@ -41,9 +41,15 @@ export interface MeiliVideo extends VideoAttributesFragment { channel_uid?: string; } -export interface MeiliPost extends PostAttributesFragment { +export interface MeiliPost extends Omit { id: string; sortable_date: number; + translations: (Omit< + NonNullable[number]>, + "body" + > & { + displayable_description?: string | null; + })[]; } export interface MeiliWikiPage extends Omit { diff --git a/src/core/helpers/formatters.ts b/src/core/helpers/formatters.ts index db4e03c..e5ad496 100644 --- a/src/core/helpers/formatters.ts +++ b/src/core/helpers/formatters.ts @@ -1,4 +1,7 @@ +import { convert } from "html-to-text"; +import { marked } from "marked"; import { isDefinedAndNotEmpty } from "./asserts"; +import DOMPurify from "isomorphic-dompurify"; export const prettySlug = (slug?: string, parentSlug?: string): string => { let newSlug = slug; @@ -218,3 +221,43 @@ export const slugify = (string: string | undefined): string => { }; export const sJoin = (...args: (string | null | undefined)[]): string => args.join(""); + +export const prettyMarkdown = (markdown: string): string => { + const block = (text: string) => `${text}\n\n`; + const escapeBlock = (text: string) => `${escape(text)}\n\n`; + const line = (text: string) => `${text}\n`; + const inline = (text: string) => text; + const newline = () => "\n"; + const empty = () => ""; + + const TxtRenderer: marked.Renderer = { + // Block elements + code: escapeBlock, + blockquote: block, + html: empty, + heading: block, + hr: newline, + list: (text) => block(text.trim()), + listitem: line, + checkbox: empty, + paragraph: block, + table: (header, body) => line(header + body), + tablerow: (text) => line(text.trim()), + tablecell: (text) => `${text} `, + // Inline elements + strong: inline, + em: inline, + codespan: inline, + br: newline, + del: inline, + link: (_0, _1, text) => text, + image: (_0, _1, text) => text, + text: inline, + // etc. + options: {}, + }; + + return convert( + DOMPurify.sanitize(marked(markdown, { renderer: TxtRenderer, mangle: false, headerIds: false })) + ).trim(); +}; diff --git a/src/helpers/meili.ts b/src/helpers/meili.ts index c157c4a..6e1817c 100644 --- a/src/helpers/meili.ts +++ b/src/helpers/meili.ts @@ -6,7 +6,7 @@ import { isDefinedAndNotEmpty, } from "core/helpers/asserts"; import { datePickerToDate, getUnixTime } from "core/helpers/date"; -import { prettyInlineTitle } from "core/helpers/formatters"; +import { prettyInlineTitle, prettyMarkdown } from "core/helpers/formatters"; import { isUntangibleGroupItem } from "core/helpers/libraryItem"; import { MeiliSearch } from "meilisearch"; @@ -47,9 +47,9 @@ const transformContent: TransformFunction = (data) => { translations: filterDefined(translations).map( ({ text_set, description, ...otherTranslatedFields }) => { let displayable_description = ""; - if (isDefinedAndNotEmpty(description)) displayable_description += description; - if (isDefinedAndNotEmpty(text_set?.text)) - displayable_description += `\n\n${text_set?.text}`; + if (isDefinedAndNotEmpty(description)) + displayable_description += prettyMarkdown(description); + if (text_set?.text) displayable_description += `\n\n${prettyMarkdown(text_set.text)}`; return { ...otherTranslatedFields, displayable_description, @@ -88,11 +88,24 @@ const transformPost: TransformFunction = (data) => { if (!data) throw new Error(`Data is empty ${MeiliIndices.POST}`); if (!data.attributes || !data.id) throw new Error(`Incorrect data stucture on ${MeiliIndices.POST}`); - const { id, attributes } = data; + const { + id, + attributes: { translations, ...otherAttributes }, + } = data; return { id, - ...attributes, - sortable_date: getUnixTime(datePickerToDate(attributes.date)), + sortable_date: getUnixTime(datePickerToDate(otherAttributes.date)), + translations: filterDefined(translations).map(({ body, excerpt, ...otherTranslatedFields }) => { + let displayable_description = ""; + if (isDefinedAndNotEmpty(excerpt)) displayable_description += prettyMarkdown(excerpt); + if (body) displayable_description += `\n\n${prettyMarkdown(body)}`; + return { + ...otherTranslatedFields, + excerpt, + displayable_description, + }; + }), + ...otherAttributes, }; }; diff --git a/src/syncho.ts b/src/syncho.ts index 187243a..5b0bb3c 100644 --- a/src/syncho.ts +++ b/src/syncho.ts @@ -60,7 +60,7 @@ export const synchronizeStrapiAndMeili = async (): Promise => { processIndex( MeiliIndices.POST, posts.posts?.data.map((item) => strapiToMeiliTransformFunctions.post(item)), - ["translations.title", "translations.excerpt", "translations.body"], + ["translations.title", "translations.displayable_description"], ["sortable_date"], ["hidden"] );