zenn-markdown-html 0.2.11 → 0.2.12-alpha.0

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/lib/index.d.ts CHANGED
@@ -1,4 +1,15 @@
1
1
  import { MarkdownOptions } from './types';
2
- declare const markdownToHtml: (text: string, options?: MarkdownOptions) => string;
2
+ /**
3
+ * Markdown を HTML に変換する(非同期)
4
+ *
5
+ * Shiki によるシンタックスハイライトを使用。
6
+ * 詳細なアーキテクチャについては md-renderer-fence.ts のコメントを参照。
7
+ *
8
+ * 処理フロー:
9
+ * 1. [Phase 1] md.render() - Markdown を HTML に変換(コードブロックはプレースホルダーに)
10
+ * 2. [Phase 2 & 3] applyHighlighting() - プレースホルダーをハイライト済み HTML に置換
11
+ * 3. sanitize() - XSS 対策のためサニタイズ
12
+ */
13
+ declare const markdownToHtml: (text: string, options?: MarkdownOptions) => Promise<string>;
3
14
  export default markdownToHtml;
4
15
  export { markdownToSimpleHtml } from './markdown-to-simple-html';
package/lib/index.js CHANGED
@@ -27,13 +27,25 @@ var _mdImage = require("./utils/md-image");
27
27
  var _mdContainer = require("./utils/md-container");
28
28
  var _markdownToSimpleHtml = require("./markdown-to-simple-html");
29
29
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
30
- // plugis
30
+ // plugins
31
31
 
32
32
  const mdContainer = require('markdown-it-container');
33
33
  const mdFootnote = require('markdown-it-footnote');
34
34
  const mdTaskLists = require('markdown-it-task-lists');
35
35
  const mdInlineComments = require('markdown-it-inline-comments');
36
- const markdownToHtml = (text, options) => {
36
+
37
+ /**
38
+ * Markdown を HTML に変換する(非同期)
39
+ *
40
+ * Shiki によるシンタックスハイライトを使用。
41
+ * 詳細なアーキテクチャについては md-renderer-fence.ts のコメントを参照。
42
+ *
43
+ * 処理フロー:
44
+ * 1. [Phase 1] md.render() - Markdown を HTML に変換(コードブロックはプレースホルダーに)
45
+ * 2. [Phase 2 & 3] applyHighlighting() - プレースホルダーをハイライト済み HTML に置換
46
+ * 3. sanitize() - XSS 対策のためサニタイズ
47
+ */
48
+ const markdownToHtml = async (text, options) => {
37
49
  if (!(text && text.length)) return '';
38
50
  const markdownOptions = {
39
51
  ...options,
@@ -53,7 +65,10 @@ const markdownToHtml = (text, options) => {
53
65
  fuzzyEmail: false
54
66
  }); // refs: https://github.com/markdown-it/linkify-it
55
67
 
56
- md.use(_mdBr.mdBr).use(_mdKatex.mdKatex).use(mdFootnote).use(mdInlineComments).use(_markdownItImsize.default).use(_mdLinkAttributes.mdLinkAttributes).use(_mdCustomBlock.mdCustomBlock, markdownOptions).use(_mdRendererFence.mdRendererFence, markdownOptions).use(_mdLinkifyToCard.mdLinkifyToCard, markdownOptions).use(mdTaskLists, {
68
+ // コードブロック情報を保存する配列
69
+ // Phase 1 で mdRendererFence によって追加され、Phase 2 でハイライト処理に使用される
70
+ const codeBlocks = [];
71
+ md.use(_mdBr.mdBr).use(_mdKatex.mdKatex).use(mdFootnote).use(mdInlineComments).use(_markdownItImsize.default).use(_mdLinkAttributes.mdLinkAttributes).use(_mdCustomBlock.mdCustomBlock, markdownOptions).use(_mdRendererFence.mdRendererFence, markdownOptions, codeBlocks).use(_mdLinkifyToCard.mdLinkifyToCard, markdownOptions).use(mdTaskLists, {
57
72
  enabled: true
58
73
  }).use(mdContainer, 'details', _mdContainer.containerDetailsOptions).use(mdContainer, 'message', _mdContainer.containerMessageOptions).use(_markdownItAnchor.default, {
59
74
  level: [1, 2, 3, 4],
@@ -73,8 +88,25 @@ const markdownToHtml = (text, options) => {
73
88
  // - https://github.com/zenn-dev/zenn-community/issues/356
74
89
  // - https://github.com/markdown-it/markdown-it-footnote/pull/8
75
90
  const docId = _crypto.default.randomBytes(2).toString('hex');
76
- return (0, _sanitizer.sanitize)(md.render(text, {
91
+
92
+ // ============================================================
93
+ // Phase 1: Markdown → HTML 変換(同期)
94
+ // ============================================================
95
+ // markdown-it がコードブロックを検出すると mdRendererFence が呼ばれ、
96
+ // コードブロック情報が codeBlocks 配列に保存され、
97
+ // HTML にはプレースホルダー(<!--SHIKI_CODE_BLOCK_xxxxxxxx-->)が挿入される
98
+ const rawHtml = md.render(text, {
77
99
  docId
78
- }));
100
+ });
101
+
102
+ // ============================================================
103
+ // Phase 2 & 3: シンタックスハイライト適用(非同期)
104
+ // ============================================================
105
+ // - Phase 2: 全コードブロックを Shiki で並列ハイライト
106
+ // - Phase 3: プレースホルダーをハイライト済み HTML に置換
107
+ const highlightedHtml = await (0, _mdRendererFence.applyHighlighting)(rawHtml, codeBlocks);
108
+
109
+ // サニタイズして返す(XSS 対策)
110
+ return (0, _sanitizer.sanitize)(highlightedHtml);
79
111
  };
80
112
  var _default = exports.default = markdownToHtml;
package/lib/sanitizer.js CHANGED
@@ -33,10 +33,10 @@ const attributes = {
33
33
  li: ['class', 'id', 'data-line'],
34
34
  ol: ['class', 'start', 'data-line'],
35
35
  p: ['class', 'data-line'],
36
- pre: ['class'],
36
+ pre: ['class', 'style'],
37
37
  s: [],
38
38
  section: ['class', 'data-line'],
39
- span: ['class', 'title'],
39
+ span: ['class', 'style', 'title'],
40
40
  strong: [],
41
41
  summary: [],
42
42
  sup: ['class'],
@@ -1 +1,48 @@
1
- export declare function highlight(text: string, langName: string, hasDiff: boolean): string;
1
+ /**
2
+ * Shiki によるシンタックスハイライト処理
3
+ *
4
+ * このモジュールは Phase 2(applyHighlighting)から呼び出され、
5
+ * 個々のコードブロックをハイライトする役割を持つ。
6
+ *
7
+ * ## 特徴
8
+ *
9
+ * - シングルトン: ハイライターインスタンスは1つだけ作成され再利用される
10
+ * - 遅延ロード: 言語定義は初回使用時にのみロードされる
11
+ * - diff サポート: ベース言語のハイライト + diff 背景色の両方を適用
12
+ * - transformers: Shiki の transformers API で AST レベルの変換を実行
13
+ *
14
+ * ## 関連ファイル
15
+ *
16
+ * - `md-renderer-fence.ts`: Phase 1(収集)と Phase 3(置換)
17
+ * - `index.ts`: 全体の統合
18
+ */
19
+ import { Highlighter } from 'shiki';
20
+ /**
21
+ * Shiki ハイライターを初期化する
22
+ * 最初は最低限のセットで初期化し、必要に応じて言語をロードする
23
+ */
24
+ export declare function getHighlighter(): Promise<Highlighter>;
25
+ /**
26
+ * ハイライトオプション
27
+ */
28
+ export interface HighlightOptions {
29
+ /** diff モードかどうか */
30
+ hasDiff: boolean;
31
+ /** 追加するクラス名 */
32
+ className: string;
33
+ /** Markdown ソースの行番号(ソースマップ用) */
34
+ line?: number;
35
+ }
36
+ /**
37
+ * [Phase 2 の実処理] コードをハイライトする
38
+ *
39
+ * applyHighlighting() から各コードブロックに対して呼び出される。
40
+ * 言語が未ロードの場合は自動的にロードする(遅延ロード)。
41
+ * Shiki の transformers API を使用して AST レベルで変換を行う。
42
+ *
43
+ * @param text - ハイライト対象のコード文字列
44
+ * @param langName - 言語名(例: "javascript", "python")
45
+ * @param options - ハイライトオプション
46
+ * @returns ハイライト済み HTML(常に <pre><code> 構造)
47
+ */
48
+ export declare function highlight(text: string, langName: string, options: HighlightOptions): Promise<string>;