rework rehype plugin
This commit is contained in:
@ -1,50 +0,0 @@
|
||||
const nonAlphaNum = /[^A-Za-z0-9\-]/g;
|
||||
const space = /\s/g
|
||||
|
||||
export function makeSlug(text) {
|
||||
return text
|
||||
.toLowerCase()
|
||||
.replace(space, '-')
|
||||
.replace(nonAlphaNum, '')
|
||||
}
|
||||
|
||||
function apply(node, types, fn) {
|
||||
if (typeof types === 'string') {
|
||||
types = new Set([types]);
|
||||
}
|
||||
else if (!(types instanceof Set)) {
|
||||
types = new Set(types)
|
||||
console.log(types)
|
||||
}
|
||||
|
||||
if (types.has(node.type)) {
|
||||
fn(node);
|
||||
}
|
||||
if ('children' in node) {
|
||||
for (let child of node.children) {
|
||||
apply(child, types, fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getTextContent(node) {
|
||||
let segments = [];
|
||||
apply(node, 'text', textNode => {
|
||||
// skip all-whitespace strings
|
||||
if (textNode.value.match(/^\s+$/)) return;
|
||||
segments.push(textNode.value.trim());
|
||||
});
|
||||
|
||||
return segments.join(' ');
|
||||
}
|
||||
|
||||
export default function slug() {
|
||||
return (tree) => {
|
||||
apply(tree, 'element', e => {
|
||||
if (e.tagName.match(/h[1-6]/)) {
|
||||
let text = getTextContent(e);
|
||||
e.properties.id = makeSlug(text);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
8
src/lib/utils.js
Normal file
8
src/lib/utils.js
Normal file
@ -0,0 +1,8 @@
|
||||
const nonAlphaNum = /[^A-Za-z0-9\-]/g;
|
||||
const space = /\s+/g;
|
||||
export function makeSlug(text) {
|
||||
return text
|
||||
.toLowerCase()
|
||||
.replace(space, '-')
|
||||
.replace(nonAlphaNum, '');
|
||||
}
|
86
src/plugins/rehype.js
Normal file
86
src/plugins/rehype.js
Normal file
@ -0,0 +1,86 @@
|
||||
import { visit, CONTINUE, EXIT, SKIP, } from 'unist-util-visit';
|
||||
import { find } from 'unist-util-find';
|
||||
import { toText } from 'hast-util-to-text';
|
||||
import { makeSlug } from '../lib/utils.js';
|
||||
|
||||
|
||||
export function localPlugins() {
|
||||
let printed = false;
|
||||
|
||||
return (tree, vfile) => {
|
||||
const needsDropcap = vfile.data.fm.dropcap !== false
|
||||
let dropcapAdded = false;
|
||||
|
||||
let moduleScript;
|
||||
let imports = [];
|
||||
if (needsDropcap) {
|
||||
imports.push("import Dropcap from '$lib/Dropcap.svelte';");
|
||||
}
|
||||
|
||||
visit(tree, node => {
|
||||
// add slugs to headings
|
||||
if (isHeading(node)) {
|
||||
processHeading(node);
|
||||
return SKIP;
|
||||
}
|
||||
|
||||
// mdsvex adds a <script context="module"> so we just hijack that for our own purposes
|
||||
if (isModuleScript(node)) {
|
||||
moduleScript = node;
|
||||
}
|
||||
|
||||
// convert first letter/word of first paragraph to <Dropcap word="{whatever}">
|
||||
if (needsDropcap && !dropcapAdded && isParagraph(node)) {
|
||||
addDropcap(node);
|
||||
dropcapAdded = true;
|
||||
return SKIP;
|
||||
}
|
||||
});
|
||||
|
||||
// insert our imports at the top of the `<script context="module">` tag
|
||||
if (imports.length > 0) {
|
||||
const script = moduleScript.value;
|
||||
// split the script where the opening tag ends
|
||||
const i = script.indexOf('>');
|
||||
const openingTag = script.slice(0, i + 1);
|
||||
const remainder = script.slice(i + 1);
|
||||
|
||||
// mdvsex uses tabs so we will as well
|
||||
const importScript = imports.join('\n\t');
|
||||
|
||||
moduleScript.value = `${openingTag}\n\t${imports}${remainder}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function processHeading(node) {
|
||||
node.properties.id = makeSlug(toText(node));
|
||||
}
|
||||
|
||||
|
||||
function addDropcap(par) {
|
||||
let txtNode = find(par, {type: 'text'});
|
||||
const i = txtNode.value.search(/\s/);
|
||||
const firstWord = txtNode.value.slice(0, i);
|
||||
const remainder = txtNode.value.slice(i);
|
||||
|
||||
par.children.unshift({
|
||||
type: 'raw',
|
||||
value: `<Dropcap word="${firstWord}" />`,
|
||||
});
|
||||
txtNode.value = remainder;
|
||||
}
|
||||
|
||||
|
||||
function isHeading(node) {
|
||||
return node.type === 'element' && node.tagName.match(/h[1-6]/);
|
||||
}
|
||||
|
||||
function isModuleScript(node) {
|
||||
return node.type === 'raw' && node.value.match(/^<script context="module">/);
|
||||
}
|
||||
|
||||
function isParagraph(node) {
|
||||
return node.type === 'element' && node.tagName === 'p';
|
||||
}
|
Reference in New Issue
Block a user