lexical-remark
Version:
This package contains Markdown helpers and functionality for Lexical using remark-parse.
94 lines (83 loc) • 2.58 kB
text/typescript
/* eslint-disable @typescript-eslint/no-use-before-define */
import { Paragraph, Root } from 'mdast';
import { Plugin } from 'unified';
import { visit } from 'unist-util-visit';
import { Node, YouTube } from '../types';
/**
* A regular expression to detect a YouTube url and parse out the video id as the sixth capture group
*
* @example
* function getVideoId(value: string) {
* const match = value.match(YOUTUBE_URL_REGEX);
* return !!match ? match[6] : null;
* }
*/
export const YOUTUBE_URL_REGEX =
/^((?:https?:)?\/\/)?((?:www|m)\.)?((?:youtube(-nocookie)?\.com|youtu.be))(\/(?:watch\?v=|embed\/|shorts\/|v\/)?)([\w\-]+)(\S+)?$/;
/**
* A remark plugin to enrich an mdast node tree by converting paragraph nodes containing only a YouTube url into YouTube nodes
*/
export const remarkYoutube: Plugin<[], string, Root> = () => {
return convertYoutubeParagraphs;
};
function convertYoutubeParagraphs(tree: Node) {
const videoId = isYoutubeParagraphNode(tree);
if (videoId) {
(tree as Paragraph).children = [
{
type: 'youtube',
videoId,
},
] as any;
}
visit(tree, function (node) {
const visitedVideoId = isYoutubeParagraphNode(node);
if (visitedVideoId) {
(node as Paragraph).children = [
{
type: 'youtube',
videoId: visitedVideoId,
},
] as any;
}
});
}
function isYoutubeParagraphNode(node: Node) {
if (node.type === 'paragraph' && node.children.length === 1 && node.children[0].type === 'text') {
const match = node.children[0].value.match(YOUTUBE_URL_REGEX);
return !!match && match[6];
}
return false;
}
/**
* A remark plugin to simplify an mdast node tree by converting YouTube nodes back to paragraph nodes
*/
export function youtubeRemark(this: any) {
return convertToYoutubeParagraphs;
}
function convertToYoutubeParagraphs(tree: any) {
if (tree.type === 'youtube') {
tree.type = 'paragraph';
(tree as Paragraph).children = [
{
type: 'text',
value: `https://www.youtube.com/watch?v=${(tree as YouTube).videoId}`,
},
];
// @ts-expect-error casting to Youtube
delete (tree as YouTube).videoId;
}
visit(tree, function (node) {
if (node.type === 'youtube') {
node.type = 'paragraph';
(node as Paragraph).children = [
{
type: 'text',
value: `https://www.youtube.com/watch?v=${(node as YouTube).videoId}`,
},
];
// @ts-expect-error casting to Youtube
delete (node as YouTube).videoId;
}
});
}