aboutsummaryrefslogtreecommitdiffstats
path: root/src/utils/helpers
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils/helpers')
-rw-r--r--src/utils/helpers/rehype.ts89
-rw-r--r--src/utils/helpers/schema-org.ts49
2 files changed, 124 insertions, 14 deletions
diff --git a/src/utils/helpers/rehype.ts b/src/utils/helpers/rehype.ts
index fc51da1..f061fc2 100644
--- a/src/utils/helpers/rehype.ts
+++ b/src/utils/helpers/rehype.ts
@@ -1,3 +1,11 @@
+import type Hast from 'hast';
+import { classnames } from 'hast-util-classnames';
+import rehypeParse from 'rehype-parse';
+import rehypeSlug from 'rehype-slug';
+import rehypeStringify from 'rehype-stringify';
+import { unified, type Plugin as UnifiedPlugin } from 'unified';
+import { visit } from 'unist-util-visit';
+
/**
* Update a stringified HTML tree using unified plugins.
*
@@ -6,16 +14,83 @@
* @param {string} content - The page contents.
* @returns {string} The updated page contents.
*/
-export const updateContentTree = async (content: string): Promise<string> => {
- const { unified } = await import('unified');
- const rehypeParse = (await import('rehype-parse')).default;
- const rehypeSlug = (await import('rehype-slug')).default;
- const rehypeStringify = (await import('rehype-stringify')).default;
-
- return unified()
+export const updateContentTree = (content: string): string =>
+ unified()
.use(rehypeParse, { fragment: true })
.use(rehypeSlug)
.use(rehypeStringify)
.processSync(content)
.toString();
+
+const isSubStrIn = (substr: string | RegExp, str: string) => {
+ if (typeof substr === 'string') return str.includes(substr);
+
+ return substr.test(str);
};
+
+const isNodeContainsClass = (
+ node: Hast.Element,
+ className: string | RegExp
+) => {
+ if (Array.isArray(node.properties.className)) {
+ return node.properties.className.some(
+ (singleClass) =>
+ typeof singleClass === 'string' && isSubStrIn(className, singleClass)
+ );
+ }
+
+ if (typeof node.properties.className === 'string')
+ return isSubStrIn(className, node.properties.className);
+
+ return false;
+};
+
+const rehypePrismClass: UnifiedPlugin<
+ Record<'className', string>[],
+ Hast.Root
+> =
+ ({ className }) =>
+ (tree) => {
+ const wpBlockClassName = 'wp-block-code';
+ const lineNumbersClassName = className
+ .replace('command-line', '')
+ .replace(/\s\s+/g, ' ');
+ const commandLineClassName = className
+ .replace('line-numbers', '')
+ .replace(/\s\s+/g, ' ');
+
+ visit(tree, 'element', (node) => {
+ if (
+ node.tagName === 'pre' &&
+ isNodeContainsClass(node, wpBlockClassName)
+ ) {
+ if (isNodeContainsClass(node, 'language-bash')) {
+ classnames(node, commandLineClassName);
+ node.properties['data-filter-output'] = '#output#';
+ } else if (isNodeContainsClass(node, /language-/)) {
+ classnames(node, lineNumbersClassName);
+ }
+ }
+ });
+ };
+
+/**
+ * Update a stringified HTML tree using unified plugins.
+ *
+ * It will parse the provided content to update the classnames of WordPress
+ * code blocks.
+ *
+ * @param {string} content - The page contents.
+ * @param {string} className - The prism classNames.
+ * @returns {string} The updated page contents.
+ */
+export const updateWordPressCodeBlocks = (
+ content: string,
+ className: string
+): string =>
+ unified()
+ .use(rehypeParse, { fragment: true })
+ .use(rehypePrismClass, { className })
+ .use(rehypeStringify)
+ .processSync(content)
+ .toString();
diff --git a/src/utils/helpers/schema-org.ts b/src/utils/helpers/schema-org.ts
index f028f5a..633c35a 100644
--- a/src/utils/helpers/schema-org.ts
+++ b/src/utils/helpers/schema-org.ts
@@ -3,11 +3,12 @@ import type {
Article,
Blog,
BlogPosting,
+ Comment as CommentSchema,
ContactPage,
Graph,
WebPage,
} from 'schema-dts';
-import type { Dates } from '../../types';
+import type { Dates, SingleComment } from '../../types';
import { CONFIG } from '../config';
import { ROUTES } from '../constants';
import { trimTrailingChars } from './strings';
@@ -50,14 +51,48 @@ export const getBlogSchema = ({
inLanguage: locale,
isPartOf: isSinglePage
? {
- '@id': `${host}${slug}`,
+ '@id': `${host}/${slug}`,
}
: undefined,
license: 'https://creativecommons.org/licenses/by-sa/4.0/deed.fr',
- mainEntityOfPage: isSinglePage ? undefined : { '@id': `${host}${slug}` },
+ mainEntityOfPage: isSinglePage ? undefined : { '@id': `${host}/${slug}` },
};
};
+/**
+ * Retrieve the JSON for Comment schema.
+ *
+ * @param props - The comments.
+ * @returns {CommentSchema[]} The JSON for Comment schema.
+ */
+export const getCommentsSchema = (comments: SingleComment[]): CommentSchema[] =>
+ comments.map((comment) => {
+ return {
+ '@context': 'https://schema.org',
+ '@id': `${CONFIG.url}/#comment-${comment.id}`,
+ '@type': 'Comment',
+ parentItem: comment.parentId
+ ? { '@id': `${CONFIG.url}/#comment-${comment.parentId}` }
+ : undefined,
+ about: { '@type': 'Article', '@id': `${CONFIG.url}/#article` },
+ author: {
+ '@type': 'Person',
+ name: comment.meta.author.name,
+ image: comment.meta.author.avatar?.src,
+ url: comment.meta.author.website,
+ },
+ creator: {
+ '@type': 'Person',
+ name: comment.meta.author.name,
+ image: comment.meta.author.avatar?.src,
+ url: comment.meta.author.website,
+ },
+ dateCreated: comment.meta.date,
+ datePublished: comment.meta.date,
+ text: comment.content,
+ };
+ });
+
export type SinglePageSchemaReturn = {
about: AboutPage;
contact: ContactPage;
@@ -159,10 +194,10 @@ export const getSinglePageSchema = <T extends SinglePageSchemaKind>({
isPartOf:
kind === 'post'
? {
- '@id': `${host}${ROUTES.BLOG}`,
+ '@id': `${host}/${ROUTES.BLOG}`,
}
: undefined,
- mainEntityOfPage: { '@id': `${host}${slug}` },
+ mainEntityOfPage: { '@id': `${host}/${slug}` },
} as SinglePageSchemaReturn[T];
};
@@ -203,7 +238,7 @@ export const getWebPageSchema = ({
updateDate,
}: GetWebPageSchemaProps): WebPage => {
return {
- '@id': `${host}${slug}`,
+ '@id': `${host}/${slug}`,
'@type': 'WebPage',
breadcrumb: { '@id': `${host}/#breadcrumb` },
lastReviewed: updateDate,
@@ -211,7 +246,7 @@ export const getWebPageSchema = ({
description,
inLanguage: locale,
reviewedBy: { '@id': `${host}/#branding` },
- url: `${host}${slug}`,
+ url: `${host}/${slug}`,
isPartOf: {
'@id': `${host}`,
},