zenn-markdown-html 0.2.11 → 0.2.12-alpha.1
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 +12 -1
- package/lib/index.js +37 -5
- package/lib/sanitizer.js +2 -2
- package/lib/utils/highlight.d.ts +48 -1
- package/lib/utils/highlight.js +254 -321
- package/lib/utils/md-renderer-fence.d.ts +89 -1
- package/lib/utils/md-renderer-fence.js +176 -20
- package/package.json +4 -6
- package/lib/prism-plugins/prism-diff-highlight.d.ts +0 -7
- package/lib/prism-plugins/prism-diff-highlight.js +0 -403
package/lib/utils/highlight.js
CHANGED
|
@@ -3,329 +3,262 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
+
exports.getHighlighter = getHighlighter;
|
|
6
7
|
exports.highlight = highlight;
|
|
7
|
-
var
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
require("prismjs/components/prism-n1ql");
|
|
192
|
-
require("prismjs/components/prism-nand2tetris-hdl");
|
|
193
|
-
require("prismjs/components/prism-naniscript");
|
|
194
|
-
require("prismjs/components/prism-nasm");
|
|
195
|
-
require("prismjs/components/prism-neon");
|
|
196
|
-
require("prismjs/components/prism-nevod");
|
|
197
|
-
require("prismjs/components/prism-nginx");
|
|
198
|
-
require("prismjs/components/prism-nim");
|
|
199
|
-
require("prismjs/components/prism-nix");
|
|
200
|
-
require("prismjs/components/prism-nsis");
|
|
201
|
-
require("prismjs/components/prism-objectivec");
|
|
202
|
-
require("prismjs/components/prism-ocaml");
|
|
203
|
-
require("prismjs/components/prism-odin");
|
|
204
|
-
require("prismjs/components/prism-opencl");
|
|
205
|
-
require("prismjs/components/prism-openqasm");
|
|
206
|
-
require("prismjs/components/prism-oz");
|
|
207
|
-
require("prismjs/components/prism-parigp");
|
|
208
|
-
require("prismjs/components/prism-parser");
|
|
209
|
-
require("prismjs/components/prism-pascal");
|
|
210
|
-
require("prismjs/components/prism-pascaligo");
|
|
211
|
-
require("prismjs/components/prism-psl");
|
|
212
|
-
require("prismjs/components/prism-pcaxis");
|
|
213
|
-
require("prismjs/components/prism-peoplecode");
|
|
214
|
-
require("prismjs/components/prism-perl");
|
|
215
|
-
require("prismjs/components/prism-phpdoc");
|
|
216
|
-
require("prismjs/components/prism-php-extras");
|
|
217
|
-
require("prismjs/components/prism-plant-uml");
|
|
218
|
-
require("prismjs/components/prism-plsql");
|
|
219
|
-
require("prismjs/components/prism-powerquery");
|
|
220
|
-
require("prismjs/components/prism-powershell");
|
|
221
|
-
require("prismjs/components/prism-processing");
|
|
222
|
-
require("prismjs/components/prism-prolog");
|
|
223
|
-
require("prismjs/components/prism-promql");
|
|
224
|
-
require("prismjs/components/prism-properties");
|
|
225
|
-
require("prismjs/components/prism-protobuf");
|
|
226
|
-
require("prismjs/components/prism-stylus");
|
|
227
|
-
require("prismjs/components/prism-twig");
|
|
228
|
-
require("prismjs/components/prism-pug");
|
|
229
|
-
require("prismjs/components/prism-puppet");
|
|
230
|
-
require("prismjs/components/prism-pure");
|
|
231
|
-
require("prismjs/components/prism-purebasic");
|
|
232
|
-
require("prismjs/components/prism-purescript");
|
|
233
|
-
require("prismjs/components/prism-python");
|
|
234
|
-
require("prismjs/components/prism-qsharp");
|
|
235
|
-
require("prismjs/components/prism-q");
|
|
236
|
-
require("prismjs/components/prism-qml");
|
|
237
|
-
require("prismjs/components/prism-qore");
|
|
238
|
-
require("prismjs/components/prism-r");
|
|
239
|
-
require("prismjs/components/prism-racket");
|
|
240
|
-
require("prismjs/components/prism-cshtml");
|
|
241
|
-
require("prismjs/components/prism-jsx");
|
|
242
|
-
require("prismjs/components/prism-tsx");
|
|
243
|
-
require("prismjs/components/prism-reason");
|
|
244
|
-
require("prismjs/components/prism-rego");
|
|
245
|
-
require("prismjs/components/prism-renpy");
|
|
246
|
-
require("prismjs/components/prism-rescript");
|
|
247
|
-
require("prismjs/components/prism-rest");
|
|
248
|
-
require("prismjs/components/prism-rip");
|
|
249
|
-
require("prismjs/components/prism-roboconf");
|
|
250
|
-
require("prismjs/components/prism-robotframework");
|
|
251
|
-
require("prismjs/components/prism-rust");
|
|
252
|
-
require("prismjs/components/prism-sas");
|
|
253
|
-
require("prismjs/components/prism-sass");
|
|
254
|
-
require("prismjs/components/prism-shell-session");
|
|
255
|
-
require("prismjs/components/prism-smali");
|
|
256
|
-
require("prismjs/components/prism-smalltalk");
|
|
257
|
-
require("prismjs/components/prism-smarty");
|
|
258
|
-
require("prismjs/components/prism-sml");
|
|
259
|
-
require("prismjs/components/prism-solidity");
|
|
260
|
-
require("prismjs/components/prism-solution-file");
|
|
261
|
-
require("prismjs/components/prism-soy");
|
|
262
|
-
require("prismjs/components/prism-turtle");
|
|
263
|
-
require("prismjs/components/prism-sparql");
|
|
264
|
-
require("prismjs/components/prism-splunk-spl");
|
|
265
|
-
require("prismjs/components/prism-sqf");
|
|
266
|
-
require("prismjs/components/prism-squirrel");
|
|
267
|
-
require("prismjs/components/prism-stan");
|
|
268
|
-
require("prismjs/components/prism-stata");
|
|
269
|
-
require("prismjs/components/prism-iecst");
|
|
270
|
-
require("prismjs/components/prism-supercollider");
|
|
271
|
-
require("prismjs/components/prism-swift");
|
|
272
|
-
require("prismjs/components/prism-systemd");
|
|
273
|
-
require("prismjs/components/prism-t4-templating");
|
|
274
|
-
require("prismjs/components/prism-t4-cs");
|
|
275
|
-
require("prismjs/components/prism-vbnet");
|
|
276
|
-
require("prismjs/components/prism-t4-vb");
|
|
277
|
-
require("prismjs/components/prism-tap");
|
|
278
|
-
require("prismjs/components/prism-tcl");
|
|
279
|
-
require("prismjs/components/prism-tt2");
|
|
280
|
-
require("prismjs/components/prism-toml");
|
|
281
|
-
require("prismjs/components/prism-tremor");
|
|
282
|
-
require("prismjs/components/prism-typoscript");
|
|
283
|
-
require("prismjs/components/prism-unrealscript");
|
|
284
|
-
require("prismjs/components/prism-uorazor");
|
|
285
|
-
require("prismjs/components/prism-v");
|
|
286
|
-
require("prismjs/components/prism-vala");
|
|
287
|
-
require("prismjs/components/prism-velocity");
|
|
288
|
-
require("prismjs/components/prism-verilog");
|
|
289
|
-
require("prismjs/components/prism-vhdl");
|
|
290
|
-
require("prismjs/components/prism-vim");
|
|
291
|
-
require("prismjs/components/prism-visual-basic");
|
|
292
|
-
require("prismjs/components/prism-warpscript");
|
|
293
|
-
require("prismjs/components/prism-wasm");
|
|
294
|
-
require("prismjs/components/prism-web-idl");
|
|
295
|
-
require("prismjs/components/prism-wgsl");
|
|
296
|
-
require("prismjs/components/prism-wiki");
|
|
297
|
-
require("prismjs/components/prism-wolfram");
|
|
298
|
-
require("prismjs/components/prism-wren");
|
|
299
|
-
require("prismjs/components/prism-xeora");
|
|
300
|
-
require("prismjs/components/prism-xml-doc");
|
|
301
|
-
require("prismjs/components/prism-xojo");
|
|
302
|
-
require("prismjs/components/prism-xquery");
|
|
303
|
-
require("prismjs/components/prism-yang");
|
|
304
|
-
require("prismjs/components/prism-zig");
|
|
305
|
-
var _markdownIt = require("./markdown-it");
|
|
306
|
-
var _prismDiffHighlight = require("../prism-plugins/prism-diff-highlight");
|
|
307
|
-
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
308
|
-
// diffプラグインを有効化
|
|
309
|
-
(0, _prismDiffHighlight.enableDiffHighlight)();
|
|
310
|
-
function highlightContent({
|
|
311
|
-
text,
|
|
312
|
-
prismGrammar,
|
|
313
|
-
langName,
|
|
314
|
-
hasDiff
|
|
315
|
-
}) {
|
|
316
|
-
if (prismGrammar && langName) {
|
|
317
|
-
if (hasDiff) return _prismCore.default.highlight(text, _prismCore.default.languages.diff, `diff-${langName}`);
|
|
318
|
-
return _prismCore.default.highlight(text, prismGrammar, langName);
|
|
8
|
+
var _shiki = require("shiki");
|
|
9
|
+
/**
|
|
10
|
+
* Shiki によるシンタックスハイライト処理
|
|
11
|
+
*
|
|
12
|
+
* このモジュールは Phase 2(applyHighlighting)から呼び出され、
|
|
13
|
+
* 個々のコードブロックをハイライトする役割を持つ。
|
|
14
|
+
*
|
|
15
|
+
* ## 特徴
|
|
16
|
+
*
|
|
17
|
+
* - シングルトン: ハイライターインスタンスは1つだけ作成され再利用される
|
|
18
|
+
* - 遅延ロード: 言語定義は初回使用時にのみロードされる
|
|
19
|
+
* - diff サポート: ベース言語のハイライト + diff 背景色の両方を適用
|
|
20
|
+
* - transformers: Shiki の transformers API で AST レベルの変換を実行
|
|
21
|
+
*
|
|
22
|
+
* ## 関連ファイル
|
|
23
|
+
*
|
|
24
|
+
* - `md-renderer-fence.ts`: Phase 1(収集)と Phase 3(置換)
|
|
25
|
+
* - `index.ts`: 全体の統合
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Shiki ハイライターの初期化 Promise をキャッシュ
|
|
30
|
+
*
|
|
31
|
+
* 注: インスタンスではなく Promise をキャッシュすることで、
|
|
32
|
+
* Promise.all による並列処理時の競合状態を防ぐ。
|
|
33
|
+
*
|
|
34
|
+
* 問題のあるパターン:
|
|
35
|
+
* let instance = null;
|
|
36
|
+
* if (instance) return instance;
|
|
37
|
+
* instance = await createHighlighter(); // ← await 中に他の呼び出しが来る
|
|
38
|
+
*
|
|
39
|
+
* 正しいパターン:
|
|
40
|
+
* let promise = null;
|
|
41
|
+
* if (!promise) promise = createHighlighter(); // ← await しない
|
|
42
|
+
* return promise; // ← 同じ Promise を返す
|
|
43
|
+
*/
|
|
44
|
+
let highlighterPromise = null;
|
|
45
|
+
const SHIKI_THEME = 'github-dark';
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Shiki ハイライターを初期化する
|
|
49
|
+
* 最初は最低限のセットで初期化し、必要に応じて言語をロードする
|
|
50
|
+
*/
|
|
51
|
+
async function getHighlighter() {
|
|
52
|
+
if (!highlighterPromise) {
|
|
53
|
+
// Promise をキャッシュ(await しない)
|
|
54
|
+
highlighterPromise = (0, _shiki.createHighlighter)({
|
|
55
|
+
themes: [SHIKI_THEME],
|
|
56
|
+
langs: []
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return highlighterPromise;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 言語がサポートされているかチェックし、必要に応じてロードする
|
|
64
|
+
*/
|
|
65
|
+
async function ensureLanguageLoaded(highlighter, langName) {
|
|
66
|
+
// 既にロード済みかチェック
|
|
67
|
+
const loadedLangs = highlighter.getLoadedLanguages();
|
|
68
|
+
if (loadedLangs.includes(langName)) {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// bundledLanguages に含まれているかチェック
|
|
73
|
+
if (langName in _shiki.bundledLanguages) {
|
|
74
|
+
await highlighter.loadLanguage(langName);
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* ハイライトオプション
|
|
82
|
+
*/
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* diff プレフィックスの定義
|
|
86
|
+
* Prism.js の diff-highlight プラグインと互換性を持たせる
|
|
87
|
+
*/
|
|
88
|
+
const DIFF_PREFIXES = {
|
|
89
|
+
// 削除行
|
|
90
|
+
'-': 'remove',
|
|
91
|
+
// deleted-sign
|
|
92
|
+
'<': 'remove',
|
|
93
|
+
// deleted-arrow
|
|
94
|
+
// 挿入行
|
|
95
|
+
'+': 'add',
|
|
96
|
+
// inserted-sign
|
|
97
|
+
'>': 'add' // inserted-arrow
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/** コンテキスト行(変更なし)のプレフィックス */
|
|
101
|
+
const DIFF_CONTEXT_PREFIX = ' ';
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* diff 行スタイルを適用する transformer を作成
|
|
105
|
+
* 行頭のプレフィックス (+, -, <, >, スペース) を検出して処理
|
|
106
|
+
* - +, -, <, >: 挿入/削除のクラスを追加し、プレフィックスをラップ
|
|
107
|
+
* - スペース: プレフィックスのみラップ(コンテキスト行)
|
|
108
|
+
*/
|
|
109
|
+
function createDiffTransformer() {
|
|
110
|
+
return {
|
|
111
|
+
line(node, lineNumber) {
|
|
112
|
+
// ソースコードの該当行を取得
|
|
113
|
+
const lines = this.source.split('\n');
|
|
114
|
+
const lineText = lines[lineNumber - 1] ?? '';
|
|
115
|
+
const firstChar = lineText.charAt(0);
|
|
116
|
+
if (firstChar in DIFF_PREFIXES) {
|
|
117
|
+
// 追加/削除行
|
|
118
|
+
this.addClassToHast(node, 'diff');
|
|
119
|
+
this.addClassToHast(node, DIFF_PREFIXES[firstChar]);
|
|
120
|
+
wrapDiffPrefix(node, firstChar);
|
|
121
|
+
} else if (firstChar === DIFF_CONTEXT_PREFIX) {
|
|
122
|
+
// コンテキスト行(先頭スペース)
|
|
123
|
+
wrapDiffPrefix(node, firstChar);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* 行の最初の文字(diff プレフィックス)を別の span 要素にラップする
|
|
131
|
+
* これにより CSS で user-select: none を適用可能になる
|
|
132
|
+
*/
|
|
133
|
+
function wrapDiffPrefix(
|
|
134
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
135
|
+
lineNode, prefix) {
|
|
136
|
+
const line = lineNode;
|
|
137
|
+
if (!line.children || line.children.length === 0) return;
|
|
138
|
+
const firstChild = line.children[0];
|
|
139
|
+
|
|
140
|
+
// 最初の子要素がテキストノードの場合(実際には発生しないはずだが念の為)
|
|
141
|
+
if (firstChild.type === 'text' && firstChild.value.startsWith(prefix)) {
|
|
142
|
+
// プレフィックスを分離
|
|
143
|
+
const prefixSpan = {
|
|
144
|
+
type: 'element',
|
|
145
|
+
tagName: 'span',
|
|
146
|
+
properties: {
|
|
147
|
+
class: 'diff-prefix'
|
|
148
|
+
},
|
|
149
|
+
children: [{
|
|
150
|
+
type: 'text',
|
|
151
|
+
value: prefix
|
|
152
|
+
}]
|
|
153
|
+
};
|
|
154
|
+
firstChild.value = firstChild.value.slice(1);
|
|
155
|
+
|
|
156
|
+
// 空になった場合は削除
|
|
157
|
+
if (firstChild.value === '') {
|
|
158
|
+
line.children.shift();
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// プレフィックス span を先頭に挿入
|
|
162
|
+
line.children.unshift(prefixSpan);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// 最初の子要素が element(span など)の場合
|
|
167
|
+
if (firstChild.type === 'element' && firstChild.children && firstChild.children.length > 0) {
|
|
168
|
+
const innerFirst = firstChild.children[0];
|
|
169
|
+
if (innerFirst.type === 'text' && innerFirst.value.startsWith(prefix)) {
|
|
170
|
+
// プレフィックスを分離
|
|
171
|
+
const prefixSpan = {
|
|
172
|
+
type: 'element',
|
|
173
|
+
tagName: 'span',
|
|
174
|
+
properties: {
|
|
175
|
+
class: 'diff-prefix'
|
|
176
|
+
},
|
|
177
|
+
children: [{
|
|
178
|
+
type: 'text',
|
|
179
|
+
value: prefix
|
|
180
|
+
}]
|
|
181
|
+
};
|
|
182
|
+
innerFirst.value = innerFirst.value.slice(1);
|
|
183
|
+
|
|
184
|
+
// 空になった場合は削除
|
|
185
|
+
if (innerFirst.value === '') {
|
|
186
|
+
firstChild.children.shift();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// プレフィックス span を先頭に挿入
|
|
190
|
+
line.children.unshift(prefixSpan);
|
|
191
|
+
}
|
|
319
192
|
}
|
|
320
|
-
if (hasDiff) return _prismCore.default.highlight(text, _prismCore.default.languages.diff, 'diff');
|
|
321
|
-
return _markdownIt.md.utils.escapeHtml(text);
|
|
322
193
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* pre/code タグにクラスと属性を追加する transformer を作成
|
|
197
|
+
*/
|
|
198
|
+
function createClassTransformer(options) {
|
|
199
|
+
const {
|
|
200
|
+
className,
|
|
201
|
+
line
|
|
202
|
+
} = options;
|
|
203
|
+
return {
|
|
204
|
+
pre(node) {
|
|
205
|
+
if (className) {
|
|
206
|
+
this.addClassToHast(node, className);
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
code(node) {
|
|
210
|
+
this.addClassToHast(node, 'code-line');
|
|
211
|
+
if (className) {
|
|
212
|
+
this.addClassToHast(node, className);
|
|
213
|
+
}
|
|
214
|
+
if (line !== undefined) {
|
|
215
|
+
node.properties['data-line'] = line;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* [Phase 2 の実処理] コードをハイライトする
|
|
223
|
+
*
|
|
224
|
+
* applyHighlighting() から各コードブロックに対して呼び出される。
|
|
225
|
+
* 言語が未ロードの場合は自動的にロードする(遅延ロード)。
|
|
226
|
+
* Shiki の transformers API を使用して AST レベルで変換を行う。
|
|
227
|
+
*
|
|
228
|
+
* @param text - ハイライト対象のコード文字列
|
|
229
|
+
* @param langName - 言語名(例: "javascript", "python")
|
|
230
|
+
* @param options - ハイライトオプション
|
|
231
|
+
* @returns ハイライト済み HTML(常に <pre><code> 構造)
|
|
232
|
+
*/
|
|
233
|
+
async function highlight(text, langName, options) {
|
|
234
|
+
const {
|
|
235
|
+
hasDiff,
|
|
236
|
+
className,
|
|
237
|
+
line
|
|
238
|
+
} = options;
|
|
239
|
+
const highlighter = await getHighlighter();
|
|
240
|
+
|
|
241
|
+
// 言語がサポートされているか確認し、必要に応じてロード
|
|
242
|
+
const isSupported = langName ? await ensureLanguageLoaded(highlighter, langName) : false;
|
|
243
|
+
|
|
244
|
+
// サポートされていない言語は text(プレーンテキスト)として処理
|
|
245
|
+
// ref: https://shiki.style/languages#plain-text
|
|
246
|
+
const lang = isSupported ? langName : 'text';
|
|
247
|
+
if (!isSupported) {
|
|
248
|
+
await ensureLanguageLoaded(highlighter, 'text');
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// transformers を構築
|
|
252
|
+
const transformers = [createClassTransformer({
|
|
253
|
+
className,
|
|
254
|
+
line
|
|
255
|
+
})];
|
|
256
|
+
if (hasDiff) {
|
|
257
|
+
transformers.push(createDiffTransformer());
|
|
258
|
+
}
|
|
259
|
+
return highlighter.codeToHtml(text, {
|
|
260
|
+
lang,
|
|
261
|
+
theme: SHIKI_THEME,
|
|
262
|
+
transformers
|
|
330
263
|
});
|
|
331
264
|
}
|