vuepress-plugin-md-power 1.0.0-rc.80 → 1.0.0-rc.81

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.
Files changed (92) hide show
  1. package/lib/client/components/CodeSandbox.vue +1 -1
  2. package/lib/client/components/PDFViewer.vue +1 -1
  3. package/lib/client/components/Plot.vue +1 -1
  4. package/lib/client/components/Replit.vue +1 -1
  5. package/lib/client/composables/codeRepl.d.ts +7 -5
  6. package/lib/client/composables/codeRepl.js +253 -145
  7. package/lib/client/composables/pdf.d.ts +7 -3
  8. package/lib/client/composables/pdf.js +55 -81
  9. package/lib/client/composables/rustRepl.d.ts +3 -2
  10. package/lib/client/composables/rustRepl.js +96 -94
  11. package/lib/client/composables/size.d.ts +9 -5
  12. package/lib/client/composables/size.js +36 -44
  13. package/lib/client/index.js +2 -1
  14. package/lib/client/options.d.ts +5 -2
  15. package/lib/client/options.js +5 -1
  16. package/lib/client/utils/http.d.ts +3 -1
  17. package/lib/client/utils/http.js +24 -20
  18. package/lib/client/utils/is.d.ts +5 -3
  19. package/lib/client/utils/is.js +16 -10
  20. package/lib/client/utils/link.d.ts +3 -1
  21. package/lib/client/utils/link.js +8 -4
  22. package/lib/client/utils/sleep.d.ts +3 -1
  23. package/lib/client/utils/sleep.js +8 -4
  24. package/lib/node/index.d.ts +188 -2
  25. package/lib/node/index.js +833 -2
  26. package/lib/shared/index.d.ts +185 -10
  27. package/lib/shared/index.js +0 -10
  28. package/package.json +5 -5
  29. package/lib/node/features/caniuse.d.ts +0 -25
  30. package/lib/node/features/caniuse.js +0 -87
  31. package/lib/node/features/codeSandbox.d.ts +0 -7
  32. package/lib/node/features/codeSandbox.js +0 -29
  33. package/lib/node/features/codepen.d.ts +0 -7
  34. package/lib/node/features/codepen.js +0 -42
  35. package/lib/node/features/icons/index.d.ts +0 -2
  36. package/lib/node/features/icons/index.js +0 -2
  37. package/lib/node/features/icons/plugin.d.ts +0 -10
  38. package/lib/node/features/icons/plugin.js +0 -61
  39. package/lib/node/features/icons/writer.d.ts +0 -11
  40. package/lib/node/features/icons/writer.js +0 -126
  41. package/lib/node/features/jsfiddle.d.ts +0 -6
  42. package/lib/node/features/jsfiddle.js +0 -28
  43. package/lib/node/features/langRepl.d.ts +0 -4
  44. package/lib/node/features/langRepl.js +0 -59
  45. package/lib/node/features/pdf.d.ts +0 -2
  46. package/lib/node/features/pdf.js +0 -31
  47. package/lib/node/features/plot.d.ts +0 -5
  48. package/lib/node/features/plot.js +0 -48
  49. package/lib/node/features/replit.d.ts +0 -7
  50. package/lib/node/features/replit.js +0 -22
  51. package/lib/node/features/video/bilibili.d.ts +0 -2
  52. package/lib/node/features/video/bilibili.js +0 -58
  53. package/lib/node/features/video/youtube.d.ts +0 -2
  54. package/lib/node/features/video/youtube.js +0 -47
  55. package/lib/node/plugin.d.ts +0 -3
  56. package/lib/node/plugin.js +0 -80
  57. package/lib/node/prepareConfigFile.d.ts +0 -3
  58. package/lib/node/prepareConfigFile.js +0 -59
  59. package/lib/node/utils/createRuleBlock.d.ts +0 -18
  60. package/lib/node/utils/createRuleBlock.js +0 -34
  61. package/lib/node/utils/package.d.ts +0 -4
  62. package/lib/node/utils/package.js +0 -4
  63. package/lib/node/utils/parseRect.d.ts +0 -1
  64. package/lib/node/utils/parseRect.js +0 -5
  65. package/lib/node/utils/resolveAttrs.d.ts +0 -4
  66. package/lib/node/utils/resolveAttrs.js +0 -29
  67. package/lib/node/utils/timeToSeconds.d.ts +0 -1
  68. package/lib/node/utils/timeToSeconds.js +0 -8
  69. package/lib/shared/caniuse.d.ts +0 -18
  70. package/lib/shared/caniuse.js +0 -1
  71. package/lib/shared/codeSandbox.d.ts +0 -11
  72. package/lib/shared/codeSandbox.js +0 -1
  73. package/lib/shared/codepen.d.ts +0 -10
  74. package/lib/shared/codepen.js +0 -1
  75. package/lib/shared/icons.d.ts +0 -17
  76. package/lib/shared/icons.js +0 -1
  77. package/lib/shared/jsfiddle.d.ts +0 -8
  78. package/lib/shared/jsfiddle.js +0 -1
  79. package/lib/shared/pdf.d.ts +0 -15
  80. package/lib/shared/pdf.js +0 -1
  81. package/lib/shared/plot.d.ts +0 -27
  82. package/lib/shared/plot.js +0 -1
  83. package/lib/shared/plugin.d.ts +0 -21
  84. package/lib/shared/plugin.js +0 -1
  85. package/lib/shared/repl.d.ts +0 -22
  86. package/lib/shared/repl.js +0 -1
  87. package/lib/shared/replit.d.ts +0 -6
  88. package/lib/shared/replit.js +0 -1
  89. package/lib/shared/size.d.ts +0 -5
  90. package/lib/shared/size.js +0 -1
  91. package/lib/shared/video.d.ts +0 -22
  92. package/lib/shared/video.js +0 -1
package/lib/node/index.js CHANGED
@@ -1,2 +1,833 @@
1
- export * from './plugin.js';
2
- export * from '../shared/index.js';
1
+ // src/node/plugin.ts
2
+ import { addViteOptimizeDepsInclude } from "@vuepress/helper";
3
+
4
+ // src/node/features/caniuse.ts
5
+ import container from "markdown-it-container";
6
+ import { customAlphabet } from "nanoid";
7
+
8
+ // src/node/utils/createRuleBlock.ts
9
+ function createRuleBlock(md, {
10
+ type,
11
+ name = type,
12
+ syntaxPattern,
13
+ beforeName = "import_code",
14
+ ruleOptions = { alt: ["paragraph", "reference", "blockquote", "list"] },
15
+ meta,
16
+ content
17
+ }) {
18
+ const MIN_LENGTH = type.length + 5;
19
+ const START_CODES = [64, 91, ...type.split("").map((c) => c.charCodeAt(0))];
20
+ md.block.ruler.before(
21
+ beforeName,
22
+ name,
23
+ (state, startLine, endLine, silent) => {
24
+ const pos = state.bMarks[startLine] + state.tShift[startLine];
25
+ const max = state.eMarks[startLine];
26
+ if (pos + MIN_LENGTH > max)
27
+ return false;
28
+ for (let i = 0; i < START_CODES.length; i += 1) {
29
+ if (state.src.charCodeAt(pos + i) !== START_CODES[i])
30
+ return false;
31
+ }
32
+ const match = state.src.slice(pos, max).match(syntaxPattern);
33
+ if (!match)
34
+ return false;
35
+ if (silent)
36
+ return true;
37
+ const token = state.push(name, "", 0);
38
+ token.meta = meta(match);
39
+ token.map = [startLine, startLine + 1];
40
+ state.line = startLine + 1;
41
+ return true;
42
+ },
43
+ ruleOptions
44
+ );
45
+ md.renderer.rules[name] = (tokens, index) => {
46
+ const token = tokens[index];
47
+ token.content = content(token.meta);
48
+ return token.content;
49
+ };
50
+ }
51
+
52
+ // src/node/features/caniuse.ts
53
+ var nanoid = customAlphabet("abcdefghijklmnopqrstuvwxyz", 5);
54
+ var UNDERLINE_RE = /_+/g;
55
+ var caniusePlugin = (md, { mode: defaultMode = "embed" } = {}) => {
56
+ createRuleBlock(md, {
57
+ type: "caniuse",
58
+ syntaxPattern: /^@\[caniuse\s*(embed|image)?(?:\{([0-9,\-]*)\})?\]\(([^)]*)\)/,
59
+ meta: ([, mode, versions = "", feature]) => ({
60
+ feature,
61
+ mode: mode || defaultMode,
62
+ versions
63
+ }),
64
+ content: (meta) => resolveCanIUse(meta)
65
+ });
66
+ };
67
+ function legacyCaniuse(md, { mode = "embed" } = {}) {
68
+ const modeMap = ["image", "embed"];
69
+ const isMode = (mode2) => modeMap.includes(mode2);
70
+ mode = isMode(mode) ? mode : modeMap[0];
71
+ const type = "caniuse";
72
+ const validateReg = new RegExp(`^${type}`);
73
+ const validate = (info) => {
74
+ return validateReg.test(info.trim());
75
+ };
76
+ const render = (tokens, index) => {
77
+ const token = tokens[index];
78
+ if (token.nesting === 1) {
79
+ const info = token.info.trim().slice(type.length).trim() || "";
80
+ const feature = info.split(/\s+/)[0];
81
+ const versions = info.match(/\{(.*)\}/)?.[1] || "";
82
+ return feature ? resolveCanIUse({ feature, mode, versions }) : "";
83
+ } else {
84
+ return "";
85
+ }
86
+ };
87
+ md.use(container, type, { validate, render });
88
+ }
89
+ function resolveCanIUse({ feature, mode, versions }) {
90
+ if (!feature)
91
+ return "";
92
+ if (mode === "image") {
93
+ const link = "https://caniuse.bitsofco.de/image/";
94
+ const alt = `Data on support for the ${feature} feature across the major browsers from caniuse.com`;
95
+ return `<ClientOnly><p><picture>
96
+ <source type="image/webp" srcset="${link}${feature}.webp">
97
+ <source type="image/png" srcset="${link}${feature}.png">
98
+ <img src="${link}${feature}.jpg" alt="${alt}" width="100%">
99
+ </picture></p></ClientOnly>`;
100
+ }
101
+ feature = feature.replace(UNDERLINE_RE, "_");
102
+ const { past, future } = resolveVersions(versions);
103
+ const meta = nanoid();
104
+ return `<CanIUseViewer feature="${feature}" meta="${meta}" past="${past}" future="${future}" />`;
105
+ }
106
+ function resolveVersions(versions) {
107
+ if (!versions)
108
+ return { past: 2, future: 1 };
109
+ const list = versions.split(",").map((v) => Number(v.trim())).filter((v) => !Number.isNaN(v) && v >= -5 && v <= 3);
110
+ list.push(0);
111
+ const uniq = [...new Set(list)].sort((a, b) => b - a);
112
+ return {
113
+ future: uniq[0],
114
+ past: Math.abs(uniq[uniq.length - 1])
115
+ };
116
+ }
117
+
118
+ // src/node/features/pdf.ts
119
+ import { path } from "vuepress/utils";
120
+
121
+ // src/node/utils/resolveAttrs.ts
122
+ var RE_ATTR_VALUE = /(?:^|\s+)(?<attr>[\w-]+)(?:=\s*(?<quote>['"])(?<value>.+?)\k<quote>)?(?:\s+|$)/;
123
+ function resolveAttrs(info) {
124
+ info = info.trim();
125
+ if (!info)
126
+ return { rawAttrs: "", attrs: {} };
127
+ const attrs = {};
128
+ const rawAttrs = info;
129
+ let matched;
130
+ while (matched = info.match(RE_ATTR_VALUE)) {
131
+ const { attr, value } = matched.groups || {};
132
+ attrs[attr] = value ?? true;
133
+ info = info.slice(matched[0].length);
134
+ }
135
+ Object.keys(attrs).forEach((key) => {
136
+ let value = attrs[key];
137
+ value = typeof value === "string" ? value.trim() : value;
138
+ if (value === "true")
139
+ value = true;
140
+ else if (value === "false")
141
+ value = false;
142
+ attrs[key] = value;
143
+ if (key.includes("-")) {
144
+ const _key = key.replace(/-(\w)/g, (_, c) => c.toUpperCase());
145
+ attrs[_key] = value;
146
+ }
147
+ });
148
+ return { attrs, rawAttrs };
149
+ }
150
+
151
+ // src/node/utils/parseRect.ts
152
+ function parseRect(str, unit = "px") {
153
+ if (Number.parseFloat(str) === Number(str))
154
+ return `${str}${unit}`;
155
+ return str;
156
+ }
157
+
158
+ // src/node/features/pdf.ts
159
+ var pdfPlugin = (md) => {
160
+ createRuleBlock(md, {
161
+ type: "pdf",
162
+ // eslint-disable-next-line regexp/no-super-linear-backtracking
163
+ syntaxPattern: /^@\[pdf(?:\s+(\d+))?([^\]]*)\]\(([^)]*)\)/,
164
+ meta([, page, info = "", src = ""]) {
165
+ const { attrs } = resolveAttrs(info);
166
+ return {
167
+ src,
168
+ page: +page || 1,
169
+ noToolbar: Boolean(attrs.noToolbar ?? false),
170
+ zoom: +attrs.zoom || 50,
171
+ width: attrs.width ? parseRect(attrs.width) : "100%",
172
+ height: attrs.height ? parseRect(attrs.height) : "",
173
+ ratio: attrs.ratio ? parseRect(attrs.ratio) : "",
174
+ title: path.basename(src || "")
175
+ };
176
+ },
177
+ content({ title, src, page, noToolbar, width, height, ratio, zoom }) {
178
+ return `<PDFViewer src="${src}" title="${title}" :page="${page}" :no-toolbar="${noToolbar}" width="${width}" height="${height}" ratio="${ratio}" :zoom="${zoom}" />`;
179
+ }
180
+ });
181
+ };
182
+
183
+ // src/node/features/icons/writer.ts
184
+ import { constants, promises as fsp } from "node:fs";
185
+ import { getIconContentCSS, getIconData } from "@iconify/utils";
186
+ import { fs, logger } from "vuepress/utils";
187
+ import { isPackageExists } from "local-pkg";
188
+ import { customAlphabet as customAlphabet2 } from "nanoid";
189
+
190
+ // src/node/utils/package.ts
191
+ async function interopDefault(m) {
192
+ const resolved = await m;
193
+ return resolved.default || resolved;
194
+ }
195
+
196
+ // src/node/features/icons/writer.ts
197
+ var nanoid2 = customAlphabet2("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 8);
198
+ var iconDataCache = /* @__PURE__ */ new Map();
199
+ var URL_CONTENT_RE = /(url\([\s\S]+?\))/;
200
+ var CSS_PATH = "internal/md-power/icons.css";
201
+ function resolveOption(opt) {
202
+ const options = typeof opt === "object" ? opt : {};
203
+ options.prefix ??= "vp-mdi";
204
+ options.color = options.color === "currentColor" || !options.color ? "currentcolor" : options.color;
205
+ options.size = options.size ? parseRect(`${options.size}`) : "1em";
206
+ return options;
207
+ }
208
+ function createIconCSSWriter(app, opt) {
209
+ const cache = /* @__PURE__ */ new Map();
210
+ const isInstalled = isPackageExists("@iconify/json");
211
+ const currentPath = app.dir.temp(CSS_PATH);
212
+ const write = async (content) => {
213
+ if (!content && app.env.isDev) {
214
+ if (existsSync(currentPath) && (await fsp.stat(currentPath)).isFile()) {
215
+ return;
216
+ }
217
+ }
218
+ await app.writeTemp(CSS_PATH, content);
219
+ };
220
+ let timer = null;
221
+ const options = resolveOption(opt);
222
+ const prefix = options.prefix;
223
+ const defaultContent = getDefaultContent(options);
224
+ async function writeCss() {
225
+ if (timer)
226
+ clearTimeout(timer);
227
+ timer = setTimeout(async () => {
228
+ let css = defaultContent;
229
+ if (cache.size > 0) {
230
+ for (const [, { content, className }] of cache)
231
+ css += `.${className} {
232
+ --svg: ${content};
233
+ }
234
+ `;
235
+ await write(css);
236
+ }
237
+ }, 100);
238
+ }
239
+ function addIcon(iconName) {
240
+ if (!isInstalled)
241
+ return;
242
+ if (cache.has(iconName))
243
+ return cache.get(iconName).className;
244
+ const item = {
245
+ className: `${prefix}-${nanoid2()}`,
246
+ content: ""
247
+ };
248
+ cache.set(iconName, item);
249
+ genIconContent(iconName, (content) => {
250
+ item.content = content;
251
+ writeCss();
252
+ });
253
+ return item.className;
254
+ }
255
+ async function initIcon() {
256
+ if (!opt)
257
+ return await write("");
258
+ if (!isInstalled) {
259
+ logger.error("[plugin-md-power]: `@iconify/json` not found! Please install `@iconify/json` first.");
260
+ return;
261
+ }
262
+ return await writeCss();
263
+ }
264
+ return { addIcon, writeCss, initIcon };
265
+ }
266
+ function getDefaultContent(options) {
267
+ const { prefix, size, color } = options;
268
+ return `[class^="${prefix}-"],
269
+ [class*=" ${prefix}-"] {
270
+ display: inline-block;
271
+ width: ${size};
272
+ height: ${size};
273
+ vertical-align: middle;
274
+ color: inherit;
275
+ background-color: ${color};
276
+ -webkit-mask: var(--svg) no-repeat;
277
+ mask: var(--svg) no-repeat;
278
+ -webkit-mask-size: 100% 100%;
279
+ mask-size: 100% 100%;
280
+ }
281
+ `;
282
+ }
283
+ var locate;
284
+ async function genIconContent(iconName, cb) {
285
+ if (!locate) {
286
+ const mod = await interopDefault(import("@iconify/json"));
287
+ locate = mod.locate;
288
+ }
289
+ const [collect, name] = iconName.split(":");
290
+ let iconJson = iconDataCache.get(collect);
291
+ if (!iconJson) {
292
+ const filename = locate(collect);
293
+ try {
294
+ iconJson = JSON.parse(await fs.readFile(filename, "utf-8"));
295
+ iconDataCache.set(collect, iconJson);
296
+ } catch {
297
+ logger.warn(`[plugin-md-power] Can not find icon, ${collect} is missing!`);
298
+ }
299
+ }
300
+ const data = getIconData(iconJson, name);
301
+ if (!data)
302
+ return logger.error(`[plugin-md-power] Can not read icon in ${collect}, ${name} is missing!`);
303
+ const content = getIconContentCSS(data, {
304
+ height: data.height || 24
305
+ });
306
+ const match = content.match(URL_CONTENT_RE);
307
+ return cb(match ? match[1] : "");
308
+ }
309
+ function existsSync(fp) {
310
+ try {
311
+ fs.accessSync(fp, constants.R_OK);
312
+ return true;
313
+ } catch {
314
+ return false;
315
+ }
316
+ }
317
+
318
+ // src/node/features/icons/plugin.ts
319
+ var [openTag, endTag] = [":[", "]:"];
320
+ function createTokenizer(addIcon) {
321
+ return (state, silent) => {
322
+ let found = false;
323
+ const max = state.posMax;
324
+ const start = state.pos;
325
+ if (state.src.slice(start, start + 2) !== openTag)
326
+ return false;
327
+ if (silent)
328
+ return false;
329
+ if (max - start < 5)
330
+ return false;
331
+ state.pos = start + 2;
332
+ while (state.pos < max) {
333
+ if (state.src.slice(state.pos, state.pos + 2) === endTag) {
334
+ found = true;
335
+ break;
336
+ }
337
+ state.md.inline.skipToken(state);
338
+ }
339
+ if (!found || start + 2 === state.pos) {
340
+ state.pos = start;
341
+ return false;
342
+ }
343
+ const content = state.src.slice(start + 2, state.pos);
344
+ if (/^\s|\s$/.test(content)) {
345
+ state.pos = start;
346
+ return false;
347
+ }
348
+ state.posMax = state.pos;
349
+ state.pos = start + 2;
350
+ const [iconName, options = ""] = content.split(/\s+/);
351
+ const [size, color] = options.split("/");
352
+ const open = state.push("iconify_open", "span", 1);
353
+ open.markup = openTag;
354
+ const className = addIcon(iconName);
355
+ if (className)
356
+ open.attrSet("class", className);
357
+ let style = "";
358
+ if (size)
359
+ style += `width:${parseRect(size)};height:${parseRect(size)};`;
360
+ if (color)
361
+ style += `color:${color};`;
362
+ if (style)
363
+ open.attrSet("style", style);
364
+ const text = state.push("text", "", 0);
365
+ text.content = className ? "" : iconName;
366
+ const close = state.push("iconify_close", "span", -1);
367
+ close.markup = endTag;
368
+ state.pos = state.posMax + 2;
369
+ state.posMax = max;
370
+ return true;
371
+ };
372
+ }
373
+ var iconsPlugin = (md, addIcon = () => "") => {
374
+ md.inline.ruler.before("emphasis", "iconify", createTokenizer(addIcon));
375
+ };
376
+
377
+ // src/node/features/video/bilibili.ts
378
+ import { URLSearchParams as URLSearchParams2 } from "node:url";
379
+
380
+ // src/node/utils/timeToSeconds.ts
381
+ function timeToSeconds(time) {
382
+ if (!time)
383
+ return 0;
384
+ if (Number.parseFloat(time) === Number(time))
385
+ return Number(time);
386
+ const [s, m, h] = time.split(":").reverse().map((n) => Number(n) || 0);
387
+ return s + m * 60 + h * 3600;
388
+ }
389
+
390
+ // src/node/features/video/bilibili.ts
391
+ var BILIBILI_LINK = "https://player.bilibili.com/player.html";
392
+ var bilibiliPlugin = (md) => {
393
+ createRuleBlock(md, {
394
+ type: "bilibili",
395
+ name: "video_bilibili",
396
+ // eslint-disable-next-line regexp/no-super-linear-backtracking
397
+ syntaxPattern: /^@\[bilibili(?:\s+p(\d+))?([^\]]*)\]\(([^)]*)\)/,
398
+ meta([, page, info = "", source = ""]) {
399
+ const { attrs } = resolveAttrs(info);
400
+ const ids = source.trim().split(/\s+/);
401
+ const bvid = ids.find((id) => id.startsWith("BV"));
402
+ const [aid, cid] = ids.filter((id) => !id.startsWith("BV"));
403
+ return {
404
+ page: +page || 1,
405
+ bvid,
406
+ aid,
407
+ cid,
408
+ autoplay: attrs.autoplay ?? false,
409
+ time: timeToSeconds(attrs.time),
410
+ title: attrs.title,
411
+ width: attrs.width ? parseRect(attrs.width) : "100%",
412
+ height: attrs.height ? parseRect(attrs.height) : "",
413
+ ratio: attrs.ratio ? parseRect(attrs.ratio) : ""
414
+ };
415
+ },
416
+ content(meta) {
417
+ const params = new URLSearchParams2();
418
+ if (meta.bvid) {
419
+ params.set("bvid", meta.bvid);
420
+ }
421
+ if (meta.aid) {
422
+ params.set("aid", meta.aid);
423
+ }
424
+ if (meta.cid) {
425
+ params.set("cid", meta.cid);
426
+ }
427
+ if (meta.page) {
428
+ params.set("p", meta.page.toString());
429
+ }
430
+ if (meta.time) {
431
+ params.set("t", meta.time.toString());
432
+ }
433
+ params.set("autoplay", meta.autoplay ? "1" : "0");
434
+ const source = `${BILIBILI_LINK}?${params.toString()}`;
435
+ return `<VideoBilibili src="${source}" width="${meta.width}" height="${meta.height}" ratio="${meta.ratio}" title="${meta.title}" />`;
436
+ }
437
+ });
438
+ };
439
+
440
+ // src/node/features/video/youtube.ts
441
+ import { URLSearchParams as URLSearchParams3 } from "node:url";
442
+ var YOUTUBE_LINK = "https://www.youtube.com/embed/";
443
+ var youtubePlugin = (md) => {
444
+ createRuleBlock(md, {
445
+ type: "youtube",
446
+ name: "video_youtube",
447
+ syntaxPattern: /^@\[youtube([^\]]*)\]\(([^)]*)\)/,
448
+ meta([, info = "", id = ""]) {
449
+ const { attrs } = resolveAttrs(info);
450
+ return {
451
+ id,
452
+ autoplay: attrs.autoplay ?? false,
453
+ loop: attrs.loop ?? false,
454
+ start: timeToSeconds(attrs.start),
455
+ end: timeToSeconds(attrs.end),
456
+ title: attrs.title,
457
+ width: attrs.width ? parseRect(attrs.width) : "100%",
458
+ height: attrs.height ? parseRect(attrs.height) : "",
459
+ ratio: attrs.ratio ? parseRect(attrs.ratio) : ""
460
+ };
461
+ },
462
+ content(meta) {
463
+ const params = new URLSearchParams3();
464
+ if (meta.autoplay) {
465
+ params.set("autoplay", "1");
466
+ }
467
+ if (meta.loop) {
468
+ params.set("loop", "1");
469
+ }
470
+ if (meta.start) {
471
+ params.set("start", meta.start.toString());
472
+ }
473
+ if (meta.end) {
474
+ params.set("end", meta.end.toString());
475
+ }
476
+ const source = `${YOUTUBE_LINK}/${meta.id}?${params.toString()}`;
477
+ return `<VideoYoutube src="${source}" width="${meta.width}" height="${meta.height}" ratio="${meta.ratio}" title="${meta.title}" />`;
478
+ }
479
+ });
480
+ };
481
+
482
+ // src/node/features/codepen.ts
483
+ var CODEPEN_LINK = "https://codepen.io/";
484
+ var codepenPlugin = (md) => {
485
+ createRuleBlock(md, {
486
+ type: "codepen",
487
+ syntaxPattern: /^@\[codepen([^\]]*)\]\(([^)]*)\)/,
488
+ meta: ([, info = "", source = ""]) => {
489
+ const { attrs } = resolveAttrs(info);
490
+ const [user, slash] = source.split("/");
491
+ return {
492
+ width: attrs.width ? parseRect(attrs.width) : "100%",
493
+ height: attrs.height ? parseRect(attrs.height) : "400px",
494
+ user,
495
+ slash,
496
+ title: attrs.title,
497
+ preview: attrs.preview,
498
+ editable: attrs.editable,
499
+ tab: attrs.tab ?? "result",
500
+ theme: attrs.theme
501
+ };
502
+ },
503
+ content: (meta) => {
504
+ const { title = "Codepen", height, width } = meta;
505
+ const params = new URLSearchParams();
506
+ if (meta.editable) {
507
+ params.set("editable", "true");
508
+ }
509
+ if (meta.tab) {
510
+ params.set("default-tab", meta.tab);
511
+ }
512
+ if (meta.theme) {
513
+ params.set("theme-id", meta.theme);
514
+ }
515
+ const middle = meta.preview ? "/embed/preview/" : "/embed/";
516
+ const link = `${CODEPEN_LINK}${meta.user}${middle}${meta.slash}?${params.toString()}`;
517
+ const style = `width:${width};height:${height};margin:16px auto;border-radius:5px;`;
518
+ return `<iframe class="code-pen-iframe-wrapper" src="${link}" title="${title}" style="${style}" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">See the Pen <a href="${CODEPEN_LINK}${meta.user}/pen/${meta.slash}">${title}</a> by ${meta.user} (<a href="${CODEPEN_LINK}${meta.user}">@${meta.user}</a>) on <a href="${CODEPEN_LINK}">CodePen</a>.</iframe>`;
519
+ }
520
+ });
521
+ };
522
+
523
+ // src/node/features/replit.ts
524
+ var replitPlugin = (md) => {
525
+ createRuleBlock(md, {
526
+ type: "replit",
527
+ syntaxPattern: /^@\[replit([^\]]*)\]\(([^)]*)\)/,
528
+ meta: ([, info = "", source = ""]) => {
529
+ const { attrs } = resolveAttrs(info);
530
+ return {
531
+ width: attrs.width ? parseRect(attrs.width) : "100%",
532
+ height: attrs.height ? parseRect(attrs.height) : "450px",
533
+ source: source.startsWith("@") ? source : `@${source}`,
534
+ title: attrs.title,
535
+ theme: attrs.theme || ""
536
+ };
537
+ },
538
+ content({ title, height, width, source, theme }) {
539
+ return `<ReplitViewer title="${title || ""}" height="${height}" width="${width}" source="${source}" theme="${theme}" />`;
540
+ }
541
+ });
542
+ };
543
+
544
+ // src/node/features/codeSandbox.ts
545
+ var codeSandboxPlugin = (md) => {
546
+ createRuleBlock(md, {
547
+ type: "codesandbox",
548
+ syntaxPattern: /^@\[codesandbox(?:\s+(embed|button))?([^\]]*)\]\(([^)]*)\)/,
549
+ meta([, type, info = "", source = ""]) {
550
+ const { attrs } = resolveAttrs(info);
551
+ const [profile, filepath2 = ""] = source.split("#");
552
+ const [user, id] = profile.includes("/") ? profile.split("/") : ["", profile];
553
+ return {
554
+ width: attrs.width ? parseRect(attrs.width) : "100%",
555
+ height: attrs.height ? parseRect(attrs.height) : "500px",
556
+ user,
557
+ id,
558
+ title: attrs.title ?? "",
559
+ console: attrs.console ?? false,
560
+ navbar: attrs.navbar ?? true,
561
+ layout: attrs.layout ?? "",
562
+ type: type || "embed",
563
+ filepath: filepath2
564
+ };
565
+ },
566
+ content({ title, height, width, user, id, type, filepath: filepath2, console, navbar, layout }) {
567
+ return `<CodeSandboxViewer title="${title}" height="${height}" width="${width}" user="${user}" id="${id}" type="${type}" filepath="${filepath2}" :console=${console} :navbar=${navbar} layout="${layout}" />`;
568
+ }
569
+ });
570
+ };
571
+
572
+ // src/node/features/jsfiddle.ts
573
+ var jsfiddlePlugin = (md) => {
574
+ createRuleBlock(md, {
575
+ type: "jsfiddle",
576
+ syntaxPattern: /^@\[jsfiddle([^\]]*)\]\(([^)]*)\)/,
577
+ meta([, info = "", source]) {
578
+ const { attrs } = resolveAttrs(info);
579
+ const [user, id] = source.split("/");
580
+ return {
581
+ width: attrs.width ? parseRect(attrs.width) : "100%",
582
+ height: attrs.height ? parseRect(attrs.height) : "400px",
583
+ user,
584
+ id,
585
+ title: attrs.title || "JS Fiddle",
586
+ tab: attrs.tab?.replace(/\s+/g, "") || "js,css,html,result",
587
+ theme: attrs.theme || "dark"
588
+ };
589
+ },
590
+ content: ({ title = "JS Fiddle", height, width, user, id, tab, theme }) => {
591
+ theme = theme === "dark" ? "/dark/" : "";
592
+ const link = `https://jsfiddle.net/${user}/${id}/embedded/${tab}${theme}`;
593
+ const style = `width:${width};height:${height};margin:16px auto;border:none;border-radius:5px;`;
594
+ return `<iframe class="js-fiddle-iframe-wrapper" style="${style}" title="${title}" src="${link}" allowfullscreen="true" allowpaymentrequest="true"></iframe>`;
595
+ }
596
+ });
597
+ };
598
+
599
+ // src/node/features/plot.ts
600
+ var [openTag2, endTag2] = ["!!", "!!"];
601
+ function createTokenizer2() {
602
+ return (state, silent) => {
603
+ let found = false;
604
+ const max = state.posMax;
605
+ const start = state.pos;
606
+ if (state.src.slice(start, start + 2) !== openTag2)
607
+ return false;
608
+ if (silent)
609
+ return false;
610
+ if (max - start < 5)
611
+ return false;
612
+ state.pos = start + 2;
613
+ while (state.pos < max) {
614
+ if (state.src.slice(state.pos - 1, state.pos + 1) === endTag2) {
615
+ found = true;
616
+ break;
617
+ }
618
+ state.md.inline.skipToken(state);
619
+ }
620
+ if (!found || start + 2 === state.pos) {
621
+ state.pos = start;
622
+ return false;
623
+ }
624
+ const content = state.src.slice(start + 2, state.pos - 1);
625
+ if (/^\s|\s$/.test(content)) {
626
+ state.pos = start;
627
+ return false;
628
+ }
629
+ state.posMax = state.pos - 1;
630
+ state.pos = start + 2;
631
+ const open = state.push("plot_open", "Plot", 1);
632
+ open.markup = openTag2;
633
+ const text = state.push("text", "", 0);
634
+ text.content = content;
635
+ const close = state.push("plot_close", "Plot", -1);
636
+ close.markup = endTag2;
637
+ state.pos = state.posMax + 2;
638
+ state.posMax = max;
639
+ return true;
640
+ };
641
+ }
642
+ var plotPlugin = (md) => {
643
+ md.inline.ruler.before("emphasis", "plot", createTokenizer2());
644
+ };
645
+
646
+ // src/node/features/langRepl.ts
647
+ import container2 from "markdown-it-container";
648
+ import { fs as fs2, getDirname, path as path2 } from "vuepress/utils";
649
+ var RE_INFO = /^(#editable)?(.*)$/;
650
+ function createReplContainer(md, lang) {
651
+ const type = `${lang}-repl`;
652
+ const validate = (info) => info.trim().startsWith(type);
653
+ const render = (tokens, index) => {
654
+ const token = tokens[index];
655
+ const info = token.info.trim().slice(type.length).trim() || "";
656
+ const [, editable, title] = info.match(RE_INFO) ?? [];
657
+ if (token.nesting === 1)
658
+ return `<CodeRepl ${editable ? "editable" : ""} title="${title || `${lang} playground`}">`;
659
+ else
660
+ return "</CodeRepl>";
661
+ };
662
+ md.use(container2, type, { validate, render });
663
+ }
664
+ async function langReplPlugin(app, md, {
665
+ theme,
666
+ go = false,
667
+ kotlin = false,
668
+ rust = false
669
+ }) {
670
+ if (kotlin) {
671
+ createReplContainer(md, "kotlin");
672
+ }
673
+ if (go) {
674
+ createReplContainer(md, "go");
675
+ }
676
+ if (rust) {
677
+ createReplContainer(md, "rust");
678
+ }
679
+ theme ??= { light: "github-light", dark: "github-dark" };
680
+ const data = { grammars: {} };
681
+ const themesPath = getDirname(import.meta.resolve("tm-themes"));
682
+ const grammarsPath = getDirname(import.meta.resolve("tm-grammars"));
683
+ const readTheme = (theme2) => read(path2.join(themesPath, "themes", `${theme2}.json`));
684
+ const readGrammar = (grammar) => read(path2.join(grammarsPath, "grammars", `${grammar}.json`));
685
+ if (typeof theme === "string") {
686
+ data.theme = await readTheme(theme);
687
+ } else {
688
+ data.theme = await Promise.all([
689
+ readTheme(theme.light),
690
+ readTheme(theme.dark)
691
+ ]).then(([light, dark]) => ({ light, dark }));
692
+ }
693
+ if (kotlin)
694
+ data.grammars.kotlin = await readGrammar("kotlin");
695
+ if (go)
696
+ data.grammars.go = await readGrammar("go");
697
+ if (rust)
698
+ data.grammars.rust = await readGrammar("rust");
699
+ await app.writeTemp(
700
+ "internal/md-power/replEditorData.js",
701
+ `export default ${JSON.stringify(data, null, 2)}`
702
+ );
703
+ }
704
+ async function read(file) {
705
+ try {
706
+ const content = await fs2.readFile(file, "utf-8");
707
+ return JSON.parse(content);
708
+ } catch {
709
+ }
710
+ return void 0;
711
+ }
712
+
713
+ // src/node/prepareConfigFile.ts
714
+ import { getDirname as getDirname2, path as path3 } from "vuepress/utils";
715
+ import { ensureEndingSlash } from "@vuepress/helper";
716
+ var { url: filepath } = import.meta;
717
+ var __dirname = getDirname2(filepath);
718
+ var CLIENT_FOLDER = ensureEndingSlash(
719
+ path3.resolve(__dirname, "../client")
720
+ );
721
+ async function prepareConfigFile(app, options) {
722
+ const imports = /* @__PURE__ */ new Set();
723
+ const enhances = /* @__PURE__ */ new Set();
724
+ imports.add(`import '@internal/md-power/icons.css'`);
725
+ if (options.pdf) {
726
+ imports.add(`import PDFViewer from '${CLIENT_FOLDER}components/PDFViewer.vue'`);
727
+ enhances.add(`app.component('PDFViewer', PDFViewer)`);
728
+ }
729
+ if (options.bilibili) {
730
+ imports.add(`import Bilibili from '${CLIENT_FOLDER}components/Bilibili.vue'`);
731
+ enhances.add(`app.component('VideoBilibili', Bilibili)`);
732
+ }
733
+ if (options.youtube) {
734
+ imports.add(`import Youtube from '${CLIENT_FOLDER}components/Youtube.vue'`);
735
+ enhances.add(`app.component('VideoYoutube', Youtube)`);
736
+ }
737
+ if (options.replit) {
738
+ imports.add(`import Replit from '${CLIENT_FOLDER}components/Replit.vue'`);
739
+ enhances.add(`app.component('ReplitViewer', Replit)`);
740
+ }
741
+ if (options.codeSandbox) {
742
+ imports.add(`import CodeSandbox from '${CLIENT_FOLDER}components/CodeSandbox.vue'`);
743
+ enhances.add(`app.component('CodeSandboxViewer', CodeSandbox)`);
744
+ }
745
+ if (options.plot) {
746
+ imports.add(`import Plot from '${CLIENT_FOLDER}components/Plot.vue'`);
747
+ enhances.add(`app.component('Plot', Plot)`);
748
+ }
749
+ if (options.repl) {
750
+ imports.add(`import CodeRepl from '${CLIENT_FOLDER}components/CodeRepl.vue'`);
751
+ enhances.add(`app.component('CodeRepl', CodeRepl)`);
752
+ }
753
+ if (options.caniuse) {
754
+ imports.add(`import CanIUse from '${CLIENT_FOLDER}components/CanIUse.vue'`);
755
+ enhances.add(`app.component('CanIUseViewer', CanIUse)`);
756
+ }
757
+ return app.writeTemp(
758
+ "md-power/config.js",
759
+ `import { defineClientConfig } from 'vuepress/client'
760
+ ${Array.from(imports.values()).join("\n")}
761
+
762
+ export default defineClientConfig({
763
+ enhance({ router, app }) {
764
+ ${Array.from(enhances.values()).map((item) => ` ${item}`).join("\n")}
765
+ }
766
+ })
767
+ `
768
+ );
769
+ }
770
+
771
+ // src/node/plugin.ts
772
+ function markdownPowerPlugin(options = {}) {
773
+ return (app) => {
774
+ const { initIcon, addIcon } = createIconCSSWriter(app, options.icons);
775
+ return {
776
+ name: "vuepress-plugin-md-power",
777
+ // clientConfigFile: path.resolve(__dirname, '../client/config.js'),
778
+ clientConfigFile: (app2) => prepareConfigFile(app2, options),
779
+ define: {
780
+ __MD_POWER_INJECT_OPTIONS__: options
781
+ },
782
+ onInitialized: async () => await initIcon(),
783
+ extendsBundlerOptions(bundlerOptions) {
784
+ if (options.repl) {
785
+ addViteOptimizeDepsInclude(
786
+ bundlerOptions,
787
+ app,
788
+ ["shiki/core", "shiki/wasm"]
789
+ );
790
+ }
791
+ },
792
+ extendsMarkdown: async (md, app2) => {
793
+ if (options.caniuse) {
794
+ const caniuse = options.caniuse === true ? {} : options.caniuse;
795
+ md.use(caniusePlugin, caniuse);
796
+ legacyCaniuse(md, caniuse);
797
+ }
798
+ if (options.pdf) {
799
+ md.use(pdfPlugin);
800
+ }
801
+ if (options.icons) {
802
+ md.use(iconsPlugin, addIcon);
803
+ }
804
+ if (options.bilibili) {
805
+ md.use(bilibiliPlugin);
806
+ }
807
+ if (options.youtube) {
808
+ md.use(youtubePlugin);
809
+ }
810
+ if (options.codepen) {
811
+ md.use(codepenPlugin);
812
+ }
813
+ if (options.replit) {
814
+ md.use(replitPlugin);
815
+ }
816
+ if (options.codeSandbox) {
817
+ md.use(codeSandboxPlugin);
818
+ }
819
+ if (options.jsfiddle) {
820
+ md.use(jsfiddlePlugin);
821
+ }
822
+ if (options.plot === true || typeof options.plot === "object" && options.plot.tag !== false) {
823
+ md.use(plotPlugin);
824
+ }
825
+ if (options.repl)
826
+ await langReplPlugin(app2, md, options.repl);
827
+ }
828
+ };
829
+ };
830
+ }
831
+ export {
832
+ markdownPowerPlugin
833
+ };