generated at
lowlight
構文解析だけするhighlight.js
HAST形式でsyntaxを出力する
virtual DOMやSSR環境でsyntax highlightするときに便利

doc.deno.landのコードから見つけたtakker

API Reference
https://doc.deno.land/https://esm.sh/lowlight@2.8.1 からはうまく型定義を読み込めない
cdn.skypack.devも同様
構文解析結果の型定義はここを参照


全ての言語のsyntax highlightを有効にするときは https://esm.sh/lowlight@2.8.1/lib/all.js を使う
サンプル
test.js
const { render, html, useState, useEffect } = htmPreact; render(html`<${() => { const [json, setJson] = useState("Loading modules..."); useEffect(() => { const code = new URLSearchParams(location.search).get("code"); if (!code) { setJson("No source file specified."); return; } (async () => { const [ { lowlight }, { toHtml }, ] = await Promise.all([ import("https://esm.sh/lowlight@2.8.1"), import("https://esm.sh/hast-util-to-html@8.0.4"), ]); setJson("Loading Code..."); const res = await fetch(code); const tree = lowlight.highlightAuto(await res.text()); setJson(JSON.stringify(tree, null, 2)); //setJson(toHtml(tree)); })().catch((e)=>alert(JSON.stringify(e))); }, []); return html`<style>pre{white-space:pre-wrap}</style><pre><code>${json}</code></pre>`; }} />`, document.body);
DOMを改行で分割するコードを参考に作る
うまく分割できたっぽいtakker
test2.js
const { render, html, useState, useEffect } = htmPreact; /** 空文字のnodeなら`false`を返す */ const isEmptyNode = (node) => (node.type === "comment" || node.type === "text") && node.value === ""; /** 与えられたhastを1行ごとに分割する * * @param node 分割したいhast * @return 分割したhastを1行ずつ返す */ function* splitNode(node) { switch (node.type) { case "root": yield* splitNode({ type: "element", tagName: "div", children: node.children, }); return; case "doctype": yield node; return; case "comment": case "text": yield* node.value.split("\n").map( (value) => ({ type: node.type, value }) ); return; case "element": { if (node.children.length === 0) { yield node; return; } let prev; const { children, ...rest } = node; for (const child of children) { let counter = 0; for (const splitted of splitNode(child)) { if (prev && counter > 0) { yield prev; prev = undefined; } counter++; const isEmpty = isEmptyNode(splitted); if (prev) { if (isEmpty) continue; prev.children.push(splitted); continue; } prev = { ...rest, children: isEmpty ? [] : [splitted] }; } } if (prev) yield prev; return; } } } render(html`<${() => { const [json, setJson] = useState("Loading modules..."); useEffect(() => { const code = new URLSearchParams(location.search).get("code"); if (!code) { setJson("No source file specified."); return; } (async () => { const [ { lowlight }, { toHtml }, ] = await Promise.all([ import("https://esm.sh/lowlight@2.8.1"), import("https://esm.sh/hast-util-to-html@8.0.4"), ]); setJson("Loading Code..."); const res = await fetch(code); const tree = lowlight.highlightAuto(await res.text()); setJson(JSON.stringify([...splitNode(tree)], null, 2)); /*setJson(toHtml( { type: "root", children: [...splitNode(tree)] } ));*/ })().catch((e)=>alert(JSON.stringify(e))); }, []); return html`<style>pre{white-space:pre-wrap}</style><pre><code>${json}</code></pre>`; }} />`, document.body);


#2023-02-18 02:26:46
#2023-02-17 23:04:20