diff --git a/src/app/lib/regex.const.js b/src/app/lib/regex.const.js index 53411412fb8..6bf65a6ab85 100644 --- a/src/app/lib/regex.const.js +++ b/src/app/lib/regex.const.js @@ -2,6 +2,7 @@ const regexes = { AMP_REGEX: /\.amp$/, APP_REGEX: /\.app$/, LITE_REGEX: /\.lite$/, + MARKDOWN_REGEX: /\.md$/, TLD_REGEX: /(\.com|\.co\.uk)/g, }; diff --git a/src/app/utilities/blocksToMarkdown/index.ts b/src/app/utilities/blocksToMarkdown/index.ts new file mode 100644 index 00000000000..c561f7a80a0 --- /dev/null +++ b/src/app/utilities/blocksToMarkdown/index.ts @@ -0,0 +1,25 @@ +export default function blocksToMarkdown(blocks: Block[]): string { + return blocks.map(block => renderBlock(block)).join('\n\n'); +} + +function renderBlock(block: Block): string { + switch (block.type) { + case 'paragraph': + return block.model?.text ?? ''; + case 'headline': + return `# ${block.model?.blocks[0].model.blocks[0].model.text ?? ''}`; + case 'subheadline': + return `## ${block.model?.blocks[0].model.blocks[0].model.text ?? ''}`; + case 'text': + const thisBlock = block.model.blocks; + const returnText = thisBlock.reduce((acc, block) => { + return acc + `${block.model?.text}\r\r`; + }, ''); + return `${returnText ?? ''}`; + case 'image': + const imgSrc = block.model.blocks[1].type === 'rawImage' ? block.model.blocks[1].model.locator : block.model.blocks[2].model.locator; + return `![${block.model.blocks[0].model.blocks[0].model.blocks[0].model.text}](https://ichef.bbci.co.uk/ace/ws/800/cpsprodpb/${imgSrc}.webp)`; + default: + // console.log(block.type, block); + } +} \ No newline at end of file diff --git a/src/app/utilities/getPathExtension/index.ts b/src/app/utilities/getPathExtension/index.ts index a836317b137..aeb80ab4629 100644 --- a/src/app/utilities/getPathExtension/index.ts +++ b/src/app/utilities/getPathExtension/index.ts @@ -1,5 +1,5 @@ import Url from 'url-parse'; -import { APP_REGEX, AMP_REGEX, LITE_REGEX } from '#app/lib/regex.const'; +import { APP_REGEX, AMP_REGEX, LITE_REGEX, MARKDOWN_REGEX } from '#app/lib/regex.const'; export default (url: string) => { const { pathname } = new Url(url, true); @@ -8,5 +8,6 @@ export default (url: string) => { isAmp: AMP_REGEX.test(pathname), isApp: APP_REGEX.test(pathname), isLite: LITE_REGEX.test(pathname), + isMarkdown: MARKDOWN_REGEX.test(pathname), }; }; diff --git a/ws-nextjs-app/pages/[service]/articles/handleArticleRoute.ts b/ws-nextjs-app/pages/[service]/articles/handleArticleRoute.ts index 59a8b8b74ee..33eeb1cc0bb 100644 --- a/ws-nextjs-app/pages/[service]/articles/handleArticleRoute.ts +++ b/ws-nextjs-app/pages/[service]/articles/handleArticleRoute.ts @@ -10,6 +10,7 @@ import handleError from '#app/routes/utils/handleError'; import { PageTypes } from '#app/models/types/global'; import { ArticleMetadata } from '#app/models/types/optimo'; +import blocksToMarkdown from '#app/utilities/blocksToMarkdown'; import augmentWithDisclaimer from './augmentWithDisclaimer'; import shouldRender from '../../../utilities/shouldRender'; import getPageData from '../../../utilities/pageRequests/getPageData'; @@ -40,7 +41,7 @@ export default async (context: GetServerSidePropsContext) => { const resolvedUrlWithoutQuery = resolvedUrl.split('?')?.[0]; - const { isAmp } = getPathExtension(resolvedUrlWithoutQuery); + const { isAmp, isMarkdown } = getPathExtension(resolvedUrlWithoutQuery); const { variant } = parseRoute(resolvedUrl); const { data } = await getPageData({ @@ -95,6 +96,13 @@ export default async (context: GetServerSidePropsContext) => { 'Cache-Control', `public, stale-if-error=90, stale-while-revalidate=30, max-age=${maxAge}`, ); + if (isMarkdown) { + const markdown = blocksToMarkdown(data?.pageData?.article.content.model.blocks); + context.res.setHeader('Content-Type', 'text/markdown; charset=utf-8'); + context.res.setHeader('x-markdown-tokens', Math.floor(markdown.length / 3)); + context.res.end(markdown); + return { props: {} }; + } const { topStories = null,