zenn-markdown-html 0.4.2 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/highlight.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -961,6 +961,10 @@ import {
|
|
|
961
961
|
import { createJavaScriptRegexEngine } from "shiki/engine/javascript";
|
|
962
962
|
var highlighterPromise = null;
|
|
963
963
|
var SHIKI_THEME = "github-dark";
|
|
964
|
+
var SHIKI_THEME_BG_COLOR = "#24292e";
|
|
965
|
+
var CODE_BLOCK_BG_COLOR = "#151e2c";
|
|
966
|
+
var SHIKI_THEME_COMMENT_COLOR = "#6a737d";
|
|
967
|
+
var COMMENT_COLOR = "#a0aab5";
|
|
964
968
|
var isBrowser = typeof window !== "undefined";
|
|
965
969
|
async function getHighlighter() {
|
|
966
970
|
if (!highlighterPromise) {
|
|
@@ -1080,7 +1084,11 @@ async function highlight(text, langName, options) {
|
|
|
1080
1084
|
return highlighter.codeToHtml(text, {
|
|
1081
1085
|
lang,
|
|
1082
1086
|
theme: SHIKI_THEME,
|
|
1083
|
-
transformers
|
|
1087
|
+
transformers,
|
|
1088
|
+
colorReplacements: {
|
|
1089
|
+
[SHIKI_THEME_BG_COLOR]: CODE_BLOCK_BG_COLOR,
|
|
1090
|
+
[SHIKI_THEME_COMMENT_COLOR]: COMMENT_COLOR
|
|
1091
|
+
}
|
|
1084
1092
|
});
|
|
1085
1093
|
}
|
|
1086
1094
|
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/sanitizer.ts","../src/utils/markdown-it.ts","../src/utils/url-matcher.ts","../src/utils/embed-helper.ts","../src/embed.ts","../src/utils/md-imsize.ts","../src/utils/md-br.ts","../src/utils/md-katex.ts","../src/utils/md-custom-block.ts","../src/utils/md-link-attributes.ts","../src/utils/md-source-map.ts","../src/utils/md-linkify-to-card.ts","../src/utils/highlight.ts","../src/utils/md-renderer-fence.ts","../src/utils/md-image.ts","../src/utils/md-container.ts","../src/markdown-to-simple-html.ts"],"sourcesContent":["import markdownIt from 'markdown-it';\nimport { sanitize } from './sanitizer';\nimport { embedGenerators } from './embed';\nimport { MarkdownOptions } from './types';\n\n// plugins\nimport markdownItAnchor from 'markdown-it-anchor';\nimport { mdImsize } from './utils/md-imsize';\nimport { mdBr } from './utils/md-br';\nimport { mdKatex } from './utils/md-katex';\nimport { mdCustomBlock } from './utils/md-custom-block';\nimport { mdLinkAttributes } from './utils/md-link-attributes';\nimport { mdSourceMap } from './utils/md-source-map';\nimport { mdLinkifyToCard } from './utils/md-linkify-to-card';\nimport {\n mdRendererFence,\n applyHighlighting,\n CodeBlockInfo,\n} from './utils/md-renderer-fence';\nimport { mdImage } from './utils/md-image';\nimport {\n containerDetailsOptions,\n containerMessageOptions,\n} from './utils/md-container';\nimport mdContainer from 'markdown-it-container';\nimport mdFootnote from 'markdown-it-footnote';\nimport mdTaskLists from 'markdown-it-task-lists';\nimport mdInlineComments from 'markdown-it-inline-comments';\n\n/**\n * Markdown を HTML に変換する(非同期)\n *\n * Shiki によるシンタックスハイライトを使用。\n * 詳細なアーキテクチャについては md-renderer-fence.ts のコメントを参照。\n *\n * 処理フロー:\n * 1. [Phase 1] md.render() - Markdown を HTML に変換(コードブロックはプレースホルダーに)\n * 2. [Phase 2 & 3] applyHighlighting() - プレースホルダーをハイライト済み HTML に置換\n * 3. sanitize() - XSS 対策のためサニタイズ\n */\nconst markdownToHtml = async (\n text: string,\n options?: MarkdownOptions\n): Promise<string> => {\n if (!(text && text.length)) return '';\n\n const markdownOptions: MarkdownOptions = {\n ...options,\n customEmbed: {\n ...embedGenerators,\n ...options?.customEmbed,\n },\n };\n\n const md = markdownIt({ breaks: true, linkify: true });\n\n md.linkify.set({ fuzzyLink: false });\n md.linkify.set({ fuzzyEmail: false }); // refs: https://github.com/markdown-it/linkify-it\n\n // コードブロック情報を保存する配列\n // Phase 1 で mdRendererFence によって追加され、Phase 2 でハイライト処理に使用される\n const codeBlocks: CodeBlockInfo[] = [];\n\n md.use(mdBr)\n .use(mdKatex)\n .use(mdFootnote)\n .use(mdInlineComments)\n .use(mdImsize)\n .use(mdLinkAttributes)\n .use(mdCustomBlock, markdownOptions)\n .use(mdRendererFence, markdownOptions, codeBlocks)\n .use(mdLinkifyToCard, markdownOptions)\n .use(mdTaskLists, { enabled: true })\n .use(mdContainer, 'details', containerDetailsOptions)\n .use(mdContainer, 'message', containerMessageOptions)\n .use(markdownItAnchor, {\n level: [1, 2, 3, 4],\n permalink: markdownItAnchor.permalink.ariaHidden({\n placement: 'before',\n class: 'header-anchor-link',\n symbol: '',\n }),\n tabIndex: false,\n })\n .use(mdSourceMap)\n .use(mdImage);\n\n // custom footnote\n md.renderer.rules.footnote_block_open = () =>\n '<section class=\"footnotes\">\\n' +\n '<span class=\"footnotes-title\">脚注</span>\\n' +\n '<ol class=\"footnotes-list\">\\n';\n\n // docIdは複数のコメントが1ページに指定されたときに脚注のリンク先が重複しないように指定する\n // 1ページの中で重複しなければ問題ないため、ごく短いランダムな文字列とする\n // - https://github.com/zenn-dev/zenn-community/issues/356\n // - https://github.com/markdown-it/markdown-it-footnote/pull/8\n // Web Crypto API を使用(ブラウザ・Node.js 両対応)\n const randomBytes = new Uint8Array(2);\n globalThis.crypto.getRandomValues(randomBytes);\n const docId = Array.from(randomBytes, (b) =>\n b.toString(16).padStart(2, '0')\n ).join('');\n\n // ============================================================\n // Phase 1: Markdown → HTML 変換(同期)\n // ============================================================\n // markdown-it がコードブロックを検出すると mdRendererFence が呼ばれ、\n // コードブロック情報が codeBlocks 配列に保存され、\n // HTML にはプレースホルダー(<!--SHIKI_CODE_BLOCK_xxxxxxxx-->)が挿入される\n const rawHtml = md.render(text, { docId });\n\n // ============================================================\n // Phase 2 & 3: シンタックスハイライト適用(非同期)\n // ============================================================\n // - Phase 2: 全コードブロックを Shiki で並列ハイライト\n // - Phase 3: プレースホルダーをハイライト済み HTML に置換\n const highlightedHtml = await applyHighlighting(rawHtml, codeBlocks);\n\n // サニタイズして返す(XSS 対策)\n return sanitize(highlightedHtml);\n};\n\nexport default markdownToHtml;\nexport { markdownToSimpleHtml } from './markdown-to-simple-html';\n","import sanitizeHtml from 'sanitize-html';\n\nconst tags = [\n 'a',\n 'aside',\n 'blockquote',\n 'br',\n 'circle',\n 'code',\n 'details',\n 'div',\n 'em',\n 'embed-katex',\n 'eq',\n 'eqn',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'hr',\n 'iframe',\n 'img',\n 'input',\n 'li',\n 'ol',\n 'p',\n 'pre',\n 's',\n 'section',\n 'span',\n 'strong',\n 'summary',\n 'sup',\n 'table',\n 'tbody',\n 'td',\n 'text',\n 'th',\n 'thead',\n 'tr',\n 'ul',\n];\n\nconst attributes = {\n a: ['aria-hidden', 'class', 'href', 'id', 'rel', 'style', 'target', 'title'],\n aside: ['class'],\n blockquote: ['class', 'data-line'],\n br: ['style'],\n circle: ['cx', 'cy', 'fill', 'r'],\n code: ['class', 'data-line'],\n details: [],\n div: ['class'],\n em: [],\n 'embed-katex': ['display-mode'],\n eq: ['class'],\n eqn: [],\n h1: ['id', 'class', 'data-line'],\n h2: ['id', 'class', 'data-line'],\n h3: ['id', 'class', 'data-line'],\n h4: ['id', 'class', 'data-line'],\n h5: ['class', 'data-line'],\n h6: ['class', 'data-line'],\n hr: ['class', 'data-line'],\n iframe: [\n 'allow',\n 'allowfullscreen',\n 'allowtransparency',\n 'data-content',\n 'frameborder',\n 'id',\n 'loading',\n 'sandbox',\n 'scrolling',\n 'src',\n 'style',\n 'width',\n ],\n img: ['alt', 'class', 'height', 'loading', 'src', 'title', 'width'],\n input: ['checked', 'class', 'type'],\n li: ['class', 'id', 'data-line'],\n ol: ['class', 'start', 'data-line'],\n p: ['class', 'data-line'],\n pre: ['class', 'style'],\n s: [],\n section: ['class', 'data-line'],\n span: ['class', 'style', 'title'],\n strong: [],\n summary: [],\n sup: ['class'],\n table: ['class', 'data-line'],\n tbody: ['class', 'data-line'],\n td: ['style'],\n text: [\n 'dominant-baseline',\n 'fill',\n 'font-size',\n 'font-weight',\n 'text-anchor',\n 'x',\n 'y',\n ],\n th: ['style'],\n thead: ['class', 'data-line'],\n tr: ['class', 'data-line'],\n ul: ['class', 'data-line'],\n};\n\nexport const sanitize = (html: string) =>\n sanitizeHtml(html, {\n allowedTags: tags,\n allowedAttributes: attributes,\n disallowedTagsMode: 'discard',\n // from: default value https://github.com/apostrophecms/sanitize-html#default-options\n selfClosing: [\n 'img',\n 'br',\n 'hr',\n 'area',\n 'base',\n 'basefont',\n 'input',\n 'link',\n 'meta',\n ],\n });\n","import markdownit from 'markdown-it';\n\nexport const md = markdownit();\n","/** URL文字列か判定する */\nexport function isValidHttpUrl(str: string) {\n try {\n const url = new URL(str);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch (_) {\n return false;\n }\n}\n\nexport function isGithubUrl(url: string): boolean {\n return /^https:\\/\\/github\\.com\\/([a-zA-Z0-9](-?[a-zA-Z0-9]){0,38})\\/([a-zA-Z0-9](-?[a-zA-Z0-9._]){0,99})\\/blob\\/[^~\\s:?[*^/\\\\]{2,}\\/[\\w!\\-_~.*%()'\"/]+(?:#L\\d+(?:-L\\d+)?)?$/.test(\n url\n );\n}\n\n// Thanks: https://github.com/forem/forem/blob/d2d9984f28b1d0662f2a858b325a0e6b7a27a24c/app/liquid_tags/gist_tag.rb\nexport function isGistUrl(url: string): boolean {\n return /^https:\\/\\/gist\\.github\\.com\\/([a-zA-Z0-9](-?[a-zA-Z0-9]){0,38})\\/([a-zA-Z0-9]){1,32}(\\/[a-zA-Z0-9]+)?(\\?file=.+)?$/.test(\n url\n );\n}\n\nexport function isTweetUrl(url: string): boolean {\n return /^https:\\/\\/(twitter|x)\\.com\\/[a-zA-Z0-9_-]+\\/status\\/[a-zA-Z0-9?=&\\-_]+$/.test(\n url\n );\n}\n\nexport function isStackblitzUrl(url: string): boolean {\n return /^https:\\/\\/stackblitz\\.com\\/[a-zA-Z0-9\\-_/.@?&=%[\\]]+$/.test(url);\n}\n\nexport function isCodesandboxUrl(url: string): boolean {\n return /^https:\\/\\/codesandbox\\.io\\/embed\\/[a-zA-Z0-9\\-_/.@?&=%,+]+$/.test(\n url\n );\n}\n\nexport function isCodepenUrl(url: string): boolean {\n return /^https:\\/\\/codepen\\.io\\/[a-zA-Z0-9\\-_/@]+\\/pen\\/[a-zA-Z0-9\\-_/.@?&=%,]+$/.test(\n url\n );\n}\n\nexport function isJsfiddleUrl(url: string): boolean {\n return /^(http|https):\\/\\/jsfiddle\\.net\\/[a-zA-Z0-9_,/-]+$/.test(url);\n}\n\n// 例: https://www.docswell.com/s/ku-suke/LK7J5V-hello-docswell\n// 例: https://www.docswell.com/s/ku-suke/LK7J5V-hello-docswell#p13\n// 例: https://www.docswell.com/s/ku-suke/LK7J5V-hello-docswell/13\nconst docswellNormalUrlRegex =\n /^https:\\/\\/www\\.docswell\\.com\\/s\\/[a-zA-Z0-9_-]+\\/[a-zA-Z0-9_-]+(\\/\\d+)?(#p\\d+)?$/;\n\n// 例: https://www.docswell.com/slide/LK7J5V/embed\n// 例: https://www.docswell.com/slide/LK7J5V/embed#p12\nconst docswellEmbedUrlRegex =\n /^https:\\/\\/www\\.docswell\\.com\\/slide\\/[a-zA-Z0-9_-]+\\/embed(#p\\d+)?$/;\n\nexport function isDocswellUrl(url: string): boolean {\n return [docswellNormalUrlRegex, docswellEmbedUrlRegex].some((pattern) =>\n pattern.test(url)\n );\n}\n\nexport function isYoutubeUrl(url: string): boolean {\n return [\n /^https?:\\/\\/youtu\\.be\\/[\\w-]+(?:\\?[\\w=&-]+)?$/,\n /^https?:\\/\\/(?:www\\.)?youtube\\.com\\/watch\\?[\\w=&-]+$/,\n ].some((pattern) => pattern.test(url));\n}\n\n/** YoutubeのVideoIdの文字列の長さ */\nconst YOUTUBE_VIDEO_ID_LENGTH = 11;\n\n/**\n * youtube の URL から videoId と開始位置の秒数を取得する\n */\nexport function extractYoutubeVideoParameters(\n youtubeUrl: string\n): { videoId: string; start?: string } | undefined {\n if (!isYoutubeUrl(youtubeUrl)) return void 0;\n\n const url = new URL(youtubeUrl);\n const params = new URLSearchParams(url.search || '');\n\n // https://youtu.be/Hoge の \"HogeHoge\" の部分または、\n // https://www.youtube.com/watch?v=Hoge の \"Hoge\" の部分を値とする\n const videoId = params.get('v') || url.pathname.split('/')[1];\n\n // https://www.youtube.com/watch?v=Hoge&t=100s の \"100\" の部分を値とする\n const start = params.get('t')?.replace('s', '');\n\n if (videoId?.length !== YOUTUBE_VIDEO_ID_LENGTH) return void 0;\n\n return { videoId, start };\n}\n\nexport function extractDocswellEmbedUrl(url: string): string | null {\n // Embed用URLの場合、そのまま返す\n if (docswellEmbedUrlRegex.test(url)) {\n return url;\n }\n // Embed用URLでない場合 https://www.docswell.com/s/:username/{slideId}-hello-docswell のslideIdを抽出する\n const urlObj = new URL(url); // URLオブジェクトを作成\n const pathSegments = urlObj.pathname.split('/');\n // pathSegmentsの例: [\"\", \"s\", \"ku-suke\", \"LK7J5V-hello-docswell\", \"10\"]\n // slideIdは pathSegments[3] の先頭部分\n const slideIdPart = pathSegments.at(3);\n const slideId = slideIdPart?.split('-').at(0);\n\n if (!slideId) {\n return null;\n }\n\n let pageSuffix = '';\n // #pXX 形式のページ番号を優先 (例: #p18)\n if (urlObj.hash && /^#p\\d+$/.test(urlObj.hash)) {\n pageSuffix = urlObj.hash;\n } else {\n // /XX 形式のページ番号 (例: /28)\n // 通常URLの形式: /s/{username}/{slideId-slug}/{optional_page_num}\n // ページ番号がある場合、pathSegmentsの長さは5になる (e.g., [\"\", \"s\", \"username\", \"slide-slug\", \"page\"])\n if (pathSegments.length === 5) {\n const pageCandidate = pathSegments.at(4);\n if (pageCandidate && /^\\d+$/.test(pageCandidate)) {\n pageSuffix = `#p${pageCandidate}`;\n }\n }\n }\n\n return new URL(\n `/slide/${slideId}/embed${pageSuffix}`, // pageSuffixを結合\n 'https://www.docswell.com'\n ).toString();\n}\n\n/**\n * 参考: https://blueprintue.com/\n * 生成されるURLをもとに正規表現を定義した\n */\n\nexport function isBlueprintUEUrl(url: string): boolean {\n return /^https:\\/\\/blueprintue\\.com\\/render\\/[-\\w]+\\/?$/.test(url);\n}\n\n/**\n * 参考: https://www.figma.com/developers/embed\n */\nexport function isFigmaUrl(url: string): boolean {\n return /^https:\\/\\/([\\w.-]+\\.)?figma.com\\/(file|proto)\\/([0-9a-zA-Z]{22,128})(?:\\/[\\w-?=&%]+)?$/.test(\n url\n );\n}\n","import { MarkdownOptions } from '../types';\nimport { embedKeys, EmbedServerType, EmbedType } from '../embed';\nimport { isTweetUrl, isGithubUrl, isYoutubeUrl } from './url-matcher';\n\n/** 渡された文字列をサニタイズする */\nexport function sanitizeEmbedToken(str: string): string {\n return str.replace(/\"/g, '%22');\n}\n\n/** `EmbedType`か判定する */\nexport function isEmbedType(type: unknown): type is EmbedType {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return embedKeys.includes(type as any);\n}\n\n/** 渡された埋め込みURLまたはTokenを検証する */\nexport const validateEmbedToken = (\n str: string,\n type?: EmbedType\n): { isValid: boolean; message: string } => {\n /** 検証から除外する埋め込みの種別 */\n const ignoredEmbedType: EmbedType[] = ['card', 'github'];\n /** 埋め込みURLまたはTokenの最大文字数( excludeEmbedTypeは除く ) */\n const MAX_EMBED_TOKEN_LENGTH = 300;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (ignoredEmbedType.includes(type as any)) {\n return { isValid: true, message: '' };\n }\n\n if (str.length > MAX_EMBED_TOKEN_LENGTH) {\n return {\n isValid: false,\n message: `埋め込みURLは${MAX_EMBED_TOKEN_LENGTH}文字以内にする必要があります`,\n };\n }\n\n return { isValid: true, message: '' };\n};\n\n/** Embedサーバーを使った埋め込み要素の文字列を生成する */\nexport function generateEmbedServerIframe(\n type: EmbedServerType,\n src: string,\n embedOrigin: string\n): string {\n const origin = (() => {\n try {\n return new URL(embedOrigin).origin;\n } catch {\n return void 0;\n }\n })();\n\n // 埋め込みサーバーの origin が設定されてなければ空文字列を返す\n if (!origin) {\n console.warn('The embedOrigin option not set');\n return '';\n }\n\n // ユーザーからの入力値が引数として渡されたときのために念のためencodeする\n const encodedType = encodeURIComponent(type);\n const encodedSrc = encodeURIComponent(src);\n const id = `zenn-embedded__${Math.random().toString(16).slice(2)}`;\n const iframeSrc = `${origin}/${encodedType}#${id}`;\n\n return `<span class=\"embed-block zenn-embedded zenn-embedded-${encodedType}\"><iframe id=\"${id}\" src=\"${iframeSrc}\" data-content=\"${encodedSrc}\" frameborder=\"0\" scrolling=\"no\" loading=\"lazy\"></iframe></span>`;\n}\n\n/** 渡された`type`の埋め込み要素のHTML文字列を返す */\nexport const generateEmbedHTML = (\n type: EmbedType,\n str: string,\n options?: MarkdownOptions\n): string => {\n const { isValid, message } = validateEmbedToken(str, type);\n const generator = options?.customEmbed?.[type];\n\n return isValid ? generator?.(str, options) || str : message;\n};\n\n/** Linkifyな埋め込み要素のHTML生成する */\nexport const generateLinkifyEmbedHTML = (\n url: string,\n options?: MarkdownOptions\n): string => {\n const { isValid, message: msg } = validateEmbedToken(url);\n const generators = options?.customEmbed;\n\n if (!generators) return url;\n\n if (isTweetUrl(url))\n return isValid ? generators.tweet?.(url, options) || url : msg;\n\n if (isYoutubeUrl(url))\n return isValid ? generators.youtube?.(url, options) || url : msg;\n\n // GitHub は URL が長くなりやすいためバリデーション(`validateEmbedToken`)から外す\n if (isGithubUrl(url)) return generators.github?.(url, options) || url;\n\n return generators.card?.(url, options) || url;\n};\n","import type { MarkdownOptions } from './types';\n\nimport { md } from './utils/markdown-it';\nimport {\n sanitizeEmbedToken,\n generateEmbedServerIframe,\n} from './utils/embed-helper';\nimport {\n isGistUrl,\n isTweetUrl,\n isGithubUrl,\n isStackblitzUrl,\n isCodesandboxUrl,\n isCodepenUrl,\n isJsfiddleUrl,\n isBlueprintUEUrl,\n isFigmaUrl,\n isValidHttpUrl,\n isDocswellUrl,\n extractYoutubeVideoParameters,\n extractDocswellEmbedUrl,\n} from './utils/url-matcher';\n\n/* 埋め込み要素の種別 */\nexport type EmbedType =\n | 'youtube'\n | 'slideshare'\n | 'speakerdeck'\n | 'jsfiddle'\n | 'docswell'\n | 'codepen'\n | 'codesandbox'\n | 'stackblitz'\n | 'tweet'\n | 'blueprintue'\n | 'figma'\n | 'card'\n | 'gist'\n | 'github'\n | 'mermaid';\n\n/** embedサーバーで表示する埋め込み要素の種別 */\nexport type EmbedServerType = Extract<\n EmbedType,\n 'tweet' | 'card' | 'mermaid' | 'github' | 'gist'\n>;\n\n/** 埋め込み要素のHTMLを生成する関数 */\nexport type EmbedGenerator = (str: string, options?: MarkdownOptions) => string;\nexport type EmbedGeneratorList = Record<EmbedType, EmbedGenerator>;\n\n/** 埋め込み要素のHTMLを生成する関数をまとめたオブジェクト */\nexport const embedGenerators: Readonly<EmbedGeneratorList> = {\n youtube(str) {\n const params = extractYoutubeVideoParameters(str) || { videoId: str };\n\n if (!params.videoId.match(/^[a-zA-Z0-9_-]+$/)) {\n return 'YouTubeのvideoIDが不正です';\n }\n\n const escapedVideoId = md.utils.escapeHtml(params.videoId);\n const time = Math.min(Number(params.start || 0), 48 * 60 * 60); // 48時間以内\n const startQuery = time ? `?start=${time}` : '';\n\n return `<span class=\"embed-block embed-youtube\"><iframe src=\"https://www.youtube-nocookie.com/embed/${escapedVideoId}${startQuery}\" allow=\"accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen loading=\"lazy\"></iframe></span>`;\n },\n slideshare(key) {\n if (!key?.match(/^[a-zA-Z0-9_-]+$/)) {\n return 'Slide Shareのkeyが不正です';\n }\n return `<span class=\"embed-block embed-slideshare\"><iframe src=\"https://www.slideshare.net/slideshow/embed_code/key/${md.utils.escapeHtml(\n key\n )}\" scrolling=\"no\" allowfullscreen loading=\"lazy\"></iframe></span>`;\n },\n speakerdeck(str) {\n if (!str?.match(/^[a-zA-Z0-9_-]+(?:\\?slide=\\d+)?$/)) {\n return 'Speaker Deckのkeyが不正です';\n }\n\n const [key, slideParamStr] = str.split('?');\n const slideQuery = slideParamStr ? `?${slideParamStr}` : '';\n\n return `<span class=\"embed-block embed-speakerdeck\"><iframe src=\"https://speakerdeck.com/player/${md.utils.escapeHtml(\n key\n )}${md.utils.escapeHtml(slideQuery)}\" scrolling=\"no\" allowfullscreen allow=\"encrypted-media\" loading=\"lazy\"></iframe></span>`;\n },\n docswell(str) {\n const errorMessage = 'DocswellのスライドURLが不正です';\n if (!isDocswellUrl(str)) {\n return errorMessage;\n }\n const slideUrl = extractDocswellEmbedUrl(str);\n if (!slideUrl) {\n return errorMessage;\n }\n return `<span class=\"embed-block embed-docswell\"><iframe src=\"${slideUrl}\" allowfullscreen=\"true\" class=\"docswell-iframe\" width=\"100%\" style=\"border: 1px solid #ccc; display: block; margin: 0px auto; padding: 0px; aspect-ratio: 16/9\"></iframe></span>`;\n },\n jsfiddle(str) {\n if (!isJsfiddleUrl(str)) {\n return 'jsfiddleのURLが不正です';\n }\n // URLを~/embedded/とする\n // ※ すでにembeddedもしくはembedが含まれるURLが入力されている場合は、そのままURLを使用する。\n let url = str;\n if (!url.includes('embed')) {\n url = url.endsWith('/') ? `${url}embedded/` : `${url}/embedded/`;\n }\n return `<span class=\"embed-block embed-jsfiddle\"><iframe src=\"${sanitizeEmbedToken(\n url\n )}\" scrolling=\"no\" frameborder=\"no\" loading=\"lazy\"></iframe></span>`;\n },\n codepen(str) {\n if (!isCodepenUrl(str)) {\n return 'CodePenのURLが不正です';\n }\n const url = new URL(str.replace('/pen/', '/embed/'));\n url.searchParams.set('embed-version', '2');\n return `<span class=\"embed-block embed-codepen\"><iframe src=\"${sanitizeEmbedToken(\n url.toString()\n )}\" scrolling=\"no\" frameborder=\"no\" loading=\"lazy\"></iframe></span>`;\n },\n codesandbox(str) {\n if (!isCodesandboxUrl(str)) {\n return '「https://codesandbox.io/embed/」から始まる正しいURLを入力してください';\n }\n return `<span class=\"embed-block embed-codesandbox\"><iframe src=\"${sanitizeEmbedToken(\n str\n )}\" style=\"width:100%;height:500px;border:none;overflow:hidden;\" allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\" loading=\"lazy\" sandbox=\"allow-modals allow-forms allow-popups allow-scripts allow-same-origin\"></iframe></span>`;\n },\n stackblitz(str) {\n if (!isStackblitzUrl(str)) {\n return 'StackBlitzのembed用のURLを指定してください';\n }\n return `<span class=\"embed-block embed-stackblitz\"><iframe src=\"${sanitizeEmbedToken(\n str\n )}\" scrolling=\"no\" frameborder=\"no\" loading=\"lazy\"></iframe></span>`;\n },\n blueprintue(str) {\n if (!isBlueprintUEUrl(str))\n return '「https://blueprintue.com/render/」から始まる正しいURLを指定してください';\n return `<span class=\"embed-block embed-blueprintue\"><iframe src=\"${sanitizeEmbedToken(\n str\n )}\" width=\"100%\" style=\"aspect-ratio: 16/9\" scrolling=\"no\" frameborder=\"no\" loading=\"lazy\" allowfullscreen></iframe></span>`;\n },\n figma(str: string) {\n if (!isFigmaUrl(str))\n return 'ファイルまたはプロトタイプのFigma URLを指定してください';\n return `<span class=\"embed-block embed-figma\"><iframe src=\"https://www.figma.com/embed?embed_host=zenn&url=${sanitizeEmbedToken(\n str\n )}\" width=\"100%\" style=\"aspect-ratio: 16/9\" scrolling=\"no\" frameborder=\"no\" loading=\"lazy\" allowfullscreen></iframe></span>`;\n },\n\n // 以下は埋め込みサーバーが絡む要素。\n // embedOrigin が指定されていれば埋め込みサーバーを iframe で表示、\n // なければデフォルトの挙動(リンクの表示など)を行います。\n\n card(str, options) {\n if (!isValidHttpUrl(str)) return 'URLが不正です';\n if (options?.embedOrigin)\n return generateEmbedServerIframe('card', str, options.embedOrigin);\n\n return `<a href=\"${str}\" rel=\"noreferrer noopener nofollow\" target=\"_blank\">${str}</a>`;\n },\n tweet(str, options) {\n if (!isTweetUrl(str)) return 'ツイートページのURLを指定してください';\n if (options?.embedOrigin)\n return generateEmbedServerIframe('tweet', str, options.embedOrigin);\n\n return `<a href=\"${str}\" rel=\"noreferrer noopener nofollow\" target=\"_blank\">${str}</a>`;\n },\n gist(str, options) {\n /**\n * gistのURL は\n * - https://gist.github.com/foo/bar.json\n * - https://gist.github.com/foo/bar.json?file=example.js\n * のような形式\n */\n if (!isGistUrl(str)) return 'GitHub GistのページURLを指定してください';\n if (options?.embedOrigin)\n return generateEmbedServerIframe('gist', str, options.embedOrigin);\n\n return `<a href=\"${str}\" rel=\"noreferrer noopener nofollow\" target=\"_blank\">${str}</a>`;\n },\n github(str, options) {\n if (!isGithubUrl(str))\n return 'GitHub のファイルURLまたはパーマリンクを指定してください';\n if (options?.embedOrigin)\n return generateEmbedServerIframe('github', str, options.embedOrigin);\n\n return `<a href=\"${str}\" rel=\"noreferrer noopener nofollow\" target=\"_blank\">${str}</a>`;\n },\n mermaid(str, options) {\n if (options?.embedOrigin)\n return generateEmbedServerIframe('mermaid', str, options.embedOrigin);\n\n // エスケープ処理しておく\n const src = str.replace(/>/g, '>');\n\n // ブラウザじゃないと mermaid はレンダリングできないので、Node.jsで描画するときはコードブロックのまま出力する\n return `<div class=\"code-block-container\"><pre><code>${src}</code></pre></div>`;\n },\n} as const;\n\n/** 埋め込み要素の種別配列 */\nexport const embedKeys = Object.keys(embedGenerators) as EmbedType[];\n","/**\n * markdown-it plugin for size-specified image markups\n * Based on https://github.com/steelydylan/markdown-it-imsize\n * License: MIT\n */\n\nimport MarkdownIt from 'markdown-it';\nimport type StateInline from 'markdown-it/lib/rules_inline/state_inline.mjs';\nimport type Token from 'markdown-it/lib/token.mjs';\n\ntype ParseResult = {\n ok: boolean;\n pos: number;\n str: string;\n};\n\nfunction parseNextNumber(str: string, pos: number, max: number) {\n let code: number;\n const start = pos;\n const result = {\n ok: false,\n pos: pos,\n value: '',\n };\n\n code = str.charCodeAt(pos);\n\n while (\n (pos < max && code >= 0x30 /* 0 */ && code <= 0x39) /* 9 */ ||\n code === 0x25 /* % */\n ) {\n code = str.charCodeAt(++pos);\n }\n\n result.ok = true;\n result.pos = pos;\n result.value = str.slice(start, pos);\n\n return result;\n}\n\nfunction parseImageSize(str: string, pos: number, max: number) {\n let code = str.charCodeAt(pos);\n const result = {\n ok: false,\n pos: 0,\n width: '',\n height: '',\n };\n\n if (pos >= max) {\n return result;\n }\n\n if (code !== 0x3d /* = */) {\n return result;\n }\n\n pos++;\n\n // size must follow = without any white spaces as follows\n // (1) =300x200\n // (2) =300x\n // (3) =x200\n code = str.charCodeAt(pos);\n if (code !== 0x78 /* x */ && (code < 0x30 || code > 0x39) /* [0-9] */) {\n return result;\n }\n\n // parse width\n const resultW = parseNextNumber(str, pos, max);\n pos = resultW.pos;\n\n // next charactor must be 'x'\n code = str.charCodeAt(pos);\n if (code !== 0x78 /* x */) {\n return result;\n }\n\n pos++;\n\n // parse height\n const resultH = parseNextNumber(str, pos, max);\n pos = resultH.pos;\n\n result.width = resultW.value;\n result.height = resultH.value;\n result.pos = pos;\n result.ok = true;\n return result;\n}\n\nfunction image_with_size(md: MarkdownIt) {\n return function (state: StateInline, silent: boolean) {\n let attrs: [string, string][];\n let code: number;\n let label = '';\n let pos: number;\n let ref: { href: string; title: string };\n let res: ParseResult | ReturnType<typeof parseImageSize>;\n let title: string;\n let width = '';\n let height = '';\n let token: Token;\n let tokens: Token[];\n let start: number;\n let href = '';\n const oldPos = state.pos;\n const max = state.posMax;\n\n if (state.src.charCodeAt(state.pos) !== 0x21 /* ! */) {\n return false;\n }\n if (state.src.charCodeAt(state.pos + 1) !== 0x5b /* [ */) {\n return false;\n }\n\n const labelStart = state.pos + 2;\n const labelEnd = md.helpers.parseLinkLabel(state, state.pos + 1, false);\n\n // parser failed to find ']', so it's not a valid link\n if (labelEnd < 0) {\n return false;\n }\n\n pos = labelEnd + 1;\n if (pos < max && state.src.charCodeAt(pos) === 0x28 /* ( */) {\n //\n // Inline link\n //\n\n // [link]( <href> \"title\" )\n // ^^ skipping these spaces\n pos++;\n for (; pos < max; pos++) {\n code = state.src.charCodeAt(pos);\n if (code !== 0x20 && code !== 0x0a) {\n break;\n }\n }\n if (pos >= max) {\n return false;\n }\n\n // [link]( <href> \"title\" )\n // ^^^^^^ parsing link destination\n res = md.helpers.parseLinkDestination(state.src, pos, state.posMax);\n if (res.ok) {\n href = state.md.normalizeLink(res.str);\n if (state.md.validateLink(href)) {\n pos = res.pos;\n } else {\n href = '';\n }\n }\n\n // [link]( <href> \"title\" )\n // ^^ skipping these spaces\n start = pos;\n for (; pos < max; pos++) {\n code = state.src.charCodeAt(pos);\n if (code !== 0x20 && code !== 0x0a) {\n break;\n }\n }\n\n // [link]( <href> \"title\" )\n // ^^^^^^^ parsing link title\n res = md.helpers.parseLinkTitle(state.src, pos, state.posMax);\n if (pos < max && start !== pos && res.ok) {\n title = res.str;\n pos = res.pos;\n\n // [link]( <href> \"title\" )\n // ^^ skipping these spaces\n for (; pos < max; pos++) {\n code = state.src.charCodeAt(pos);\n if (code !== 0x20 && code !== 0x0a) {\n break;\n }\n }\n } else {\n title = '';\n }\n\n // [link]( <href> \"title\" =WxH )\n // ^^^^ parsing image size\n if (pos - 1 >= 0) {\n code = state.src.charCodeAt(pos - 1);\n\n // there must be at least one white spaces\n // between previous field and the size\n if (code === 0x20) {\n res = parseImageSize(state.src, pos, state.posMax);\n if (res.ok) {\n width = res.width;\n height = res.height;\n pos = res.pos;\n\n // [link]( <href> \"title\" =WxH )\n // ^^ skipping these spaces\n for (; pos < max; pos++) {\n code = state.src.charCodeAt(pos);\n if (code !== 0x20 && code !== 0x0a) {\n break;\n }\n }\n }\n }\n }\n\n if (pos >= max || state.src.charCodeAt(pos) !== 0x29 /* ) */) {\n state.pos = oldPos;\n return false;\n }\n pos++;\n } else {\n //\n // Link reference\n //\n if (typeof state.env.references === 'undefined') {\n return false;\n }\n\n // [foo] [bar]\n // ^^ optional whitespace (can include newlines)\n for (; pos < max; pos++) {\n code = state.src.charCodeAt(pos);\n if (code !== 0x20 && code !== 0x0a) {\n break;\n }\n }\n\n if (pos < max && state.src.charCodeAt(pos) === 0x5b /* [ */) {\n start = pos + 1;\n pos = md.helpers.parseLinkLabel(state, pos);\n if (pos >= 0) {\n label = state.src.slice(start, pos++);\n } else {\n pos = labelEnd + 1;\n }\n } else {\n pos = labelEnd + 1;\n }\n\n // covers label === '' and label === undefined\n // (collapsed reference link and shortcut reference link respectively)\n if (!label) {\n label = state.src.slice(labelStart, labelEnd);\n }\n\n ref = state.env.references[md.utils.normalizeReference(label)];\n if (!ref) {\n state.pos = oldPos;\n return false;\n }\n href = ref.href;\n title = ref.title;\n }\n\n //\n // We found the end of the link, and know for a fact it's a valid link;\n // so all that's left to do is to call tokenizer.\n //\n if (!silent) {\n state.pos = labelStart;\n state.posMax = labelEnd;\n\n const newState = new state.md.inline.State(\n state.src.slice(labelStart, labelEnd),\n state.md,\n state.env,\n (tokens = [])\n );\n newState.md.inline.tokenize(newState);\n token = state.push('image', 'img', 0);\n token.attrs = attrs = [\n ['src', href],\n ['alt', ''],\n ];\n token.children = tokens;\n if (title) {\n attrs.push(['title', title]);\n }\n\n if (width !== '') {\n attrs.push(['width', width]);\n }\n\n if (height !== '') {\n attrs.push(['height', height]);\n }\n }\n\n state.pos = pos;\n state.posMax = max;\n return true;\n };\n}\n\nexport function mdImsize(md: MarkdownIt) {\n md.inline.ruler.before('emphasis', 'image', image_with_size(md));\n}\n","/**\n * forked from https://github.com/iktakahiro/markdown-it-br\n */\nimport MarkdownIt from 'markdown-it';\n\n/**\n * Return case-sensitive matched br tag\n * @param {any} state MarkdownIt state\n * @param {number} start start position at br tag\n * @returns {string | null} br tag (<br> or <br/> or <br />)\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction matchBR(state: any, start: number): string | null {\n const match = state.src.slice(start, start + 6).match(/^<br\\s?\\/?>/);\n if (match) {\n return match[0];\n }\n return null;\n}\n\nexport function mdBr(md: MarkdownIt): void {\n // Tokenize\n md.inline.ruler.before(\n 'emphasis',\n 'br',\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n function tokenize(state: any, silent): boolean {\n const max = state.posMax;\n const start = state.pos;\n\n // don't run any pairs in validation mode\n if (silent) {\n return false;\n }\n\n const br = matchBR(state, start);\n if (br === null || start + br.length > max) {\n return false;\n }\n state.scanDelims(state.pos, true);\n const token = state.push('text', '', 0);\n token.content = '<br>';\n state.delimiters.push({\n marker: token.content,\n jump: 0,\n token: state.tokens.length - 1,\n level: state.level,\n end: -1,\n open: true,\n close: true,\n });\n\n // length is: <br> -> 4, <br/> -> 5, <br /> -> 6\n state.pos += br.length;\n\n return true;\n }\n );\n\n // Walk through delimiter list and replace text tokens with tags\n md.inline.ruler2.before('emphasis', 'br', function postProcess(state) {\n let i;\n let delim;\n let token;\n const delimiters = state.delimiters;\n const max = state.delimiters.length;\n\n for (i = 0; i < max; i++) {\n delim = delimiters[i];\n const marker = delim.marker as number | '<br>';\n\n if (marker === '<br>') {\n token = state.tokens[delim.token];\n token.type = 'br_openclose';\n token.tag = 'br';\n token.nesting = 1;\n token.markup = '<br>';\n token.content = '';\n }\n }\n\n return true;\n });\n}\n","/**\n * forked from https://github.com/goessner/markdown-it-mdKatex\n */\n\nimport MarkdownIt from 'markdown-it';\n\ntype PreHandler = (str: string, begin: number) => boolean;\ntype PostHandler = (str: string, begin: number) => boolean;\n\nconst katexClassName = 'zenn-katex';\n\nconst preHandler: PreHandler = function (str, beg) {\n const prv = beg > 0 ? str[beg - 1].charCodeAt(0) : false;\n return (\n !prv ||\n (prv !== 0x5c && // no backslash,\n (prv < 0x30 || prv > 0x39))\n ); // no decimal digit .. before opening '$'\n};\n\nconst postHandler: PostHandler = function (str, end) {\n const nxt = str[end + 1] && str[end + 1].charCodeAt(0);\n return !nxt || nxt < 0x30 || nxt > 0x39; // no decimal digit .. after closing '$'\n};\n\ntype HandlingRule = {\n name: string;\n rex: RegExp;\n tmpl: string;\n tag: string;\n pre?: PreHandler;\n post?: PostHandler;\n};\n\nconst inlineRules: HandlingRule[] = [\n {\n name: 'math_inline_double',\n // maybe unused.\n rex: /\\${2}((?:\\S)|(?:\\S(?!.*\\]\\(http).*?\\S))\\${2}/gy,\n tmpl: `<section class=\"${katexClassName}\"><embed-katex display-mode=\"1\"><eqn>$1</eqn></embed-katex></section>`,\n tag: '$$',\n pre: preHandler,\n post: postHandler,\n },\n {\n name: 'math_inline',\n // fixed so that the expression [$something](https://something.com/$example) is skipped.\n // (?:\\S(?![^$]*\\]\\(http.*) means something like \"](https://hoge.com/hoge)\"\n rex: /\\$((?:\\S)|(?:\\S(?![^$]*\\]\\(http.*).*?\\S))\\$/gy,\n tmpl: `<embed-katex><eq class=\"${katexClassName}\">$1</eq></embed-katex>`,\n tag: '$',\n pre: preHandler,\n post: postHandler,\n },\n];\n\nconst blockRules: HandlingRule[] = [\n {\n name: 'math_block_eqno',\n rex: /\\${2}([^$]+?)\\${2}\\s*?\\(([^)\\s]+?)\\)/gmy,\n tmpl: `<section class=\"${katexClassName} eqno code-line\" $3><eqn><embed-katex display-mode=\"1\">$1</embed-katex></eqn><span>($2)</span></section>`,\n tag: '$$',\n },\n {\n name: 'math_block',\n rex: /\\${2}([^$]+?)\\${2}/gmy,\n tmpl: `<section class=\"${katexClassName} code-line\" $3><eqn><embed-katex display-mode=\"1\">$1</embed-katex></eqn></section>`,\n tag: '$$',\n },\n];\n\nexport function mdKatex(md: MarkdownIt) {\n for (const rule of inlineRules) {\n md.inline.ruler.before('escape', rule.name, function (state, silent) {\n const pos = state.pos;\n const str = state.src;\n const pre =\n str.startsWith(rule.tag, (rule.rex.lastIndex = pos)) &&\n (!rule.pre || rule.pre(str, pos)); // valid pre-condition ...\n const match = pre && rule.rex.exec(str);\n const res =\n !!match &&\n pos < rule.rex.lastIndex &&\n (!rule.post || rule.post(str, rule.rex.lastIndex - 1));\n\n if (res) {\n if (!silent && match) {\n const token = state.push(rule.name, 'math', 0);\n token.content = match[1];\n token.markup = rule.tag;\n }\n state.pos = rule.rex.lastIndex;\n }\n return res;\n }); // ! important\n md.renderer.rules[rule.name] = (tokens, idx) =>\n rule.tmpl.replace(/\\$1/, md.utils.escapeHtml(tokens[idx].content));\n }\n\n for (const rule of blockRules) {\n md.block.ruler.before(\n 'fence',\n rule.name,\n function block(state, begLine, endLine, silent) {\n const pos = state.bMarks[begLine] + state.tShift[begLine];\n const str = state.src;\n const pre =\n str.startsWith(rule.tag, (rule.rex.lastIndex = pos)) &&\n (!rule.pre || rule.pre(str, pos)); // valid pre-condition ....\n const match = pre && rule.rex.exec(str);\n const res =\n !!match &&\n pos < rule.rex.lastIndex &&\n (!rule.post || rule.post(str, rule.rex.lastIndex - 1));\n\n if (res && !silent && match) {\n // match and valid post-condition ...\n const endpos = rule.rex.lastIndex - 1;\n let curline;\n\n for (curline = begLine; curline < endLine; curline++)\n if (\n endpos >= state.bMarks[curline] + state.tShift[curline] &&\n endpos <= state.eMarks[curline]\n )\n // line for end of block math found ...\n break;\n\n // \"this will prevent lazy continuations from ever going past our end marker\"\n // s. https://github.com/markdown-it/markdown-it-container/blob/master/index.js\n const lineMax = state.lineMax;\n const oldParentType = state.parentType;\n state.lineMax = curline;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n state.parentType = 'math' as any;\n\n if (oldParentType === 'blockquote') {\n // remove all leading '>' inside multiline formula\n match[1] = match[1].replace(/(\\n*?^(?:\\s*>)+)/gm, '');\n }\n // begin token\n let token = state.push(rule.name, 'math', 1); // 'math_block'\n token.block = true;\n token.markup = rule.tag;\n token.content = match[1];\n token.info = match[match.length - 1]; // eq.no\n token.map = [begLine, curline];\n // end token\n token = state.push(rule.name + '_end', 'math', -1);\n token.block = true;\n token.markup = rule.tag;\n\n state.parentType = oldParentType;\n state.lineMax = lineMax;\n state.line = curline + 1;\n }\n return res;\n }\n ); // ! important for ```math delimiters\n\n md.renderer.rules[rule.name] = (tokens, idx) =>\n rule.tmpl\n .replace(/\\$2/, md.utils.escapeHtml(tokens[idx].info)) // equation number .. ?\n .replace(/\\$1/, md.utils.escapeHtml(tokens[idx].content))\n .replace(/\\$3/, 'data-line=\"' + tokens[idx].attrGet('data-line') + '\"');\n }\n}\n","import MarkdownIt from 'markdown-it';\nimport { MarkdownOptions } from '../types';\nimport { generateEmbedHTML, isEmbedType } from './embed-helper';\n\n// Forked from: https://github.com/posva/markdown-it-custom-block\nexport function mdCustomBlock(md: MarkdownIt, options?: MarkdownOptions) {\n md.renderer.rules.custom = function tokenizeBlock(tokens, idx) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const { tag, arg }: any = tokens[idx].info;\n\n if (!isEmbedType(tag)) return '';\n if (typeof arg !== 'string') return '';\n\n try {\n return generateEmbedHTML(tag, arg, options || {}) + '\\n';\n } catch (_e) {\n return '';\n }\n };\n\n md.block.ruler.before(\n 'fence',\n 'custom',\n function customEmbed(state, startLine, endLine, silent) {\n const startPos = state.bMarks[startLine] + state.tShift[startLine];\n const maxPos = state.eMarks[startLine];\n const block = state.src.slice(startPos, maxPos);\n const pointer = { line: startLine, pos: startPos };\n\n // Note: skip prev line break check\n // if (startLine !== 0) {\n // let prevLineStartPos =\n // state.bMarks[startLine - 1] + state.tShift[startLine - 1];\n // let prevLineMaxPos = state.eMarks[startLine - 1];\n // if (prevLineMaxPos > prevLineStartPos) return false;\n // }\n\n // Check if it's @[tag](arg)\n if (\n state.src.charCodeAt(pointer.pos) !== 0x40 /* @ */ ||\n state.src.charCodeAt(pointer.pos + 1) !== 0x5b /* [ */\n ) {\n return false;\n }\n\n const embedRE = /@\\[([\\w-]+)\\]\\((.+)\\)/im;\n const match = embedRE.exec(block);\n\n if (!match || match.length < 3) {\n return false;\n }\n\n const [all, tag, arg] = match;\n\n pointer.pos += all.length;\n\n // Note: skip nextline break check\n // if (endLine !== pointer.line + 1) {\n // let nextLineStartPos =\n // state.bMarks[pointer.line + 1] + state.tShift[pointer.line + 1];\n // let nextLineMaxPos = state.eMarks[pointer.line + 1];\n // if (nextLineMaxPos > nextLineStartPos) return false;\n // }\n\n if (pointer.line >= endLine) return false;\n if (!silent) {\n const token = state.push('custom', 'div', 0);\n token.markup = state.src.slice(startPos, pointer.pos);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n token.info = { arg, tag } as any;\n token.block = true;\n token.map = [startLine, pointer.line + 1];\n state.line = pointer.line + 1;\n }\n\n return true;\n },\n { alt: ['paragraph', 'reference', 'blockquote', 'list'] }\n );\n}\n","import MarkdownIt from 'markdown-it';\nimport markdownItLinkAttributes from 'markdown-it-link-attributes';\n\nexport function mdLinkAttributes(md: MarkdownIt) {\n // <a>タグの属性を設定する\n // Ref: https://github.com/crookedneighbor/markdown-it-link-attributes\n md.use(markdownItLinkAttributes, [\n // 内部リンク\n {\n matcher(href: string) {\n return href.match(\n /^(?:https:\\/\\/zenn\\.dev$)|(?:https:\\/\\/zenn\\.dev\\/.*$)/\n );\n },\n attrs: {\n target: '_blank',\n },\n },\n // 外部リンク\n {\n matcher(href: string) {\n return href.match(/^https?:\\/\\//);\n },\n attrs: {\n target: '_blank',\n rel: 'nofollow noopener noreferrer',\n },\n },\n ]);\n}\n","import MarkdownIt from 'markdown-it';\n\n/**\n * Adds begin line index to the output via the 'data-line' data attribute.\n *\n * Ref: https://github.com/microsoft/vscode/blob/84f63bf4e54c60e40865c8c4d8002893a337fe61/extensions/markdown-language-features/src/markdownEngine.ts#L17-L40\n */\nexport function mdSourceMap(md: MarkdownIt): void {\n // Set the attribute on every possible token.\n md.core.ruler.push('source_map_data_attribute', (state): void => {\n for (const token of state.tokens) {\n if (token.map && token.type !== 'inline') {\n token.attrSet('data-line', String(token.map[0]));\n token.attrJoin('class', 'code-line');\n }\n }\n });\n}\n","import MarkdownIt from 'markdown-it';\nimport Token from 'markdown-it/lib/token.mjs';\nimport { MarkdownOptions } from '../types';\nimport { generateLinkifyEmbedHTML } from './embed-helper';\n\nfunction convertAutolinkToEmbed(\n inlineChildTokens: Token[],\n options: MarkdownOptions\n): Token[] {\n const newTokens: Token[] = [];\n\n inlineChildTokens.forEach((token, i) => {\n // 埋め込み対象となるlink_open かつ linkify以外はそのまま出力結果に含める\n if (!(token.type === 'link_open' && token.markup === 'linkify')) {\n newTokens.push(token); // 変換は行わずに出力結果に含める\n return;\n }\n\n const linkOpenToken = token;\n\n // tokenがlinkifyの場合は必要に応じて、カードを生成\n const url = linkOpenToken.attrGet('href');\n if (!url) {\n newTokens.push(token); // 変換は行わずに出力結果に含める\n return;\n }\n\n const isStartOfLine = i === 0;\n const isEndOfLine = i + 2 === inlineChildTokens.length - 1; // i + 2 = link_closeのこと => link_closeが最後のtokenか\n\n const prevToken = isStartOfLine ? null : inlineChildTokens[i - 1]; // e.g. [✋, link_open, text, link_close]\n const nextToken = isEndOfLine ? null : inlineChildTokens[i + 3]; // e.g. [text, link_open, text, link_close, ✋]\n\n const isPrevBr = prevToken?.tag === 'br';\n const isNextBr = nextToken?.tag === 'br';\n\n // 以下の2つをどちらも満たした場合にリンク化\n // 1. パラグラフ先頭 もしくは リンクの前が br\n // 2. パラグラフの末尾 もしくは リンクの後が br\n\n const shouldConvertToCard =\n (isStartOfLine || isPrevBr) && (isEndOfLine || isNextBr);\n\n if (!shouldConvertToCard) {\n newTokens.push(token); // 変換は行わずに出力結果に含める\n return;\n }\n\n // 埋め込み用のHTMLを生成\n const embedToken = new Token('html_inline', '', 0);\n\n // 埋め込み要素のHTML生成\n embedToken.content = generateLinkifyEmbedHTML(url, options);\n\n // a要素自体はカードにより不要になるため非表示に\n linkOpenToken.attrJoin('style', 'display: none');\n\n // カードとリンクのトークンを出力結果のtokenに追加\n newTokens.push(embedToken, linkOpenToken);\n\n // 前後のbrタグはスペースを広げすぎてしまうため非表示にしておく\n if (nextToken && isNextBr) {\n nextToken.type = 'html_inline';\n nextToken.content = '<br style=\"display: none\">\\n';\n }\n if (prevToken && isPrevBr) {\n prevToken.type = 'html_inline';\n prevToken.content = '<br style=\"display: none\">\\n';\n }\n });\n return newTokens;\n}\n\nexport function mdLinkifyToCard(md: MarkdownIt, options?: MarkdownOptions) {\n md.core.ruler.after('replacements', 'link-to-card', function ({ tokens }) {\n // 埋め込みを許可するネストレベル\n let allowLevel = 0;\n\n // 本文内のすべてのtokenをチェック\n tokens.forEach((token, i) => {\n if (token.type === 'container_details_open') {\n allowLevel++;\n return;\n }\n if (token.type === 'container_details_close' && allowLevel > 0) {\n allowLevel--;\n return;\n }\n\n // autolinkはinline内のchildrenにのみ存在\n if (token.type !== 'inline') return;\n\n // childrenが存在しない場合は変換しない\n const children = token.children;\n if (!children) return;\n\n // childrenにautolinkが存在する場合のみ変換\n const hasAnyAutolink = children?.some(\n (child) => child.markup === 'linkify'\n );\n if (!hasAnyAutolink) return;\n\n // 親がコンテンツ直下のp要素の場合のみ変換\n const parentToken = tokens[i - 1];\n const isParentRootParagraph =\n parentToken &&\n parentToken.type === 'paragraph_open' &&\n parentToken.level === allowLevel;\n if (!isParentRootParagraph) return;\n\n token.children = convertAutolinkToEmbed(children, options || {});\n });\n\n return true;\n });\n}\n","/**\n * Shiki によるシンタックスハイライト処理\n *\n * このモジュールは Phase 2(applyHighlighting)から呼び出され、\n * 個々のコードブロックをハイライトする役割を持つ。\n *\n * ## 特徴\n *\n * - シングルトン: ハイライターインスタンスは1つだけ作成され再利用される\n * - 遅延ロード: 言語定義は初回使用時にのみロードされる\n * - diff サポート: ベース言語のハイライト + diff 背景色の両方を適用\n * - transformers: Shiki の transformers API で AST レベルの変換を実行\n *\n * ## 関連ファイル\n *\n * - `md-renderer-fence.ts`: Phase 1(収集)と Phase 3(置換)\n * - `index.ts`: 全体の統合\n */\n\nimport {\n createHighlighter,\n Highlighter,\n bundledLanguages,\n BundledLanguage,\n ShikiTransformer,\n} from 'shiki';\nimport { createJavaScriptRegexEngine } from 'shiki/engine/javascript';\n\n/**\n * Shiki ハイライターの初期化 Promise をキャッシュ\n *\n * 注: インスタンスではなく Promise をキャッシュすることで、\n * Promise.all による並列処理時の競合状態を防ぐ。\n *\n * 問題のあるパターン:\n * let instance = null;\n * if (instance) return instance;\n * instance = await createHighlighter(); // ← await 中に他の呼び出しが来る\n *\n * 正しいパターン:\n * let promise = null;\n * if (!promise) promise = createHighlighter(); // ← await しない\n * return promise; // ← 同じ Promise を返す\n */\nlet highlighterPromise: Promise<Highlighter> | null = null;\n\nconst SHIKI_THEME = 'github-dark';\n\n/** ブラウザ環境かどうかを判定 */\n// @ts-expect-error: window is not defined in Node.js types\nconst isBrowser = typeof window !== 'undefined';\n\n/**\n * Shiki ハイライターを初期化する\n * 最初は最低限のセットで初期化し、必要に応じて言語をロードする\n *\n * ブラウザ環境では JavaScript エンジンを使用(WASM 不要)\n * Node.js 環境では Oniguruma エンジンを使用(デフォルト)\n */\nexport async function getHighlighter(): Promise<Highlighter> {\n if (!highlighterPromise) {\n // Promise をキャッシュ(await しない)\n highlighterPromise = createHighlighter({\n themes: [SHIKI_THEME],\n langs: [],\n // ブラウザ環境では JavaScript エンジンを使用\n // forgiving: true で変換できないパターンもベストエフォートで処理\n ...(isBrowser && {\n engine: createJavaScriptRegexEngine({ forgiving: true }),\n }),\n });\n }\n\n return highlighterPromise;\n}\n\n/**\n * 言語がサポートされているかチェックし、必要に応じてロードする\n */\nasync function ensureLanguageLoaded(\n highlighter: Highlighter,\n langName: string\n): Promise<boolean> {\n // 既にロード済みかチェック\n const loadedLangs = highlighter.getLoadedLanguages();\n if (loadedLangs.includes(langName)) {\n return true;\n }\n\n // bundledLanguages に含まれているかチェック\n if (langName in bundledLanguages) {\n await highlighter.loadLanguage(langName as BundledLanguage);\n return true;\n }\n\n return false;\n}\n\n/**\n * ハイライトオプション\n */\nexport interface HighlightOptions {\n /** diff モードかどうか */\n hasDiff: boolean;\n /** Markdown ソースの行番号(ソースマップ用) */\n line?: number;\n}\n\n/**\n * diff プレフィックスの定義\n * Prism.js の diff-highlight プラグインと互換性を持たせる\n */\nconst DIFF_PREFIXES = {\n // 削除行\n '-': 'remove', // deleted-sign\n '<': 'remove', // deleted-arrow\n // 挿入行\n '+': 'add', // inserted-sign\n '>': 'add', // inserted-arrow\n} as const;\n\n/** コンテキスト行(変更なし)のプレフィックス */\nconst DIFF_CONTEXT_PREFIX = ' ';\n\n/**\n * diff 行スタイルを適用する transformer を作成\n * 行頭のプレフィックス (+, -, <, >, スペース) を検出して処理\n * - +, -, <, >: 挿入/削除のクラスを追加し、プレフィックスをラップ\n * - スペース: プレフィックスのみラップ(コンテキスト行)\n */\nfunction createDiffTransformer(): ShikiTransformer {\n return {\n line(node, lineNumber) {\n // ソースコードの該当行を取得\n const lines = this.source.split('\\n');\n const lineText = lines[lineNumber - 1] ?? '';\n const firstChar = lineText.charAt(0);\n\n if (firstChar in DIFF_PREFIXES) {\n // 追加/削除行\n this.addClassToHast(node, 'diff');\n this.addClassToHast(\n node,\n DIFF_PREFIXES[firstChar as keyof typeof DIFF_PREFIXES]\n );\n wrapDiffPrefix(node, firstChar);\n } else if (firstChar === DIFF_CONTEXT_PREFIX) {\n // コンテキスト行(先頭スペース)\n wrapDiffPrefix(node, firstChar);\n }\n },\n };\n}\n\n/**\n * 行の最初の文字(diff プレフィックス)を別の span 要素にラップする\n * これにより CSS で user-select: none を適用可能になる\n */\nfunction wrapDiffPrefix(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n lineNode: any,\n prefix: string\n): void {\n const line = lineNode;\n\n if (!line.children || line.children.length === 0) return;\n\n const firstChild = line.children[0];\n\n // 最初の子要素がテキストノードの場合(実際には発生しないはずだが念の為)\n if (firstChild.type === 'text' && firstChild.value.startsWith(prefix)) {\n // プレフィックスを分離\n const prefixSpan = {\n type: 'element',\n tagName: 'span',\n properties: { class: 'diff-prefix' },\n children: [{ type: 'text', value: prefix }],\n };\n firstChild.value = firstChild.value.slice(1);\n\n // 空になった場合は削除\n if (firstChild.value === '') {\n line.children.shift();\n }\n\n // プレフィックス span を先頭に挿入\n line.children.unshift(prefixSpan);\n return;\n }\n\n // 最初の子要素が element(span など)の場合\n if (\n firstChild.type === 'element' &&\n firstChild.children &&\n firstChild.children.length > 0\n ) {\n const innerFirst = firstChild.children[0];\n if (innerFirst.type === 'text' && innerFirst.value.startsWith(prefix)) {\n // プレフィックスを分離\n const prefixSpan = {\n type: 'element',\n tagName: 'span',\n properties: { class: 'diff-prefix' },\n children: [{ type: 'text', value: prefix }],\n };\n innerFirst.value = innerFirst.value.slice(1);\n\n // 空になった場合は削除\n if (innerFirst.value === '') {\n firstChild.children.shift();\n }\n\n // プレフィックス span を先頭に挿入\n line.children.unshift(prefixSpan);\n }\n }\n}\n\n/**\n * code タグにクラスと属性を追加する transformer を作成\n */\nfunction createCodeTransformer(options: { line?: number }): ShikiTransformer {\n const { line } = options;\n return {\n code(node) {\n this.addClassToHast(node, 'code-line');\n if (line !== undefined) {\n node.properties['data-line'] = line;\n }\n },\n };\n}\n\n/**\n * [Phase 2 の実処理] コードをハイライトする\n *\n * applyHighlighting() から各コードブロックに対して呼び出される。\n * 言語が未ロードの場合は自動的にロードする(遅延ロード)。\n * Shiki の transformers API を使用して AST レベルで変換を行う。\n *\n * @param text - ハイライト対象のコード文字列\n * @param langName - 言語名(例: \"javascript\", \"python\")\n * @param options - ハイライトオプション\n * @returns ハイライト済み HTML(常に <pre><code> 構造)\n */\nexport async function highlight(\n text: string,\n langName: string,\n options: HighlightOptions\n): Promise<string> {\n const { hasDiff, line } = options;\n const highlighter = await getHighlighter();\n\n // 言語がサポートされているか確認し、必要に応じてロード\n const isSupported = langName\n ? await ensureLanguageLoaded(highlighter, langName)\n : false;\n\n // サポートされていない言語は text(プレーンテキスト)として処理\n // ref: https://shiki.style/languages#plain-text\n const lang = isSupported ? langName : 'text';\n if (!isSupported) {\n await ensureLanguageLoaded(highlighter, 'text');\n }\n\n // transformers を構築\n const transformers: ShikiTransformer[] = [createCodeTransformer({ line })];\n if (hasDiff) {\n transformers.push(createDiffTransformer());\n }\n\n return highlighter.codeToHtml(text, {\n lang,\n theme: SHIKI_THEME,\n transformers,\n });\n}\n","/**\n * コードブロックのレンダリングとシンタックスハイライト\n *\n * ## 非同期処理アーキテクチャの概要\n *\n * Shiki(シンタックスハイライター)は非同期APIを持つが、\n * markdown-it のレンダラーは同期的に文字列を返す必要がある。\n * この制約を解決するため、プレースホルダー方式を採用している。\n *\n * ### 処理フロー(3フェーズ)\n *\n * ```\n * [Phase 1: 収集] markdown-it レンダリング(同期)\n * ↓\n * コードブロックを検出するたびに:\n * 1. コードブロック情報を配列に保存\n * 2. プレースホルダー(HTMLコメント)を返す\n * ↓\n * 出力: プレースホルダー付きHTML + コードブロック情報配列\n *\n * [Phase 2: ハイライト] Shiki によるハイライト(非同期・並列)\n * ↓\n * Promise.all で全コードブロックを並列処理\n * ↓\n * 出力: ハイライト済みHTML配列\n *\n * [Phase 3: 置換] プレースホルダーを置換(同期)\n * ↓\n * プレースホルダーをハイライト済みHTMLに置換\n * ↓\n * 出力: 最終HTML\n * ```\n *\n * ### この方式のメリット\n *\n * 1. 同期/非同期の不一致を解決: markdown-it の同期的なプラグインシステムを維持\n * 2. 並列処理: 複数のコードブロックを Promise.all で同時にハイライト\n * 3. 遅延ロード: Shiki の言語定義を必要に応じてロード(メモリ効率)\n *\n * ### 関連ファイル\n *\n * - `index.ts`: markdownToHtml() - 3フェーズを統合\n * - `highlight.ts`: highlight() - Shiki によるハイライト処理\n * - `md-renderer-fence.ts`: このファイル - Phase 1 と 3 を担当\n */\n\nimport MarkdownIt from 'markdown-it';\nimport { md } from './markdown-it';\nimport { MarkdownOptions } from '../types';\nimport { highlight } from './highlight';\n\n/**\n * コードブロック情報を保存するインターフェース\n * Phase 1 で収集し、Phase 2 でハイライト処理に使用\n */\nexport interface CodeBlockInfo {\n content: string;\n langName: string;\n hasDiff: boolean;\n fileName?: string;\n line?: number;\n placeholder: string;\n}\n\n// プレースホルダーのプレフィックス\nconst PLACEHOLDER_PREFIX = '<!--SHIKI_CODE_BLOCK_';\nconst PLACEHOLDER_SUFFIX = '-->';\n\n/**\n * ランダムな8文字の文字列を生成する\n */\nfunction generateRandomId(): string {\n return Math.random().toString(36).slice(2, 10);\n}\n\n/**\n * プレースホルダーを生成する\n * ユーザーが本文中に同じ文字列を書いても衝突しないようランダムIDを使用\n */\nfunction createPlaceholder(): string {\n return `${PLACEHOLDER_PREFIX}${generateRandomId()}${PLACEHOLDER_SUFFIX}`;\n}\n\n/**\n * コードブロックの HTML を生成する\n * Shiki の出力(<pre><code>...</code></pre>)を外側のコンテナでラップする\n * 注: <pre> や <code> へのクラス・属性追加は highlight() の transformers で行う\n */\nfunction wrapHighlightedCode({\n highlightedHtml,\n fileName,\n}: {\n highlightedHtml: string;\n fileName?: string;\n}): string {\n // ファイル名コンテナを追加\n const fileNameHtml = fileName\n ? `<div class=\"code-block-filename-container\"><span class=\"code-block-filename\">${md.utils.escapeHtml(\n fileName\n )}</span></div>`\n : '';\n\n return `<div class=\"code-block-container\">${fileNameHtml}${highlightedHtml}</div>`;\n}\n\n/**\n * エラー時のフォールバック HTML を生成\n * Shiki でのハイライトに失敗した場合に使用\n */\nfunction getPlainHtml({\n content,\n fileName,\n line,\n}: {\n content: string;\n fileName?: string;\n line?: number;\n}): string {\n const escapedContent = md.utils.escapeHtml(content);\n const lineAttr = line !== undefined ? ` data-line=\"${line}\"` : '';\n\n const preHtml = `<pre><code class=\"code-line\"${lineAttr}>${escapedContent}</code></pre>`;\n\n return wrapHighlightedCode({ highlightedHtml: preHtml, fileName });\n}\n\n// Shiki がネイティブサポートしていない言語のフォールバック\nconst fallbackLanguages: {\n [key: string]: string;\n} = {\n react: 'jsx',\n cwl: 'yaml',\n};\n\nfunction normalizeLangName(str?: string): string {\n if (!str?.length) return '';\n const langName = str.toLocaleLowerCase();\n return fallbackLanguages[langName] ?? langName;\n}\n\nexport function parseInfo(str: string): {\n hasDiff: boolean;\n langName: string;\n fileName?: string;\n} {\n if (str.trim() === '') {\n return {\n langName: '',\n fileName: undefined,\n hasDiff: false,\n };\n }\n\n // e.g. foo:filename => [\"foo\", \"filename\"]\n // e.g. foo diff:filename => [\"foo diff\", \"filename\"]\n // e.g. foo:filename:bar => [\"foo\", \"filename:bar\"]\n const separatorIndex = str.indexOf(':');\n const langInfo = separatorIndex > -1 ? str.substring(0, separatorIndex) : str;\n const fileName =\n separatorIndex > -1 ? str.substring(separatorIndex + 1) : undefined;\n\n const langNames = langInfo.split(' ');\n const hasDiff = langNames.some((name) => name === 'diff');\n\n const langName: undefined | string = hasDiff\n ? langNames.find((lang) => lang !== 'diff')\n : langNames[0];\n\n return {\n langName: normalizeLangName(langName),\n fileName,\n hasDiff,\n };\n}\n\n/**\n * [Phase 1] markdown-it にコードブロックのレンダラーを登録する\n *\n * markdown-it がコードブロック(```)を検出するたびに呼ばれ、\n * 以下の処理を行う:\n * 1. コードブロックの情報(内容、言語、diff有無など)を codeBlocks 配列に追加\n * 2. プレースホルダー(例: <!--SHIKI_CODE_BLOCK_xxxxxxxx-->)を返す\n *\n * このレンダラーは同期的に動作し、実際のハイライト処理は\n * Phase 2(applyHighlighting)で非同期に行われる。\n *\n * @param md - markdown-it インスタンス\n * @param options - Markdown 変換オプション\n * @param codeBlocks - コードブロック情報を格納する配列(副作用で変更される)\n */\nexport function mdRendererFence(\n md: MarkdownIt,\n options: MarkdownOptions,\n codeBlocks: CodeBlockInfo[]\n) {\n // override fence\n md.renderer.rules.fence = function (...args) {\n const [tokens, idx] = args;\n const { info, content } = tokens[idx];\n const { langName, fileName, hasDiff } = parseInfo(info);\n\n if (langName === 'mermaid') {\n const generator = options.customEmbed?.mermaid;\n // generator が(上書きされて)定義されてない場合はそのまま出力する\n return generator ? generator(content.trim(), options) : content;\n }\n\n const fenceStart = tokens[idx].map?.[0];\n const placeholder = createPlaceholder();\n\n codeBlocks.push({\n content,\n langName,\n hasDiff,\n fileName,\n line: fenceStart,\n placeholder,\n });\n return placeholder;\n };\n}\n\n/**\n * [Phase 2 & 3] プレースホルダーをハイライトされたコードに置換する\n *\n * Phase 2: 全コードブロックを Shiki で並列ハイライト\n * - Promise.all により、複数のコードブロックを同時に処理\n * - 各コードブロックに対して highlight() を呼び出し\n * - 言語が未ロードの場合は自動的にロード(遅延ロード)\n *\n * Phase 3: プレースホルダーを置換\n * - <!--SHIKI_CODE_BLOCK_xxxxxxxx--> を実際のハイライト済み HTML に置換\n *\n * @param html - プレースホルダーを含む HTML 文字列\n * @param codeBlocks - Phase 1 で収集したコードブロック情報の配列\n * @returns ハイライト済みの完全な HTML 文字列\n */\nexport async function applyHighlighting(\n html: string,\n codeBlocks: CodeBlockInfo[]\n): Promise<string> {\n // すべてのコードブロックを並列でハイライト\n const highlightedBlocks = await Promise.all(\n codeBlocks.map(async (block) => {\n try {\n const highlightedHtml = await highlight(block.content, block.langName, {\n hasDiff: block.hasDiff,\n line: block.line,\n });\n\n return wrapHighlightedCode({\n highlightedHtml,\n fileName: block.fileName,\n });\n } catch {\n // エラー時はプレーンテキストとして出力\n return getPlainHtml({\n content: block.content,\n fileName: block.fileName,\n line: block.line,\n });\n }\n })\n );\n\n // プレースホルダーを置換\n // 注: replace の第2引数を関数にすることで、$' や $` などの\n // 特殊パターン解釈を防ぐ(コードブロック内に $ が含まれる場合の対策)\n let result = html;\n for (let i = 0; i < highlightedBlocks.length; i++) {\n result = result.replace(\n codeBlocks[i].placeholder,\n () => highlightedBlocks[i]\n );\n }\n\n return result;\n}\n","import MarkdownIt from 'markdown-it';\nimport type { RenderRule } from 'markdown-it/lib/renderer.mjs';\n\nexport const mdImage = (md: MarkdownIt): void => {\n const originalImageRenderRule = md.renderer.rules['image'] as RenderRule;\n\n md.renderer.rules.image = (tokens, idx, options, env, slf) => {\n const token = tokens[idx];\n\n token.attrJoin('class', 'md-img');\n token.attrSet('loading', 'lazy');\n\n return originalImageRenderRule(tokens, idx, options, env, slf);\n };\n};\n","import { md } from './markdown-it';\nimport type Token from 'markdown-it/lib/token.mjs';\n\n// containers\n// ref: https://github.com/markdown-it/markdown-it-container\n\n// ::: details Detail\n// summary comes here\n// :::\nexport const containerDetailsOptions = {\n validate: function (params: string) {\n return /^details\\s+(.*)$/.test(params.trim());\n },\n render: function (tokens: Token[], idx: number) {\n const m = tokens[idx].info.trim().match(/^details\\s+(.*)$/);\n const summary = m?.[1] || '';\n if (tokens[idx].nesting === 1) {\n // opening tag\n return (\n '<details><summary>' +\n md.utils.escapeHtml(summary) +\n '</summary><div class=\"details-content\">'\n );\n } else {\n // closing tag\n return '</div></details>\\n';\n }\n },\n};\n// ::: message alert\n// text\n// :::\nconst msgClassRegex = /^message\\s*(alert)?$/;\n\nexport const containerMessageOptions = {\n validate: function (params: string) {\n return msgClassRegex.test(params.trim());\n },\n render: function (tokens: Token[], idx: number) {\n const m = tokens[idx].info.trim().match(msgClassRegex);\n const messageName = m?.[1] === 'alert' ? 'alert' : 'message';\n\n if (tokens[idx].nesting === 1) {\n // opening tag\n const symbol = `<span class=\"msg-symbol\">!</span>`;\n return `<aside class=\"msg ${messageName}\">${symbol}<div class=\"msg-content\">`;\n } else {\n // closing tag\n return `</div></aside>\\n`;\n }\n },\n};\n","import MarkdownIt from 'markdown-it';\nimport { mdLinkAttributes } from './utils/md-link-attributes';\nimport { sanitize } from './sanitizer';\n\n// preset 'zero' はデフォルトで全ての変換を無効化したプリセットです。\n// Ref: https://github.com/markdown-it/markdown-it/blob/master/lib/presets/zero.js\nconst md = MarkdownIt('zero', {\n breaks: true, // 改行を<br>に変換する\n linkify: true, // URLをリンクに変換する\n});\n\nmd.enable('emphasis'); // 太字と斜体を有効化\nmd.enable('link'); // リンクを有効化\nmd.enable('list'); // リストを有効化\n// 改行コードを<br>に変換する('zero'presetの場合、newlineを有効化する必要がある)\n// Ref: https://github.com/markdown-it/markdown-it/issues/491\nmd.enable('newline');\n// linkify を有効化('zero'presetの場合、linkifyを有効化する必要がある)\n// Ref: https://github.com/markdown-it/markdown-it/issues/396\nmd.enable('linkify');\n\n// fuzzyLink - recognize URL-s without http(s):// head. Default true.\n// Ref: http://markdown-it.github.io/linkify-it/doc/#LinkifyIt.prototype.set\nmd.linkify.set({ fuzzyLink: false });\n\nmd.use(mdLinkAttributes);\n\n// 限られた記法のみをHTMLに変換するパーサー\nexport const markdownToSimpleHtml = (text: string): string => {\n if (!(text && text.length)) return '';\n\n return sanitize(md.render(text));\n};\n"],"mappings":"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","names":["md","md","md","md","md","md","md","md","md","md","md"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/sanitizer.ts","../src/utils/markdown-it.ts","../src/utils/url-matcher.ts","../src/utils/embed-helper.ts","../src/embed.ts","../src/utils/md-imsize.ts","../src/utils/md-br.ts","../src/utils/md-katex.ts","../src/utils/md-custom-block.ts","../src/utils/md-link-attributes.ts","../src/utils/md-source-map.ts","../src/utils/md-linkify-to-card.ts","../src/utils/highlight.ts","../src/utils/md-renderer-fence.ts","../src/utils/md-image.ts","../src/utils/md-container.ts","../src/markdown-to-simple-html.ts"],"sourcesContent":["import markdownIt from 'markdown-it';\nimport { sanitize } from './sanitizer';\nimport { embedGenerators } from './embed';\nimport { MarkdownOptions } from './types';\n\n// plugins\nimport markdownItAnchor from 'markdown-it-anchor';\nimport { mdImsize } from './utils/md-imsize';\nimport { mdBr } from './utils/md-br';\nimport { mdKatex } from './utils/md-katex';\nimport { mdCustomBlock } from './utils/md-custom-block';\nimport { mdLinkAttributes } from './utils/md-link-attributes';\nimport { mdSourceMap } from './utils/md-source-map';\nimport { mdLinkifyToCard } from './utils/md-linkify-to-card';\nimport {\n mdRendererFence,\n applyHighlighting,\n CodeBlockInfo,\n} from './utils/md-renderer-fence';\nimport { mdImage } from './utils/md-image';\nimport {\n containerDetailsOptions,\n containerMessageOptions,\n} from './utils/md-container';\nimport mdContainer from 'markdown-it-container';\nimport mdFootnote from 'markdown-it-footnote';\nimport mdTaskLists from 'markdown-it-task-lists';\nimport mdInlineComments from 'markdown-it-inline-comments';\n\n/**\n * Markdown を HTML に変換する(非同期)\n *\n * Shiki によるシンタックスハイライトを使用。\n * 詳細なアーキテクチャについては md-renderer-fence.ts のコメントを参照。\n *\n * 処理フロー:\n * 1. [Phase 1] md.render() - Markdown を HTML に変換(コードブロックはプレースホルダーに)\n * 2. [Phase 2 & 3] applyHighlighting() - プレースホルダーをハイライト済み HTML に置換\n * 3. sanitize() - XSS 対策のためサニタイズ\n */\nconst markdownToHtml = async (\n text: string,\n options?: MarkdownOptions\n): Promise<string> => {\n if (!(text && text.length)) return '';\n\n const markdownOptions: MarkdownOptions = {\n ...options,\n customEmbed: {\n ...embedGenerators,\n ...options?.customEmbed,\n },\n };\n\n const md = markdownIt({ breaks: true, linkify: true });\n\n md.linkify.set({ fuzzyLink: false });\n md.linkify.set({ fuzzyEmail: false }); // refs: https://github.com/markdown-it/linkify-it\n\n // コードブロック情報を保存する配列\n // Phase 1 で mdRendererFence によって追加され、Phase 2 でハイライト処理に使用される\n const codeBlocks: CodeBlockInfo[] = [];\n\n md.use(mdBr)\n .use(mdKatex)\n .use(mdFootnote)\n .use(mdInlineComments)\n .use(mdImsize)\n .use(mdLinkAttributes)\n .use(mdCustomBlock, markdownOptions)\n .use(mdRendererFence, markdownOptions, codeBlocks)\n .use(mdLinkifyToCard, markdownOptions)\n .use(mdTaskLists, { enabled: true })\n .use(mdContainer, 'details', containerDetailsOptions)\n .use(mdContainer, 'message', containerMessageOptions)\n .use(markdownItAnchor, {\n level: [1, 2, 3, 4],\n permalink: markdownItAnchor.permalink.ariaHidden({\n placement: 'before',\n class: 'header-anchor-link',\n symbol: '',\n }),\n tabIndex: false,\n })\n .use(mdSourceMap)\n .use(mdImage);\n\n // custom footnote\n md.renderer.rules.footnote_block_open = () =>\n '<section class=\"footnotes\">\\n' +\n '<span class=\"footnotes-title\">脚注</span>\\n' +\n '<ol class=\"footnotes-list\">\\n';\n\n // docIdは複数のコメントが1ページに指定されたときに脚注のリンク先が重複しないように指定する\n // 1ページの中で重複しなければ問題ないため、ごく短いランダムな文字列とする\n // - https://github.com/zenn-dev/zenn-community/issues/356\n // - https://github.com/markdown-it/markdown-it-footnote/pull/8\n // Web Crypto API を使用(ブラウザ・Node.js 両対応)\n const randomBytes = new Uint8Array(2);\n globalThis.crypto.getRandomValues(randomBytes);\n const docId = Array.from(randomBytes, (b) =>\n b.toString(16).padStart(2, '0')\n ).join('');\n\n // ============================================================\n // Phase 1: Markdown → HTML 変換(同期)\n // ============================================================\n // markdown-it がコードブロックを検出すると mdRendererFence が呼ばれ、\n // コードブロック情報が codeBlocks 配列に保存され、\n // HTML にはプレースホルダー(<!--SHIKI_CODE_BLOCK_xxxxxxxx-->)が挿入される\n const rawHtml = md.render(text, { docId });\n\n // ============================================================\n // Phase 2 & 3: シンタックスハイライト適用(非同期)\n // ============================================================\n // - Phase 2: 全コードブロックを Shiki で並列ハイライト\n // - Phase 3: プレースホルダーをハイライト済み HTML に置換\n const highlightedHtml = await applyHighlighting(rawHtml, codeBlocks);\n\n // サニタイズして返す(XSS 対策)\n return sanitize(highlightedHtml);\n};\n\nexport default markdownToHtml;\nexport { markdownToSimpleHtml } from './markdown-to-simple-html';\n","import sanitizeHtml from 'sanitize-html';\n\nconst tags = [\n 'a',\n 'aside',\n 'blockquote',\n 'br',\n 'circle',\n 'code',\n 'details',\n 'div',\n 'em',\n 'embed-katex',\n 'eq',\n 'eqn',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'hr',\n 'iframe',\n 'img',\n 'input',\n 'li',\n 'ol',\n 'p',\n 'pre',\n 's',\n 'section',\n 'span',\n 'strong',\n 'summary',\n 'sup',\n 'table',\n 'tbody',\n 'td',\n 'text',\n 'th',\n 'thead',\n 'tr',\n 'ul',\n];\n\nconst attributes = {\n a: ['aria-hidden', 'class', 'href', 'id', 'rel', 'style', 'target', 'title'],\n aside: ['class'],\n blockquote: ['class', 'data-line'],\n br: ['style'],\n circle: ['cx', 'cy', 'fill', 'r'],\n code: ['class', 'data-line'],\n details: [],\n div: ['class'],\n em: [],\n 'embed-katex': ['display-mode'],\n eq: ['class'],\n eqn: [],\n h1: ['id', 'class', 'data-line'],\n h2: ['id', 'class', 'data-line'],\n h3: ['id', 'class', 'data-line'],\n h4: ['id', 'class', 'data-line'],\n h5: ['class', 'data-line'],\n h6: ['class', 'data-line'],\n hr: ['class', 'data-line'],\n iframe: [\n 'allow',\n 'allowfullscreen',\n 'allowtransparency',\n 'data-content',\n 'frameborder',\n 'id',\n 'loading',\n 'sandbox',\n 'scrolling',\n 'src',\n 'style',\n 'width',\n ],\n img: ['alt', 'class', 'height', 'loading', 'src', 'title', 'width'],\n input: ['checked', 'class', 'type'],\n li: ['class', 'id', 'data-line'],\n ol: ['class', 'start', 'data-line'],\n p: ['class', 'data-line'],\n pre: ['class', 'style'],\n s: [],\n section: ['class', 'data-line'],\n span: ['class', 'style', 'title'],\n strong: [],\n summary: [],\n sup: ['class'],\n table: ['class', 'data-line'],\n tbody: ['class', 'data-line'],\n td: ['style'],\n text: [\n 'dominant-baseline',\n 'fill',\n 'font-size',\n 'font-weight',\n 'text-anchor',\n 'x',\n 'y',\n ],\n th: ['style'],\n thead: ['class', 'data-line'],\n tr: ['class', 'data-line'],\n ul: ['class', 'data-line'],\n};\n\nexport const sanitize = (html: string) =>\n sanitizeHtml(html, {\n allowedTags: tags,\n allowedAttributes: attributes,\n disallowedTagsMode: 'discard',\n // from: default value https://github.com/apostrophecms/sanitize-html#default-options\n selfClosing: [\n 'img',\n 'br',\n 'hr',\n 'area',\n 'base',\n 'basefont',\n 'input',\n 'link',\n 'meta',\n ],\n });\n","import markdownit from 'markdown-it';\n\nexport const md = markdownit();\n","/** URL文字列か判定する */\nexport function isValidHttpUrl(str: string) {\n try {\n const url = new URL(str);\n return url.protocol === 'http:' || url.protocol === 'https:';\n } catch (_) {\n return false;\n }\n}\n\nexport function isGithubUrl(url: string): boolean {\n return /^https:\\/\\/github\\.com\\/([a-zA-Z0-9](-?[a-zA-Z0-9]){0,38})\\/([a-zA-Z0-9](-?[a-zA-Z0-9._]){0,99})\\/blob\\/[^~\\s:?[*^/\\\\]{2,}\\/[\\w!\\-_~.*%()'\"/]+(?:#L\\d+(?:-L\\d+)?)?$/.test(\n url\n );\n}\n\n// Thanks: https://github.com/forem/forem/blob/d2d9984f28b1d0662f2a858b325a0e6b7a27a24c/app/liquid_tags/gist_tag.rb\nexport function isGistUrl(url: string): boolean {\n return /^https:\\/\\/gist\\.github\\.com\\/([a-zA-Z0-9](-?[a-zA-Z0-9]){0,38})\\/([a-zA-Z0-9]){1,32}(\\/[a-zA-Z0-9]+)?(\\?file=.+)?$/.test(\n url\n );\n}\n\nexport function isTweetUrl(url: string): boolean {\n return /^https:\\/\\/(twitter|x)\\.com\\/[a-zA-Z0-9_-]+\\/status\\/[a-zA-Z0-9?=&\\-_]+$/.test(\n url\n );\n}\n\nexport function isStackblitzUrl(url: string): boolean {\n return /^https:\\/\\/stackblitz\\.com\\/[a-zA-Z0-9\\-_/.@?&=%[\\]]+$/.test(url);\n}\n\nexport function isCodesandboxUrl(url: string): boolean {\n return /^https:\\/\\/codesandbox\\.io\\/embed\\/[a-zA-Z0-9\\-_/.@?&=%,+]+$/.test(\n url\n );\n}\n\nexport function isCodepenUrl(url: string): boolean {\n return /^https:\\/\\/codepen\\.io\\/[a-zA-Z0-9\\-_/@]+\\/pen\\/[a-zA-Z0-9\\-_/.@?&=%,]+$/.test(\n url\n );\n}\n\nexport function isJsfiddleUrl(url: string): boolean {\n return /^(http|https):\\/\\/jsfiddle\\.net\\/[a-zA-Z0-9_,/-]+$/.test(url);\n}\n\n// 例: https://www.docswell.com/s/ku-suke/LK7J5V-hello-docswell\n// 例: https://www.docswell.com/s/ku-suke/LK7J5V-hello-docswell#p13\n// 例: https://www.docswell.com/s/ku-suke/LK7J5V-hello-docswell/13\nconst docswellNormalUrlRegex =\n /^https:\\/\\/www\\.docswell\\.com\\/s\\/[a-zA-Z0-9_-]+\\/[a-zA-Z0-9_-]+(\\/\\d+)?(#p\\d+)?$/;\n\n// 例: https://www.docswell.com/slide/LK7J5V/embed\n// 例: https://www.docswell.com/slide/LK7J5V/embed#p12\nconst docswellEmbedUrlRegex =\n /^https:\\/\\/www\\.docswell\\.com\\/slide\\/[a-zA-Z0-9_-]+\\/embed(#p\\d+)?$/;\n\nexport function isDocswellUrl(url: string): boolean {\n return [docswellNormalUrlRegex, docswellEmbedUrlRegex].some((pattern) =>\n pattern.test(url)\n );\n}\n\nexport function isYoutubeUrl(url: string): boolean {\n return [\n /^https?:\\/\\/youtu\\.be\\/[\\w-]+(?:\\?[\\w=&-]+)?$/,\n /^https?:\\/\\/(?:www\\.)?youtube\\.com\\/watch\\?[\\w=&-]+$/,\n ].some((pattern) => pattern.test(url));\n}\n\n/** YoutubeのVideoIdの文字列の長さ */\nconst YOUTUBE_VIDEO_ID_LENGTH = 11;\n\n/**\n * youtube の URL から videoId と開始位置の秒数を取得する\n */\nexport function extractYoutubeVideoParameters(\n youtubeUrl: string\n): { videoId: string; start?: string } | undefined {\n if (!isYoutubeUrl(youtubeUrl)) return void 0;\n\n const url = new URL(youtubeUrl);\n const params = new URLSearchParams(url.search || '');\n\n // https://youtu.be/Hoge の \"HogeHoge\" の部分または、\n // https://www.youtube.com/watch?v=Hoge の \"Hoge\" の部分を値とする\n const videoId = params.get('v') || url.pathname.split('/')[1];\n\n // https://www.youtube.com/watch?v=Hoge&t=100s の \"100\" の部分を値とする\n const start = params.get('t')?.replace('s', '');\n\n if (videoId?.length !== YOUTUBE_VIDEO_ID_LENGTH) return void 0;\n\n return { videoId, start };\n}\n\nexport function extractDocswellEmbedUrl(url: string): string | null {\n // Embed用URLの場合、そのまま返す\n if (docswellEmbedUrlRegex.test(url)) {\n return url;\n }\n // Embed用URLでない場合 https://www.docswell.com/s/:username/{slideId}-hello-docswell のslideIdを抽出する\n const urlObj = new URL(url); // URLオブジェクトを作成\n const pathSegments = urlObj.pathname.split('/');\n // pathSegmentsの例: [\"\", \"s\", \"ku-suke\", \"LK7J5V-hello-docswell\", \"10\"]\n // slideIdは pathSegments[3] の先頭部分\n const slideIdPart = pathSegments.at(3);\n const slideId = slideIdPart?.split('-').at(0);\n\n if (!slideId) {\n return null;\n }\n\n let pageSuffix = '';\n // #pXX 形式のページ番号を優先 (例: #p18)\n if (urlObj.hash && /^#p\\d+$/.test(urlObj.hash)) {\n pageSuffix = urlObj.hash;\n } else {\n // /XX 形式のページ番号 (例: /28)\n // 通常URLの形式: /s/{username}/{slideId-slug}/{optional_page_num}\n // ページ番号がある場合、pathSegmentsの長さは5になる (e.g., [\"\", \"s\", \"username\", \"slide-slug\", \"page\"])\n if (pathSegments.length === 5) {\n const pageCandidate = pathSegments.at(4);\n if (pageCandidate && /^\\d+$/.test(pageCandidate)) {\n pageSuffix = `#p${pageCandidate}`;\n }\n }\n }\n\n return new URL(\n `/slide/${slideId}/embed${pageSuffix}`, // pageSuffixを結合\n 'https://www.docswell.com'\n ).toString();\n}\n\n/**\n * 参考: https://blueprintue.com/\n * 生成されるURLをもとに正規表現を定義した\n */\n\nexport function isBlueprintUEUrl(url: string): boolean {\n return /^https:\\/\\/blueprintue\\.com\\/render\\/[-\\w]+\\/?$/.test(url);\n}\n\n/**\n * 参考: https://www.figma.com/developers/embed\n */\nexport function isFigmaUrl(url: string): boolean {\n return /^https:\\/\\/([\\w.-]+\\.)?figma.com\\/(file|proto)\\/([0-9a-zA-Z]{22,128})(?:\\/[\\w-?=&%]+)?$/.test(\n url\n );\n}\n","import { MarkdownOptions } from '../types';\nimport { embedKeys, EmbedServerType, EmbedType } from '../embed';\nimport { isTweetUrl, isGithubUrl, isYoutubeUrl } from './url-matcher';\n\n/** 渡された文字列をサニタイズする */\nexport function sanitizeEmbedToken(str: string): string {\n return str.replace(/\"/g, '%22');\n}\n\n/** `EmbedType`か判定する */\nexport function isEmbedType(type: unknown): type is EmbedType {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return embedKeys.includes(type as any);\n}\n\n/** 渡された埋め込みURLまたはTokenを検証する */\nexport const validateEmbedToken = (\n str: string,\n type?: EmbedType\n): { isValid: boolean; message: string } => {\n /** 検証から除外する埋め込みの種別 */\n const ignoredEmbedType: EmbedType[] = ['card', 'github'];\n /** 埋め込みURLまたはTokenの最大文字数( excludeEmbedTypeは除く ) */\n const MAX_EMBED_TOKEN_LENGTH = 300;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (ignoredEmbedType.includes(type as any)) {\n return { isValid: true, message: '' };\n }\n\n if (str.length > MAX_EMBED_TOKEN_LENGTH) {\n return {\n isValid: false,\n message: `埋め込みURLは${MAX_EMBED_TOKEN_LENGTH}文字以内にする必要があります`,\n };\n }\n\n return { isValid: true, message: '' };\n};\n\n/** Embedサーバーを使った埋め込み要素の文字列を生成する */\nexport function generateEmbedServerIframe(\n type: EmbedServerType,\n src: string,\n embedOrigin: string\n): string {\n const origin = (() => {\n try {\n return new URL(embedOrigin).origin;\n } catch {\n return void 0;\n }\n })();\n\n // 埋め込みサーバーの origin が設定されてなければ空文字列を返す\n if (!origin) {\n console.warn('The embedOrigin option not set');\n return '';\n }\n\n // ユーザーからの入力値が引数として渡されたときのために念のためencodeする\n const encodedType = encodeURIComponent(type);\n const encodedSrc = encodeURIComponent(src);\n const id = `zenn-embedded__${Math.random().toString(16).slice(2)}`;\n const iframeSrc = `${origin}/${encodedType}#${id}`;\n\n return `<span class=\"embed-block zenn-embedded zenn-embedded-${encodedType}\"><iframe id=\"${id}\" src=\"${iframeSrc}\" data-content=\"${encodedSrc}\" frameborder=\"0\" scrolling=\"no\" loading=\"lazy\"></iframe></span>`;\n}\n\n/** 渡された`type`の埋め込み要素のHTML文字列を返す */\nexport const generateEmbedHTML = (\n type: EmbedType,\n str: string,\n options?: MarkdownOptions\n): string => {\n const { isValid, message } = validateEmbedToken(str, type);\n const generator = options?.customEmbed?.[type];\n\n return isValid ? generator?.(str, options) || str : message;\n};\n\n/** Linkifyな埋め込み要素のHTML生成する */\nexport const generateLinkifyEmbedHTML = (\n url: string,\n options?: MarkdownOptions\n): string => {\n const { isValid, message: msg } = validateEmbedToken(url);\n const generators = options?.customEmbed;\n\n if (!generators) return url;\n\n if (isTweetUrl(url))\n return isValid ? generators.tweet?.(url, options) || url : msg;\n\n if (isYoutubeUrl(url))\n return isValid ? generators.youtube?.(url, options) || url : msg;\n\n // GitHub は URL が長くなりやすいためバリデーション(`validateEmbedToken`)から外す\n if (isGithubUrl(url)) return generators.github?.(url, options) || url;\n\n return generators.card?.(url, options) || url;\n};\n","import type { MarkdownOptions } from './types';\n\nimport { md } from './utils/markdown-it';\nimport {\n sanitizeEmbedToken,\n generateEmbedServerIframe,\n} from './utils/embed-helper';\nimport {\n isGistUrl,\n isTweetUrl,\n isGithubUrl,\n isStackblitzUrl,\n isCodesandboxUrl,\n isCodepenUrl,\n isJsfiddleUrl,\n isBlueprintUEUrl,\n isFigmaUrl,\n isValidHttpUrl,\n isDocswellUrl,\n extractYoutubeVideoParameters,\n extractDocswellEmbedUrl,\n} from './utils/url-matcher';\n\n/* 埋め込み要素の種別 */\nexport type EmbedType =\n | 'youtube'\n | 'slideshare'\n | 'speakerdeck'\n | 'jsfiddle'\n | 'docswell'\n | 'codepen'\n | 'codesandbox'\n | 'stackblitz'\n | 'tweet'\n | 'blueprintue'\n | 'figma'\n | 'card'\n | 'gist'\n | 'github'\n | 'mermaid';\n\n/** embedサーバーで表示する埋め込み要素の種別 */\nexport type EmbedServerType = Extract<\n EmbedType,\n 'tweet' | 'card' | 'mermaid' | 'github' | 'gist'\n>;\n\n/** 埋め込み要素のHTMLを生成する関数 */\nexport type EmbedGenerator = (str: string, options?: MarkdownOptions) => string;\nexport type EmbedGeneratorList = Record<EmbedType, EmbedGenerator>;\n\n/** 埋め込み要素のHTMLを生成する関数をまとめたオブジェクト */\nexport const embedGenerators: Readonly<EmbedGeneratorList> = {\n youtube(str) {\n const params = extractYoutubeVideoParameters(str) || { videoId: str };\n\n if (!params.videoId.match(/^[a-zA-Z0-9_-]+$/)) {\n return 'YouTubeのvideoIDが不正です';\n }\n\n const escapedVideoId = md.utils.escapeHtml(params.videoId);\n const time = Math.min(Number(params.start || 0), 48 * 60 * 60); // 48時間以内\n const startQuery = time ? `?start=${time}` : '';\n\n return `<span class=\"embed-block embed-youtube\"><iframe src=\"https://www.youtube-nocookie.com/embed/${escapedVideoId}${startQuery}\" allow=\"accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen loading=\"lazy\"></iframe></span>`;\n },\n slideshare(key) {\n if (!key?.match(/^[a-zA-Z0-9_-]+$/)) {\n return 'Slide Shareのkeyが不正です';\n }\n return `<span class=\"embed-block embed-slideshare\"><iframe src=\"https://www.slideshare.net/slideshow/embed_code/key/${md.utils.escapeHtml(\n key\n )}\" scrolling=\"no\" allowfullscreen loading=\"lazy\"></iframe></span>`;\n },\n speakerdeck(str) {\n if (!str?.match(/^[a-zA-Z0-9_-]+(?:\\?slide=\\d+)?$/)) {\n return 'Speaker Deckのkeyが不正です';\n }\n\n const [key, slideParamStr] = str.split('?');\n const slideQuery = slideParamStr ? `?${slideParamStr}` : '';\n\n return `<span class=\"embed-block embed-speakerdeck\"><iframe src=\"https://speakerdeck.com/player/${md.utils.escapeHtml(\n key\n )}${md.utils.escapeHtml(slideQuery)}\" scrolling=\"no\" allowfullscreen allow=\"encrypted-media\" loading=\"lazy\"></iframe></span>`;\n },\n docswell(str) {\n const errorMessage = 'DocswellのスライドURLが不正です';\n if (!isDocswellUrl(str)) {\n return errorMessage;\n }\n const slideUrl = extractDocswellEmbedUrl(str);\n if (!slideUrl) {\n return errorMessage;\n }\n return `<span class=\"embed-block embed-docswell\"><iframe src=\"${slideUrl}\" allowfullscreen=\"true\" class=\"docswell-iframe\" width=\"100%\" style=\"border: 1px solid #ccc; display: block; margin: 0px auto; padding: 0px; aspect-ratio: 16/9\"></iframe></span>`;\n },\n jsfiddle(str) {\n if (!isJsfiddleUrl(str)) {\n return 'jsfiddleのURLが不正です';\n }\n // URLを~/embedded/とする\n // ※ すでにembeddedもしくはembedが含まれるURLが入力されている場合は、そのままURLを使用する。\n let url = str;\n if (!url.includes('embed')) {\n url = url.endsWith('/') ? `${url}embedded/` : `${url}/embedded/`;\n }\n return `<span class=\"embed-block embed-jsfiddle\"><iframe src=\"${sanitizeEmbedToken(\n url\n )}\" scrolling=\"no\" frameborder=\"no\" loading=\"lazy\"></iframe></span>`;\n },\n codepen(str) {\n if (!isCodepenUrl(str)) {\n return 'CodePenのURLが不正です';\n }\n const url = new URL(str.replace('/pen/', '/embed/'));\n url.searchParams.set('embed-version', '2');\n return `<span class=\"embed-block embed-codepen\"><iframe src=\"${sanitizeEmbedToken(\n url.toString()\n )}\" scrolling=\"no\" frameborder=\"no\" loading=\"lazy\"></iframe></span>`;\n },\n codesandbox(str) {\n if (!isCodesandboxUrl(str)) {\n return '「https://codesandbox.io/embed/」から始まる正しいURLを入力してください';\n }\n return `<span class=\"embed-block embed-codesandbox\"><iframe src=\"${sanitizeEmbedToken(\n str\n )}\" style=\"width:100%;height:500px;border:none;overflow:hidden;\" allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\" loading=\"lazy\" sandbox=\"allow-modals allow-forms allow-popups allow-scripts allow-same-origin\"></iframe></span>`;\n },\n stackblitz(str) {\n if (!isStackblitzUrl(str)) {\n return 'StackBlitzのembed用のURLを指定してください';\n }\n return `<span class=\"embed-block embed-stackblitz\"><iframe src=\"${sanitizeEmbedToken(\n str\n )}\" scrolling=\"no\" frameborder=\"no\" loading=\"lazy\"></iframe></span>`;\n },\n blueprintue(str) {\n if (!isBlueprintUEUrl(str))\n return '「https://blueprintue.com/render/」から始まる正しいURLを指定してください';\n return `<span class=\"embed-block embed-blueprintue\"><iframe src=\"${sanitizeEmbedToken(\n str\n )}\" width=\"100%\" style=\"aspect-ratio: 16/9\" scrolling=\"no\" frameborder=\"no\" loading=\"lazy\" allowfullscreen></iframe></span>`;\n },\n figma(str: string) {\n if (!isFigmaUrl(str))\n return 'ファイルまたはプロトタイプのFigma URLを指定してください';\n return `<span class=\"embed-block embed-figma\"><iframe src=\"https://www.figma.com/embed?embed_host=zenn&url=${sanitizeEmbedToken(\n str\n )}\" width=\"100%\" style=\"aspect-ratio: 16/9\" scrolling=\"no\" frameborder=\"no\" loading=\"lazy\" allowfullscreen></iframe></span>`;\n },\n\n // 以下は埋め込みサーバーが絡む要素。\n // embedOrigin が指定されていれば埋め込みサーバーを iframe で表示、\n // なければデフォルトの挙動(リンクの表示など)を行います。\n\n card(str, options) {\n if (!isValidHttpUrl(str)) return 'URLが不正です';\n if (options?.embedOrigin)\n return generateEmbedServerIframe('card', str, options.embedOrigin);\n\n return `<a href=\"${str}\" rel=\"noreferrer noopener nofollow\" target=\"_blank\">${str}</a>`;\n },\n tweet(str, options) {\n if (!isTweetUrl(str)) return 'ツイートページのURLを指定してください';\n if (options?.embedOrigin)\n return generateEmbedServerIframe('tweet', str, options.embedOrigin);\n\n return `<a href=\"${str}\" rel=\"noreferrer noopener nofollow\" target=\"_blank\">${str}</a>`;\n },\n gist(str, options) {\n /**\n * gistのURL は\n * - https://gist.github.com/foo/bar.json\n * - https://gist.github.com/foo/bar.json?file=example.js\n * のような形式\n */\n if (!isGistUrl(str)) return 'GitHub GistのページURLを指定してください';\n if (options?.embedOrigin)\n return generateEmbedServerIframe('gist', str, options.embedOrigin);\n\n return `<a href=\"${str}\" rel=\"noreferrer noopener nofollow\" target=\"_blank\">${str}</a>`;\n },\n github(str, options) {\n if (!isGithubUrl(str))\n return 'GitHub のファイルURLまたはパーマリンクを指定してください';\n if (options?.embedOrigin)\n return generateEmbedServerIframe('github', str, options.embedOrigin);\n\n return `<a href=\"${str}\" rel=\"noreferrer noopener nofollow\" target=\"_blank\">${str}</a>`;\n },\n mermaid(str, options) {\n if (options?.embedOrigin)\n return generateEmbedServerIframe('mermaid', str, options.embedOrigin);\n\n // エスケープ処理しておく\n const src = str.replace(/>/g, '>');\n\n // ブラウザじゃないと mermaid はレンダリングできないので、Node.jsで描画するときはコードブロックのまま出力する\n return `<div class=\"code-block-container\"><pre><code>${src}</code></pre></div>`;\n },\n} as const;\n\n/** 埋め込み要素の種別配列 */\nexport const embedKeys = Object.keys(embedGenerators) as EmbedType[];\n","/**\n * markdown-it plugin for size-specified image markups\n * Based on https://github.com/steelydylan/markdown-it-imsize\n * License: MIT\n */\n\nimport MarkdownIt from 'markdown-it';\nimport type StateInline from 'markdown-it/lib/rules_inline/state_inline.mjs';\nimport type Token from 'markdown-it/lib/token.mjs';\n\ntype ParseResult = {\n ok: boolean;\n pos: number;\n str: string;\n};\n\nfunction parseNextNumber(str: string, pos: number, max: number) {\n let code: number;\n const start = pos;\n const result = {\n ok: false,\n pos: pos,\n value: '',\n };\n\n code = str.charCodeAt(pos);\n\n while (\n (pos < max && code >= 0x30 /* 0 */ && code <= 0x39) /* 9 */ ||\n code === 0x25 /* % */\n ) {\n code = str.charCodeAt(++pos);\n }\n\n result.ok = true;\n result.pos = pos;\n result.value = str.slice(start, pos);\n\n return result;\n}\n\nfunction parseImageSize(str: string, pos: number, max: number) {\n let code = str.charCodeAt(pos);\n const result = {\n ok: false,\n pos: 0,\n width: '',\n height: '',\n };\n\n if (pos >= max) {\n return result;\n }\n\n if (code !== 0x3d /* = */) {\n return result;\n }\n\n pos++;\n\n // size must follow = without any white spaces as follows\n // (1) =300x200\n // (2) =300x\n // (3) =x200\n code = str.charCodeAt(pos);\n if (code !== 0x78 /* x */ && (code < 0x30 || code > 0x39) /* [0-9] */) {\n return result;\n }\n\n // parse width\n const resultW = parseNextNumber(str, pos, max);\n pos = resultW.pos;\n\n // next charactor must be 'x'\n code = str.charCodeAt(pos);\n if (code !== 0x78 /* x */) {\n return result;\n }\n\n pos++;\n\n // parse height\n const resultH = parseNextNumber(str, pos, max);\n pos = resultH.pos;\n\n result.width = resultW.value;\n result.height = resultH.value;\n result.pos = pos;\n result.ok = true;\n return result;\n}\n\nfunction image_with_size(md: MarkdownIt) {\n return function (state: StateInline, silent: boolean) {\n let attrs: [string, string][];\n let code: number;\n let label = '';\n let pos: number;\n let ref: { href: string; title: string };\n let res: ParseResult | ReturnType<typeof parseImageSize>;\n let title: string;\n let width = '';\n let height = '';\n let token: Token;\n let tokens: Token[];\n let start: number;\n let href = '';\n const oldPos = state.pos;\n const max = state.posMax;\n\n if (state.src.charCodeAt(state.pos) !== 0x21 /* ! */) {\n return false;\n }\n if (state.src.charCodeAt(state.pos + 1) !== 0x5b /* [ */) {\n return false;\n }\n\n const labelStart = state.pos + 2;\n const labelEnd = md.helpers.parseLinkLabel(state, state.pos + 1, false);\n\n // parser failed to find ']', so it's not a valid link\n if (labelEnd < 0) {\n return false;\n }\n\n pos = labelEnd + 1;\n if (pos < max && state.src.charCodeAt(pos) === 0x28 /* ( */) {\n //\n // Inline link\n //\n\n // [link]( <href> \"title\" )\n // ^^ skipping these spaces\n pos++;\n for (; pos < max; pos++) {\n code = state.src.charCodeAt(pos);\n if (code !== 0x20 && code !== 0x0a) {\n break;\n }\n }\n if (pos >= max) {\n return false;\n }\n\n // [link]( <href> \"title\" )\n // ^^^^^^ parsing link destination\n res = md.helpers.parseLinkDestination(state.src, pos, state.posMax);\n if (res.ok) {\n href = state.md.normalizeLink(res.str);\n if (state.md.validateLink(href)) {\n pos = res.pos;\n } else {\n href = '';\n }\n }\n\n // [link]( <href> \"title\" )\n // ^^ skipping these spaces\n start = pos;\n for (; pos < max; pos++) {\n code = state.src.charCodeAt(pos);\n if (code !== 0x20 && code !== 0x0a) {\n break;\n }\n }\n\n // [link]( <href> \"title\" )\n // ^^^^^^^ parsing link title\n res = md.helpers.parseLinkTitle(state.src, pos, state.posMax);\n if (pos < max && start !== pos && res.ok) {\n title = res.str;\n pos = res.pos;\n\n // [link]( <href> \"title\" )\n // ^^ skipping these spaces\n for (; pos < max; pos++) {\n code = state.src.charCodeAt(pos);\n if (code !== 0x20 && code !== 0x0a) {\n break;\n }\n }\n } else {\n title = '';\n }\n\n // [link]( <href> \"title\" =WxH )\n // ^^^^ parsing image size\n if (pos - 1 >= 0) {\n code = state.src.charCodeAt(pos - 1);\n\n // there must be at least one white spaces\n // between previous field and the size\n if (code === 0x20) {\n res = parseImageSize(state.src, pos, state.posMax);\n if (res.ok) {\n width = res.width;\n height = res.height;\n pos = res.pos;\n\n // [link]( <href> \"title\" =WxH )\n // ^^ skipping these spaces\n for (; pos < max; pos++) {\n code = state.src.charCodeAt(pos);\n if (code !== 0x20 && code !== 0x0a) {\n break;\n }\n }\n }\n }\n }\n\n if (pos >= max || state.src.charCodeAt(pos) !== 0x29 /* ) */) {\n state.pos = oldPos;\n return false;\n }\n pos++;\n } else {\n //\n // Link reference\n //\n if (typeof state.env.references === 'undefined') {\n return false;\n }\n\n // [foo] [bar]\n // ^^ optional whitespace (can include newlines)\n for (; pos < max; pos++) {\n code = state.src.charCodeAt(pos);\n if (code !== 0x20 && code !== 0x0a) {\n break;\n }\n }\n\n if (pos < max && state.src.charCodeAt(pos) === 0x5b /* [ */) {\n start = pos + 1;\n pos = md.helpers.parseLinkLabel(state, pos);\n if (pos >= 0) {\n label = state.src.slice(start, pos++);\n } else {\n pos = labelEnd + 1;\n }\n } else {\n pos = labelEnd + 1;\n }\n\n // covers label === '' and label === undefined\n // (collapsed reference link and shortcut reference link respectively)\n if (!label) {\n label = state.src.slice(labelStart, labelEnd);\n }\n\n ref = state.env.references[md.utils.normalizeReference(label)];\n if (!ref) {\n state.pos = oldPos;\n return false;\n }\n href = ref.href;\n title = ref.title;\n }\n\n //\n // We found the end of the link, and know for a fact it's a valid link;\n // so all that's left to do is to call tokenizer.\n //\n if (!silent) {\n state.pos = labelStart;\n state.posMax = labelEnd;\n\n const newState = new state.md.inline.State(\n state.src.slice(labelStart, labelEnd),\n state.md,\n state.env,\n (tokens = [])\n );\n newState.md.inline.tokenize(newState);\n token = state.push('image', 'img', 0);\n token.attrs = attrs = [\n ['src', href],\n ['alt', ''],\n ];\n token.children = tokens;\n if (title) {\n attrs.push(['title', title]);\n }\n\n if (width !== '') {\n attrs.push(['width', width]);\n }\n\n if (height !== '') {\n attrs.push(['height', height]);\n }\n }\n\n state.pos = pos;\n state.posMax = max;\n return true;\n };\n}\n\nexport function mdImsize(md: MarkdownIt) {\n md.inline.ruler.before('emphasis', 'image', image_with_size(md));\n}\n","/**\n * forked from https://github.com/iktakahiro/markdown-it-br\n */\nimport MarkdownIt from 'markdown-it';\n\n/**\n * Return case-sensitive matched br tag\n * @param {any} state MarkdownIt state\n * @param {number} start start position at br tag\n * @returns {string | null} br tag (<br> or <br/> or <br />)\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction matchBR(state: any, start: number): string | null {\n const match = state.src.slice(start, start + 6).match(/^<br\\s?\\/?>/);\n if (match) {\n return match[0];\n }\n return null;\n}\n\nexport function mdBr(md: MarkdownIt): void {\n // Tokenize\n md.inline.ruler.before(\n 'emphasis',\n 'br',\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n function tokenize(state: any, silent): boolean {\n const max = state.posMax;\n const start = state.pos;\n\n // don't run any pairs in validation mode\n if (silent) {\n return false;\n }\n\n const br = matchBR(state, start);\n if (br === null || start + br.length > max) {\n return false;\n }\n state.scanDelims(state.pos, true);\n const token = state.push('text', '', 0);\n token.content = '<br>';\n state.delimiters.push({\n marker: token.content,\n jump: 0,\n token: state.tokens.length - 1,\n level: state.level,\n end: -1,\n open: true,\n close: true,\n });\n\n // length is: <br> -> 4, <br/> -> 5, <br /> -> 6\n state.pos += br.length;\n\n return true;\n }\n );\n\n // Walk through delimiter list and replace text tokens with tags\n md.inline.ruler2.before('emphasis', 'br', function postProcess(state) {\n let i;\n let delim;\n let token;\n const delimiters = state.delimiters;\n const max = state.delimiters.length;\n\n for (i = 0; i < max; i++) {\n delim = delimiters[i];\n const marker = delim.marker as number | '<br>';\n\n if (marker === '<br>') {\n token = state.tokens[delim.token];\n token.type = 'br_openclose';\n token.tag = 'br';\n token.nesting = 1;\n token.markup = '<br>';\n token.content = '';\n }\n }\n\n return true;\n });\n}\n","/**\n * forked from https://github.com/goessner/markdown-it-mdKatex\n */\n\nimport MarkdownIt from 'markdown-it';\n\ntype PreHandler = (str: string, begin: number) => boolean;\ntype PostHandler = (str: string, begin: number) => boolean;\n\nconst katexClassName = 'zenn-katex';\n\nconst preHandler: PreHandler = function (str, beg) {\n const prv = beg > 0 ? str[beg - 1].charCodeAt(0) : false;\n return (\n !prv ||\n (prv !== 0x5c && // no backslash,\n (prv < 0x30 || prv > 0x39))\n ); // no decimal digit .. before opening '$'\n};\n\nconst postHandler: PostHandler = function (str, end) {\n const nxt = str[end + 1] && str[end + 1].charCodeAt(0);\n return !nxt || nxt < 0x30 || nxt > 0x39; // no decimal digit .. after closing '$'\n};\n\ntype HandlingRule = {\n name: string;\n rex: RegExp;\n tmpl: string;\n tag: string;\n pre?: PreHandler;\n post?: PostHandler;\n};\n\nconst inlineRules: HandlingRule[] = [\n {\n name: 'math_inline_double',\n // maybe unused.\n rex: /\\${2}((?:\\S)|(?:\\S(?!.*\\]\\(http).*?\\S))\\${2}/gy,\n tmpl: `<section class=\"${katexClassName}\"><embed-katex display-mode=\"1\"><eqn>$1</eqn></embed-katex></section>`,\n tag: '$$',\n pre: preHandler,\n post: postHandler,\n },\n {\n name: 'math_inline',\n // fixed so that the expression [$something](https://something.com/$example) is skipped.\n // (?:\\S(?![^$]*\\]\\(http.*) means something like \"](https://hoge.com/hoge)\"\n rex: /\\$((?:\\S)|(?:\\S(?![^$]*\\]\\(http.*).*?\\S))\\$/gy,\n tmpl: `<embed-katex><eq class=\"${katexClassName}\">$1</eq></embed-katex>`,\n tag: '$',\n pre: preHandler,\n post: postHandler,\n },\n];\n\nconst blockRules: HandlingRule[] = [\n {\n name: 'math_block_eqno',\n rex: /\\${2}([^$]+?)\\${2}\\s*?\\(([^)\\s]+?)\\)/gmy,\n tmpl: `<section class=\"${katexClassName} eqno code-line\" $3><eqn><embed-katex display-mode=\"1\">$1</embed-katex></eqn><span>($2)</span></section>`,\n tag: '$$',\n },\n {\n name: 'math_block',\n rex: /\\${2}([^$]+?)\\${2}/gmy,\n tmpl: `<section class=\"${katexClassName} code-line\" $3><eqn><embed-katex display-mode=\"1\">$1</embed-katex></eqn></section>`,\n tag: '$$',\n },\n];\n\nexport function mdKatex(md: MarkdownIt) {\n for (const rule of inlineRules) {\n md.inline.ruler.before('escape', rule.name, function (state, silent) {\n const pos = state.pos;\n const str = state.src;\n const pre =\n str.startsWith(rule.tag, (rule.rex.lastIndex = pos)) &&\n (!rule.pre || rule.pre(str, pos)); // valid pre-condition ...\n const match = pre && rule.rex.exec(str);\n const res =\n !!match &&\n pos < rule.rex.lastIndex &&\n (!rule.post || rule.post(str, rule.rex.lastIndex - 1));\n\n if (res) {\n if (!silent && match) {\n const token = state.push(rule.name, 'math', 0);\n token.content = match[1];\n token.markup = rule.tag;\n }\n state.pos = rule.rex.lastIndex;\n }\n return res;\n }); // ! important\n md.renderer.rules[rule.name] = (tokens, idx) =>\n rule.tmpl.replace(/\\$1/, md.utils.escapeHtml(tokens[idx].content));\n }\n\n for (const rule of blockRules) {\n md.block.ruler.before(\n 'fence',\n rule.name,\n function block(state, begLine, endLine, silent) {\n const pos = state.bMarks[begLine] + state.tShift[begLine];\n const str = state.src;\n const pre =\n str.startsWith(rule.tag, (rule.rex.lastIndex = pos)) &&\n (!rule.pre || rule.pre(str, pos)); // valid pre-condition ....\n const match = pre && rule.rex.exec(str);\n const res =\n !!match &&\n pos < rule.rex.lastIndex &&\n (!rule.post || rule.post(str, rule.rex.lastIndex - 1));\n\n if (res && !silent && match) {\n // match and valid post-condition ...\n const endpos = rule.rex.lastIndex - 1;\n let curline;\n\n for (curline = begLine; curline < endLine; curline++)\n if (\n endpos >= state.bMarks[curline] + state.tShift[curline] &&\n endpos <= state.eMarks[curline]\n )\n // line for end of block math found ...\n break;\n\n // \"this will prevent lazy continuations from ever going past our end marker\"\n // s. https://github.com/markdown-it/markdown-it-container/blob/master/index.js\n const lineMax = state.lineMax;\n const oldParentType = state.parentType;\n state.lineMax = curline;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n state.parentType = 'math' as any;\n\n if (oldParentType === 'blockquote') {\n // remove all leading '>' inside multiline formula\n match[1] = match[1].replace(/(\\n*?^(?:\\s*>)+)/gm, '');\n }\n // begin token\n let token = state.push(rule.name, 'math', 1); // 'math_block'\n token.block = true;\n token.markup = rule.tag;\n token.content = match[1];\n token.info = match[match.length - 1]; // eq.no\n token.map = [begLine, curline];\n // end token\n token = state.push(rule.name + '_end', 'math', -1);\n token.block = true;\n token.markup = rule.tag;\n\n state.parentType = oldParentType;\n state.lineMax = lineMax;\n state.line = curline + 1;\n }\n return res;\n }\n ); // ! important for ```math delimiters\n\n md.renderer.rules[rule.name] = (tokens, idx) =>\n rule.tmpl\n .replace(/\\$2/, md.utils.escapeHtml(tokens[idx].info)) // equation number .. ?\n .replace(/\\$1/, md.utils.escapeHtml(tokens[idx].content))\n .replace(/\\$3/, 'data-line=\"' + tokens[idx].attrGet('data-line') + '\"');\n }\n}\n","import MarkdownIt from 'markdown-it';\nimport { MarkdownOptions } from '../types';\nimport { generateEmbedHTML, isEmbedType } from './embed-helper';\n\n// Forked from: https://github.com/posva/markdown-it-custom-block\nexport function mdCustomBlock(md: MarkdownIt, options?: MarkdownOptions) {\n md.renderer.rules.custom = function tokenizeBlock(tokens, idx) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const { tag, arg }: any = tokens[idx].info;\n\n if (!isEmbedType(tag)) return '';\n if (typeof arg !== 'string') return '';\n\n try {\n return generateEmbedHTML(tag, arg, options || {}) + '\\n';\n } catch (_e) {\n return '';\n }\n };\n\n md.block.ruler.before(\n 'fence',\n 'custom',\n function customEmbed(state, startLine, endLine, silent) {\n const startPos = state.bMarks[startLine] + state.tShift[startLine];\n const maxPos = state.eMarks[startLine];\n const block = state.src.slice(startPos, maxPos);\n const pointer = { line: startLine, pos: startPos };\n\n // Note: skip prev line break check\n // if (startLine !== 0) {\n // let prevLineStartPos =\n // state.bMarks[startLine - 1] + state.tShift[startLine - 1];\n // let prevLineMaxPos = state.eMarks[startLine - 1];\n // if (prevLineMaxPos > prevLineStartPos) return false;\n // }\n\n // Check if it's @[tag](arg)\n if (\n state.src.charCodeAt(pointer.pos) !== 0x40 /* @ */ ||\n state.src.charCodeAt(pointer.pos + 1) !== 0x5b /* [ */\n ) {\n return false;\n }\n\n const embedRE = /@\\[([\\w-]+)\\]\\((.+)\\)/im;\n const match = embedRE.exec(block);\n\n if (!match || match.length < 3) {\n return false;\n }\n\n const [all, tag, arg] = match;\n\n pointer.pos += all.length;\n\n // Note: skip nextline break check\n // if (endLine !== pointer.line + 1) {\n // let nextLineStartPos =\n // state.bMarks[pointer.line + 1] + state.tShift[pointer.line + 1];\n // let nextLineMaxPos = state.eMarks[pointer.line + 1];\n // if (nextLineMaxPos > nextLineStartPos) return false;\n // }\n\n if (pointer.line >= endLine) return false;\n if (!silent) {\n const token = state.push('custom', 'div', 0);\n token.markup = state.src.slice(startPos, pointer.pos);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n token.info = { arg, tag } as any;\n token.block = true;\n token.map = [startLine, pointer.line + 1];\n state.line = pointer.line + 1;\n }\n\n return true;\n },\n { alt: ['paragraph', 'reference', 'blockquote', 'list'] }\n );\n}\n","import MarkdownIt from 'markdown-it';\nimport markdownItLinkAttributes from 'markdown-it-link-attributes';\n\nexport function mdLinkAttributes(md: MarkdownIt) {\n // <a>タグの属性を設定する\n // Ref: https://github.com/crookedneighbor/markdown-it-link-attributes\n md.use(markdownItLinkAttributes, [\n // 内部リンク\n {\n matcher(href: string) {\n return href.match(\n /^(?:https:\\/\\/zenn\\.dev$)|(?:https:\\/\\/zenn\\.dev\\/.*$)/\n );\n },\n attrs: {\n target: '_blank',\n },\n },\n // 外部リンク\n {\n matcher(href: string) {\n return href.match(/^https?:\\/\\//);\n },\n attrs: {\n target: '_blank',\n rel: 'nofollow noopener noreferrer',\n },\n },\n ]);\n}\n","import MarkdownIt from 'markdown-it';\n\n/**\n * Adds begin line index to the output via the 'data-line' data attribute.\n *\n * Ref: https://github.com/microsoft/vscode/blob/84f63bf4e54c60e40865c8c4d8002893a337fe61/extensions/markdown-language-features/src/markdownEngine.ts#L17-L40\n */\nexport function mdSourceMap(md: MarkdownIt): void {\n // Set the attribute on every possible token.\n md.core.ruler.push('source_map_data_attribute', (state): void => {\n for (const token of state.tokens) {\n if (token.map && token.type !== 'inline') {\n token.attrSet('data-line', String(token.map[0]));\n token.attrJoin('class', 'code-line');\n }\n }\n });\n}\n","import MarkdownIt from 'markdown-it';\nimport Token from 'markdown-it/lib/token.mjs';\nimport { MarkdownOptions } from '../types';\nimport { generateLinkifyEmbedHTML } from './embed-helper';\n\nfunction convertAutolinkToEmbed(\n inlineChildTokens: Token[],\n options: MarkdownOptions\n): Token[] {\n const newTokens: Token[] = [];\n\n inlineChildTokens.forEach((token, i) => {\n // 埋め込み対象となるlink_open かつ linkify以外はそのまま出力結果に含める\n if (!(token.type === 'link_open' && token.markup === 'linkify')) {\n newTokens.push(token); // 変換は行わずに出力結果に含める\n return;\n }\n\n const linkOpenToken = token;\n\n // tokenがlinkifyの場合は必要に応じて、カードを生成\n const url = linkOpenToken.attrGet('href');\n if (!url) {\n newTokens.push(token); // 変換は行わずに出力結果に含める\n return;\n }\n\n const isStartOfLine = i === 0;\n const isEndOfLine = i + 2 === inlineChildTokens.length - 1; // i + 2 = link_closeのこと => link_closeが最後のtokenか\n\n const prevToken = isStartOfLine ? null : inlineChildTokens[i - 1]; // e.g. [✋, link_open, text, link_close]\n const nextToken = isEndOfLine ? null : inlineChildTokens[i + 3]; // e.g. [text, link_open, text, link_close, ✋]\n\n const isPrevBr = prevToken?.tag === 'br';\n const isNextBr = nextToken?.tag === 'br';\n\n // 以下の2つをどちらも満たした場合にリンク化\n // 1. パラグラフ先頭 もしくは リンクの前が br\n // 2. パラグラフの末尾 もしくは リンクの後が br\n\n const shouldConvertToCard =\n (isStartOfLine || isPrevBr) && (isEndOfLine || isNextBr);\n\n if (!shouldConvertToCard) {\n newTokens.push(token); // 変換は行わずに出力結果に含める\n return;\n }\n\n // 埋め込み用のHTMLを生成\n const embedToken = new Token('html_inline', '', 0);\n\n // 埋め込み要素のHTML生成\n embedToken.content = generateLinkifyEmbedHTML(url, options);\n\n // a要素自体はカードにより不要になるため非表示に\n linkOpenToken.attrJoin('style', 'display: none');\n\n // カードとリンクのトークンを出力結果のtokenに追加\n newTokens.push(embedToken, linkOpenToken);\n\n // 前後のbrタグはスペースを広げすぎてしまうため非表示にしておく\n if (nextToken && isNextBr) {\n nextToken.type = 'html_inline';\n nextToken.content = '<br style=\"display: none\">\\n';\n }\n if (prevToken && isPrevBr) {\n prevToken.type = 'html_inline';\n prevToken.content = '<br style=\"display: none\">\\n';\n }\n });\n return newTokens;\n}\n\nexport function mdLinkifyToCard(md: MarkdownIt, options?: MarkdownOptions) {\n md.core.ruler.after('replacements', 'link-to-card', function ({ tokens }) {\n // 埋め込みを許可するネストレベル\n let allowLevel = 0;\n\n // 本文内のすべてのtokenをチェック\n tokens.forEach((token, i) => {\n if (token.type === 'container_details_open') {\n allowLevel++;\n return;\n }\n if (token.type === 'container_details_close' && allowLevel > 0) {\n allowLevel--;\n return;\n }\n\n // autolinkはinline内のchildrenにのみ存在\n if (token.type !== 'inline') return;\n\n // childrenが存在しない場合は変換しない\n const children = token.children;\n if (!children) return;\n\n // childrenにautolinkが存在する場合のみ変換\n const hasAnyAutolink = children?.some(\n (child) => child.markup === 'linkify'\n );\n if (!hasAnyAutolink) return;\n\n // 親がコンテンツ直下のp要素の場合のみ変換\n const parentToken = tokens[i - 1];\n const isParentRootParagraph =\n parentToken &&\n parentToken.type === 'paragraph_open' &&\n parentToken.level === allowLevel;\n if (!isParentRootParagraph) return;\n\n token.children = convertAutolinkToEmbed(children, options || {});\n });\n\n return true;\n });\n}\n","/**\n * Shiki によるシンタックスハイライト処理\n *\n * このモジュールは Phase 2(applyHighlighting)から呼び出され、\n * 個々のコードブロックをハイライトする役割を持つ。\n *\n * ## 特徴\n *\n * - シングルトン: ハイライターインスタンスは1つだけ作成され再利用される\n * - 遅延ロード: 言語定義は初回使用時にのみロードされる\n * - diff サポート: ベース言語のハイライト + diff 背景色の両方を適用\n * - transformers: Shiki の transformers API で AST レベルの変換を実行\n *\n * ## 関連ファイル\n *\n * - `md-renderer-fence.ts`: Phase 1(収集)と Phase 3(置換)\n * - `index.ts`: 全体の統合\n */\n\nimport {\n createHighlighter,\n Highlighter,\n bundledLanguages,\n BundledLanguage,\n ShikiTransformer,\n} from 'shiki';\nimport { createJavaScriptRegexEngine } from 'shiki/engine/javascript';\n\n/**\n * Shiki ハイライターの初期化 Promise をキャッシュ\n *\n * 注: インスタンスではなく Promise をキャッシュすることで、\n * Promise.all による並列処理時の競合状態を防ぐ。\n *\n * 問題のあるパターン:\n * let instance = null;\n * if (instance) return instance;\n * instance = await createHighlighter(); // ← await 中に他の呼び出しが来る\n *\n * 正しいパターン:\n * let promise = null;\n * if (!promise) promise = createHighlighter(); // ← await しない\n * return promise; // ← 同じ Promise を返す\n */\nlet highlighterPromise: Promise<Highlighter> | null = null;\n\nconst SHIKI_THEME = 'github-dark';\n\n/**\n * github-dark テーマの背景色\n * @see https://github.com/shikijs/textmate-grammars-themes/blob/main/packages/tm-themes/themes/github-dark.json\n */\nconst SHIKI_THEME_BG_COLOR = '#24292e';\n\n/**\n * コードブロックの背景色\n * CSS変数 --c-bg-code-block より少し暗めに調整\n * @see packages/zenn-content-css/src/index.scss\n */\nconst CODE_BLOCK_BG_COLOR = '#151e2c';\n\n/**\n * github-dark テーマのコメント色\n */\nconst SHIKI_THEME_COMMENT_COLOR = '#6a737d';\n\n/**\n * コントラスト改善後のコメント色\n * github-dark-default テーマのコメント色(#8b949e)より明るく調整\n */\nconst COMMENT_COLOR = '#a0aab5';\n\n/** ブラウザ環境かどうかを判定 */\n// @ts-expect-error: window is not defined in Node.js types\nconst isBrowser = typeof window !== 'undefined';\n\n/**\n * Shiki ハイライターを初期化する\n * 最初は最低限のセットで初期化し、必要に応じて言語をロードする\n *\n * ブラウザ環境では JavaScript エンジンを使用(WASM 不要)\n * Node.js 環境では Oniguruma エンジンを使用(デフォルト)\n */\nexport async function getHighlighter(): Promise<Highlighter> {\n if (!highlighterPromise) {\n // Promise をキャッシュ(await しない)\n highlighterPromise = createHighlighter({\n themes: [SHIKI_THEME],\n langs: [],\n // ブラウザ環境では JavaScript エンジンを使用\n // forgiving: true で変換できないパターンもベストエフォートで処理\n ...(isBrowser && {\n engine: createJavaScriptRegexEngine({ forgiving: true }),\n }),\n });\n }\n\n return highlighterPromise;\n}\n\n/**\n * 言語がサポートされているかチェックし、必要に応じてロードする\n */\nasync function ensureLanguageLoaded(\n highlighter: Highlighter,\n langName: string\n): Promise<boolean> {\n // 既にロード済みかチェック\n const loadedLangs = highlighter.getLoadedLanguages();\n if (loadedLangs.includes(langName)) {\n return true;\n }\n\n // bundledLanguages に含まれているかチェック\n if (langName in bundledLanguages) {\n await highlighter.loadLanguage(langName as BundledLanguage);\n return true;\n }\n\n return false;\n}\n\n/**\n * ハイライトオプション\n */\nexport interface HighlightOptions {\n /** diff モードかどうか */\n hasDiff: boolean;\n /** Markdown ソースの行番号(ソースマップ用) */\n line?: number;\n}\n\n/**\n * diff プレフィックスの定義\n * Prism.js の diff-highlight プラグインと互換性を持たせる\n */\nconst DIFF_PREFIXES = {\n // 削除行\n '-': 'remove', // deleted-sign\n '<': 'remove', // deleted-arrow\n // 挿入行\n '+': 'add', // inserted-sign\n '>': 'add', // inserted-arrow\n} as const;\n\n/** コンテキスト行(変更なし)のプレフィックス */\nconst DIFF_CONTEXT_PREFIX = ' ';\n\n/**\n * diff 行スタイルを適用する transformer を作成\n * 行頭のプレフィックス (+, -, <, >, スペース) を検出して処理\n * - +, -, <, >: 挿入/削除のクラスを追加し、プレフィックスをラップ\n * - スペース: プレフィックスのみラップ(コンテキスト行)\n */\nfunction createDiffTransformer(): ShikiTransformer {\n return {\n line(node, lineNumber) {\n // ソースコードの該当行を取得\n const lines = this.source.split('\\n');\n const lineText = lines[lineNumber - 1] ?? '';\n const firstChar = lineText.charAt(0);\n\n if (firstChar in DIFF_PREFIXES) {\n // 追加/削除行\n this.addClassToHast(node, 'diff');\n this.addClassToHast(\n node,\n DIFF_PREFIXES[firstChar as keyof typeof DIFF_PREFIXES]\n );\n wrapDiffPrefix(node, firstChar);\n } else if (firstChar === DIFF_CONTEXT_PREFIX) {\n // コンテキスト行(先頭スペース)\n wrapDiffPrefix(node, firstChar);\n }\n },\n };\n}\n\n/**\n * 行の最初の文字(diff プレフィックス)を別の span 要素にラップする\n * これにより CSS で user-select: none を適用可能になる\n */\nfunction wrapDiffPrefix(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n lineNode: any,\n prefix: string\n): void {\n const line = lineNode;\n\n if (!line.children || line.children.length === 0) return;\n\n const firstChild = line.children[0];\n\n // 最初の子要素がテキストノードの場合(実際には発生しないはずだが念の為)\n if (firstChild.type === 'text' && firstChild.value.startsWith(prefix)) {\n // プレフィックスを分離\n const prefixSpan = {\n type: 'element',\n tagName: 'span',\n properties: { class: 'diff-prefix' },\n children: [{ type: 'text', value: prefix }],\n };\n firstChild.value = firstChild.value.slice(1);\n\n // 空になった場合は削除\n if (firstChild.value === '') {\n line.children.shift();\n }\n\n // プレフィックス span を先頭に挿入\n line.children.unshift(prefixSpan);\n return;\n }\n\n // 最初の子要素が element(span など)の場合\n if (\n firstChild.type === 'element' &&\n firstChild.children &&\n firstChild.children.length > 0\n ) {\n const innerFirst = firstChild.children[0];\n if (innerFirst.type === 'text' && innerFirst.value.startsWith(prefix)) {\n // プレフィックスを分離\n const prefixSpan = {\n type: 'element',\n tagName: 'span',\n properties: { class: 'diff-prefix' },\n children: [{ type: 'text', value: prefix }],\n };\n innerFirst.value = innerFirst.value.slice(1);\n\n // 空になった場合は削除\n if (innerFirst.value === '') {\n firstChild.children.shift();\n }\n\n // プレフィックス span を先頭に挿入\n line.children.unshift(prefixSpan);\n }\n }\n}\n\n/**\n * code タグにクラスと属性を追加する transformer を作成\n */\nfunction createCodeTransformer(options: { line?: number }): ShikiTransformer {\n const { line } = options;\n return {\n code(node) {\n this.addClassToHast(node, 'code-line');\n if (line !== undefined) {\n node.properties['data-line'] = line;\n }\n },\n };\n}\n\n/**\n * [Phase 2 の実処理] コードをハイライトする\n *\n * applyHighlighting() から各コードブロックに対して呼び出される。\n * 言語が未ロードの場合は自動的にロードする(遅延ロード)。\n * Shiki の transformers API を使用して AST レベルで変換を行う。\n *\n * @param text - ハイライト対象のコード文字列\n * @param langName - 言語名(例: \"javascript\", \"python\")\n * @param options - ハイライトオプション\n * @returns ハイライト済み HTML(常に <pre><code> 構造)\n */\nexport async function highlight(\n text: string,\n langName: string,\n options: HighlightOptions\n): Promise<string> {\n const { hasDiff, line } = options;\n const highlighter = await getHighlighter();\n\n // 言語がサポートされているか確認し、必要に応じてロード\n const isSupported = langName\n ? await ensureLanguageLoaded(highlighter, langName)\n : false;\n\n // サポートされていない言語は text(プレーンテキスト)として処理\n // ref: https://shiki.style/languages#plain-text\n const lang = isSupported ? langName : 'text';\n if (!isSupported) {\n await ensureLanguageLoaded(highlighter, 'text');\n }\n\n // transformers を構築\n const transformers: ShikiTransformer[] = [createCodeTransformer({ line })];\n if (hasDiff) {\n transformers.push(createDiffTransformer());\n }\n\n return highlighter.codeToHtml(text, {\n lang,\n theme: SHIKI_THEME,\n transformers,\n colorReplacements: {\n [SHIKI_THEME_BG_COLOR]: CODE_BLOCK_BG_COLOR,\n [SHIKI_THEME_COMMENT_COLOR]: COMMENT_COLOR,\n },\n });\n}\n","/**\n * コードブロックのレンダリングとシンタックスハイライト\n *\n * ## 非同期処理アーキテクチャの概要\n *\n * Shiki(シンタックスハイライター)は非同期APIを持つが、\n * markdown-it のレンダラーは同期的に文字列を返す必要がある。\n * この制約を解決するため、プレースホルダー方式を採用している。\n *\n * ### 処理フロー(3フェーズ)\n *\n * ```\n * [Phase 1: 収集] markdown-it レンダリング(同期)\n * ↓\n * コードブロックを検出するたびに:\n * 1. コードブロック情報を配列に保存\n * 2. プレースホルダー(HTMLコメント)を返す\n * ↓\n * 出力: プレースホルダー付きHTML + コードブロック情報配列\n *\n * [Phase 2: ハイライト] Shiki によるハイライト(非同期・並列)\n * ↓\n * Promise.all で全コードブロックを並列処理\n * ↓\n * 出力: ハイライト済みHTML配列\n *\n * [Phase 3: 置換] プレースホルダーを置換(同期)\n * ↓\n * プレースホルダーをハイライト済みHTMLに置換\n * ↓\n * 出力: 最終HTML\n * ```\n *\n * ### この方式のメリット\n *\n * 1. 同期/非同期の不一致を解決: markdown-it の同期的なプラグインシステムを維持\n * 2. 並列処理: 複数のコードブロックを Promise.all で同時にハイライト\n * 3. 遅延ロード: Shiki の言語定義を必要に応じてロード(メモリ効率)\n *\n * ### 関連ファイル\n *\n * - `index.ts`: markdownToHtml() - 3フェーズを統合\n * - `highlight.ts`: highlight() - Shiki によるハイライト処理\n * - `md-renderer-fence.ts`: このファイル - Phase 1 と 3 を担当\n */\n\nimport MarkdownIt from 'markdown-it';\nimport { md } from './markdown-it';\nimport { MarkdownOptions } from '../types';\nimport { highlight } from './highlight';\n\n/**\n * コードブロック情報を保存するインターフェース\n * Phase 1 で収集し、Phase 2 でハイライト処理に使用\n */\nexport interface CodeBlockInfo {\n content: string;\n langName: string;\n hasDiff: boolean;\n fileName?: string;\n line?: number;\n placeholder: string;\n}\n\n// プレースホルダーのプレフィックス\nconst PLACEHOLDER_PREFIX = '<!--SHIKI_CODE_BLOCK_';\nconst PLACEHOLDER_SUFFIX = '-->';\n\n/**\n * ランダムな8文字の文字列を生成する\n */\nfunction generateRandomId(): string {\n return Math.random().toString(36).slice(2, 10);\n}\n\n/**\n * プレースホルダーを生成する\n * ユーザーが本文中に同じ文字列を書いても衝突しないようランダムIDを使用\n */\nfunction createPlaceholder(): string {\n return `${PLACEHOLDER_PREFIX}${generateRandomId()}${PLACEHOLDER_SUFFIX}`;\n}\n\n/**\n * コードブロックの HTML を生成する\n * Shiki の出力(<pre><code>...</code></pre>)を外側のコンテナでラップする\n * 注: <pre> や <code> へのクラス・属性追加は highlight() の transformers で行う\n */\nfunction wrapHighlightedCode({\n highlightedHtml,\n fileName,\n}: {\n highlightedHtml: string;\n fileName?: string;\n}): string {\n // ファイル名コンテナを追加\n const fileNameHtml = fileName\n ? `<div class=\"code-block-filename-container\"><span class=\"code-block-filename\">${md.utils.escapeHtml(\n fileName\n )}</span></div>`\n : '';\n\n return `<div class=\"code-block-container\">${fileNameHtml}${highlightedHtml}</div>`;\n}\n\n/**\n * エラー時のフォールバック HTML を生成\n * Shiki でのハイライトに失敗した場合に使用\n */\nfunction getPlainHtml({\n content,\n fileName,\n line,\n}: {\n content: string;\n fileName?: string;\n line?: number;\n}): string {\n const escapedContent = md.utils.escapeHtml(content);\n const lineAttr = line !== undefined ? ` data-line=\"${line}\"` : '';\n\n const preHtml = `<pre><code class=\"code-line\"${lineAttr}>${escapedContent}</code></pre>`;\n\n return wrapHighlightedCode({ highlightedHtml: preHtml, fileName });\n}\n\n// Shiki がネイティブサポートしていない言語のフォールバック\nconst fallbackLanguages: {\n [key: string]: string;\n} = {\n react: 'jsx',\n cwl: 'yaml',\n};\n\nfunction normalizeLangName(str?: string): string {\n if (!str?.length) return '';\n const langName = str.toLocaleLowerCase();\n return fallbackLanguages[langName] ?? langName;\n}\n\nexport function parseInfo(str: string): {\n hasDiff: boolean;\n langName: string;\n fileName?: string;\n} {\n if (str.trim() === '') {\n return {\n langName: '',\n fileName: undefined,\n hasDiff: false,\n };\n }\n\n // e.g. foo:filename => [\"foo\", \"filename\"]\n // e.g. foo diff:filename => [\"foo diff\", \"filename\"]\n // e.g. foo:filename:bar => [\"foo\", \"filename:bar\"]\n const separatorIndex = str.indexOf(':');\n const langInfo = separatorIndex > -1 ? str.substring(0, separatorIndex) : str;\n const fileName =\n separatorIndex > -1 ? str.substring(separatorIndex + 1) : undefined;\n\n const langNames = langInfo.split(' ');\n const hasDiff = langNames.some((name) => name === 'diff');\n\n const langName: undefined | string = hasDiff\n ? langNames.find((lang) => lang !== 'diff')\n : langNames[0];\n\n return {\n langName: normalizeLangName(langName),\n fileName,\n hasDiff,\n };\n}\n\n/**\n * [Phase 1] markdown-it にコードブロックのレンダラーを登録する\n *\n * markdown-it がコードブロック(```)を検出するたびに呼ばれ、\n * 以下の処理を行う:\n * 1. コードブロックの情報(内容、言語、diff有無など)を codeBlocks 配列に追加\n * 2. プレースホルダー(例: <!--SHIKI_CODE_BLOCK_xxxxxxxx-->)を返す\n *\n * このレンダラーは同期的に動作し、実際のハイライト処理は\n * Phase 2(applyHighlighting)で非同期に行われる。\n *\n * @param md - markdown-it インスタンス\n * @param options - Markdown 変換オプション\n * @param codeBlocks - コードブロック情報を格納する配列(副作用で変更される)\n */\nexport function mdRendererFence(\n md: MarkdownIt,\n options: MarkdownOptions,\n codeBlocks: CodeBlockInfo[]\n) {\n // override fence\n md.renderer.rules.fence = function (...args) {\n const [tokens, idx] = args;\n const { info, content } = tokens[idx];\n const { langName, fileName, hasDiff } = parseInfo(info);\n\n if (langName === 'mermaid') {\n const generator = options.customEmbed?.mermaid;\n // generator が(上書きされて)定義されてない場合はそのまま出力する\n return generator ? generator(content.trim(), options) : content;\n }\n\n const fenceStart = tokens[idx].map?.[0];\n const placeholder = createPlaceholder();\n\n codeBlocks.push({\n content,\n langName,\n hasDiff,\n fileName,\n line: fenceStart,\n placeholder,\n });\n return placeholder;\n };\n}\n\n/**\n * [Phase 2 & 3] プレースホルダーをハイライトされたコードに置換する\n *\n * Phase 2: 全コードブロックを Shiki で並列ハイライト\n * - Promise.all により、複数のコードブロックを同時に処理\n * - 各コードブロックに対して highlight() を呼び出し\n * - 言語が未ロードの場合は自動的にロード(遅延ロード)\n *\n * Phase 3: プレースホルダーを置換\n * - <!--SHIKI_CODE_BLOCK_xxxxxxxx--> を実際のハイライト済み HTML に置換\n *\n * @param html - プレースホルダーを含む HTML 文字列\n * @param codeBlocks - Phase 1 で収集したコードブロック情報の配列\n * @returns ハイライト済みの完全な HTML 文字列\n */\nexport async function applyHighlighting(\n html: string,\n codeBlocks: CodeBlockInfo[]\n): Promise<string> {\n // すべてのコードブロックを並列でハイライト\n const highlightedBlocks = await Promise.all(\n codeBlocks.map(async (block) => {\n try {\n const highlightedHtml = await highlight(block.content, block.langName, {\n hasDiff: block.hasDiff,\n line: block.line,\n });\n\n return wrapHighlightedCode({\n highlightedHtml,\n fileName: block.fileName,\n });\n } catch {\n // エラー時はプレーンテキストとして出力\n return getPlainHtml({\n content: block.content,\n fileName: block.fileName,\n line: block.line,\n });\n }\n })\n );\n\n // プレースホルダーを置換\n // 注: replace の第2引数を関数にすることで、$' や $` などの\n // 特殊パターン解釈を防ぐ(コードブロック内に $ が含まれる場合の対策)\n let result = html;\n for (let i = 0; i < highlightedBlocks.length; i++) {\n result = result.replace(\n codeBlocks[i].placeholder,\n () => highlightedBlocks[i]\n );\n }\n\n return result;\n}\n","import MarkdownIt from 'markdown-it';\nimport type { RenderRule } from 'markdown-it/lib/renderer.mjs';\n\nexport const mdImage = (md: MarkdownIt): void => {\n const originalImageRenderRule = md.renderer.rules['image'] as RenderRule;\n\n md.renderer.rules.image = (tokens, idx, options, env, slf) => {\n const token = tokens[idx];\n\n token.attrJoin('class', 'md-img');\n token.attrSet('loading', 'lazy');\n\n return originalImageRenderRule(tokens, idx, options, env, slf);\n };\n};\n","import { md } from './markdown-it';\nimport type Token from 'markdown-it/lib/token.mjs';\n\n// containers\n// ref: https://github.com/markdown-it/markdown-it-container\n\n// ::: details Detail\n// summary comes here\n// :::\nexport const containerDetailsOptions = {\n validate: function (params: string) {\n return /^details\\s+(.*)$/.test(params.trim());\n },\n render: function (tokens: Token[], idx: number) {\n const m = tokens[idx].info.trim().match(/^details\\s+(.*)$/);\n const summary = m?.[1] || '';\n if (tokens[idx].nesting === 1) {\n // opening tag\n return (\n '<details><summary>' +\n md.utils.escapeHtml(summary) +\n '</summary><div class=\"details-content\">'\n );\n } else {\n // closing tag\n return '</div></details>\\n';\n }\n },\n};\n// ::: message alert\n// text\n// :::\nconst msgClassRegex = /^message\\s*(alert)?$/;\n\nexport const containerMessageOptions = {\n validate: function (params: string) {\n return msgClassRegex.test(params.trim());\n },\n render: function (tokens: Token[], idx: number) {\n const m = tokens[idx].info.trim().match(msgClassRegex);\n const messageName = m?.[1] === 'alert' ? 'alert' : 'message';\n\n if (tokens[idx].nesting === 1) {\n // opening tag\n const symbol = `<span class=\"msg-symbol\">!</span>`;\n return `<aside class=\"msg ${messageName}\">${symbol}<div class=\"msg-content\">`;\n } else {\n // closing tag\n return `</div></aside>\\n`;\n }\n },\n};\n","import MarkdownIt from 'markdown-it';\nimport { mdLinkAttributes } from './utils/md-link-attributes';\nimport { sanitize } from './sanitizer';\n\n// preset 'zero' はデフォルトで全ての変換を無効化したプリセットです。\n// Ref: https://github.com/markdown-it/markdown-it/blob/master/lib/presets/zero.js\nconst md = MarkdownIt('zero', {\n breaks: true, // 改行を<br>に変換する\n linkify: true, // URLをリンクに変換する\n});\n\nmd.enable('emphasis'); // 太字と斜体を有効化\nmd.enable('link'); // リンクを有効化\nmd.enable('list'); // リストを有効化\n// 改行コードを<br>に変換する('zero'presetの場合、newlineを有効化する必要がある)\n// Ref: https://github.com/markdown-it/markdown-it/issues/491\nmd.enable('newline');\n// linkify を有効化('zero'presetの場合、linkifyを有効化する必要がある)\n// Ref: https://github.com/markdown-it/markdown-it/issues/396\nmd.enable('linkify');\n\n// fuzzyLink - recognize URL-s without http(s):// head. Default true.\n// Ref: http://markdown-it.github.io/linkify-it/doc/#LinkifyIt.prototype.set\nmd.linkify.set({ fuzzyLink: false });\n\nmd.use(mdLinkAttributes);\n\n// 限られた記法のみをHTMLに変換するパーサー\nexport const markdownToSimpleHtml = (text: string): string => {\n if (!(text && text.length)) return '';\n\n return sanitize(md.render(text));\n};\n"],"mappings":"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","names":["md","md","md","md","md","md","md","md","md","md","md"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"highlight.d.ts","sourceRoot":"","sources":["../../src/utils/highlight.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAEL,WAAW,EAIZ,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"highlight.d.ts","sourceRoot":"","sources":["../../src/utils/highlight.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAEL,WAAW,EAIZ,MAAM,OAAO,CAAC;AAmDf;;;;;;GAMG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC,CAe3D;AAwBD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,mBAAmB;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,gCAAgC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AA+HD;;;;;;;;;;;GAWG;AACH,wBAAsB,SAAS,CAC7B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,MAAM,CAAC,CA+BjB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zenn-markdown-html",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Convert markdown to zenn flavor html.",
|
|
6
6
|
"type": "module",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"sanitize-html": "^2.17.0",
|
|
74
74
|
"shiki": "^3.21.0"
|
|
75
75
|
},
|
|
76
|
-
"gitHead": "
|
|
76
|
+
"gitHead": "35cdba273c40855cd4e89359b6a316bf92644810",
|
|
77
77
|
"publishConfig": {
|
|
78
78
|
"access": "public"
|
|
79
79
|
}
|