remark-directive-sugar
Version:
Remark plugin built on remark-directive, providing predefined directives for image captions, video embedding, styled GitHub links, badges, and more.
65 lines (64 loc) • 2.6 kB
JavaScript
import { createIfNeeded, mergeProps } from '../utils.js';
const customUrlRegex = /^(?:https?:\/\/)?(?:[\w-]+\.)+[a-z]{2,}(?:\/\S*)?$/;
const defaultPlatforms = {
youtube: 'https://www.youtube-nocookie.com/embed/{id}',
bilibili: 'https://player.bilibili.com/player.html?bvid={id}',
vimeo: 'https://player.vimeo.com/video/{id}',
};
/**
* Handles the `video` directive.
*/
export function handleVideoDirective(node, config, regex) {
if (node.type === 'textDirective')
throw new Error('Unexpected text directive. Use double colons (`::`) for a `video` leaf directive.');
if (node.type === 'containerDirective')
throw new Error('Unexpected container directive. Use double colons (`::`) for a `video` leaf directive.');
const defaultIframeProps = { className: ['rds-video'] };
const { iframeProps, platforms } = config;
const expandedPlatforms = {
...defaultPlatforms,
...platforms,
};
const data = (node.data ||= {});
const attributes = node.attributes || {};
const { children } = node;
const { id, ...attrs } = attributes;
// check if the platforms are invalid
if (platforms && 'url' in platforms) {
throw new Error('Invalid `video` directive config. The `url` is reserved.');
}
// check if the id is missing
if (!id) {
throw new Error('Invalid `video` directive. The `id` is missing.');
}
// check if it matches the platform & get type
let videoType;
const match = node.name.match(regex);
if (match?.[1]) {
if (match[1] in expandedPlatforms) {
videoType = match[1];
}
else {
throw new Error('Invalid `video` directive. The directive failed to match a valid video platform.');
}
}
else if (match && !match[1] && customUrlRegex.test(id)) {
videoType = 'url';
}
else {
throw new Error('Invalid `video` directive. Ensure a valid URL is passed via `id` instead of `#`.');
}
// get src
const src = videoType === 'url' ? id : expandedPlatforms[videoType].replace('{id}', id);
// get title
const title = children.length > 0 && children[0].type === 'text'
? children[0].value
: 'Video Player';
// handle props
const iframeProperties = createIfNeeded(iframeProps, node);
const iframeNewProperties = mergeProps({ ...defaultIframeProps, ...iframeProperties }, { 'data-video': videoType }, attrs);
// update node
data.hName = 'iframe';
data.hProperties = { src, title, ...iframeNewProperties };
data.hChildren = [];
}