vuepress-plugin-md-power 1.0.0-rc.142 → 1.0.0-rc.144

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/node/index.js CHANGED
@@ -816,14 +816,14 @@ var definitions = {
816
816
  };
817
817
 
818
818
  // src/node/fileIcons/findIcon.ts
819
- function getFileIcon(fileName, type2) {
820
- const name = getFileIconName(fileName, type2);
819
+ function getFileIcon(fileName, type) {
820
+ const name = getFileIconName(fileName, type);
821
821
  if (!name)
822
- return type2 !== "folder" ? defaultFile : defaultFolder;
822
+ return type !== "folder" ? defaultFile : defaultFolder;
823
823
  return name;
824
824
  }
825
- function getFileIconName(fileName, type2 = "file") {
826
- if (type2 === "folder") {
825
+ function getFileIconName(fileName, type = "file") {
826
+ if (type === "folder") {
827
827
  const icon2 = definitions.folders[fileName];
828
828
  if (icon2)
829
829
  return icon2;
@@ -921,10 +921,10 @@ var codeTabs = (md, options = {}) => {
921
921
  tabOpenRenderer: ({ index }, tokens, tokenIndex) => {
922
922
  let foundFence = false;
923
923
  for (let i = tokenIndex; i < tokens.length; i++) {
924
- const { type: type2 } = tokens[i];
925
- if (type2 === "code-tabs_tab_close")
924
+ const { type } = tokens[i];
925
+ if (type === "code-tabs_tab_close")
926
926
  break;
927
- if ((type2 === "fence" || type2 === "import_code") && !foundFence) {
927
+ if ((type === "fence" || type === "import_code") && !foundFence) {
928
928
  foundFence = true;
929
929
  continue;
930
930
  }
@@ -946,6 +946,7 @@ import imageSize from "image-size";
946
946
  import { fs, logger, path } from "vuepress/utils";
947
947
 
948
948
  // src/node/utils/resolveAttrs.ts
949
+ import { camelCase } from "@pengzhanbo/utils";
949
950
  var RE_ATTR_VALUE = /(?:^|\s+)(?<attr>[\w-]+)(?:=\s*(?<quote>['"])(?<value>.+?)\k<quote>)?(?:\s+|$)/;
950
951
  function resolveAttrs(info) {
951
952
  info = info.trim();
@@ -955,23 +956,15 @@ function resolveAttrs(info) {
955
956
  const rawAttrs = info;
956
957
  let matched;
957
958
  while (matched = info.match(RE_ATTR_VALUE)) {
958
- const { attr, value } = matched.groups;
959
- attrs2[attr] = value ?? true;
959
+ const { attr, value = true } = matched.groups;
960
+ let v = typeof value === "string" ? value.trim() : value;
961
+ if (v === "true")
962
+ v = true;
963
+ else if (v === "false")
964
+ v = false;
965
+ attrs2[camelCase(attr)] = v;
960
966
  info = info.slice(matched[0].length);
961
967
  }
962
- Object.keys(attrs2).forEach((key) => {
963
- let value = attrs2[key];
964
- value = typeof value === "string" ? value.trim() : value;
965
- if (value === "true")
966
- value = true;
967
- else if (value === "false")
968
- value = false;
969
- attrs2[key] = value;
970
- if (key.includes("-")) {
971
- const _key = key.replace(/-(\w)/g, (_, c) => c.toUpperCase());
972
- attrs2[_key] = value;
973
- }
974
- });
975
968
  return { attrs: attrs2, rawAttrs };
976
969
  }
977
970
 
@@ -987,10 +980,10 @@ var BADGE_LIST = [
987
980
  "https://vercel.com/button"
988
981
  ];
989
982
  var cache = /* @__PURE__ */ new Map();
990
- async function imageSizePlugin(app, md, type2 = false) {
991
- if (!app.env.isBuild || !type2)
983
+ async function imageSizePlugin(app, md, type = false) {
984
+ if (!app.env.isBuild || !type)
992
985
  return;
993
- if (type2 === "all") {
986
+ if (type === "all") {
994
987
  const start = performance.now();
995
988
  try {
996
989
  await scanRemoteImageSize(app);
@@ -1158,17 +1151,63 @@ import { isPlainObject as isPlainObject2 } from "@vuepress/helper";
1158
1151
 
1159
1152
  // src/node/container/createContainer.ts
1160
1153
  import container from "markdown-it-container";
1161
- function createContainerPlugin(md, type2, { before, after } = {}) {
1154
+ function createContainerPlugin(md, type, { before, after } = {}) {
1162
1155
  const render = (tokens, index, options, env) => {
1163
1156
  const token = tokens[index];
1164
- const info = token.info.trim().slice(type2.length).trim() || "";
1157
+ const info = token.info.trim().slice(type.length).trim() || "";
1165
1158
  if (token.nesting === 1) {
1166
- return before?.(info, tokens, index, options, env) || `<div class="custom-container ${type2}">`;
1159
+ return before?.(info, tokens, index, options, env) ?? `<div class="custom-container ${type}">`;
1167
1160
  } else {
1168
- return after?.(info, tokens, index, options, env) || "</div>";
1161
+ return after?.(info, tokens, index, options, env) ?? "</div>";
1169
1162
  }
1170
1163
  };
1171
- md.use(container, type2, { render });
1164
+ md.use(container, type, { render });
1165
+ }
1166
+ function createContainerSyntaxPlugin(md, type, render) {
1167
+ const maker = ":";
1168
+ const markerMinLen = 3;
1169
+ function defineContainer(state, startLine, endLine, silent) {
1170
+ const start = state.bMarks[startLine] + state.tShift[startLine];
1171
+ const max = state.eMarks[startLine];
1172
+ let pos = start;
1173
+ if (state.src[pos] !== maker)
1174
+ return false;
1175
+ pos += markerMinLen;
1176
+ for (pos = start + 1; pos <= max; pos++) {
1177
+ if (state.src[pos] !== maker)
1178
+ break;
1179
+ }
1180
+ if (pos - start < markerMinLen)
1181
+ return false;
1182
+ const markup = state.src.slice(start, pos);
1183
+ const info = state.src.slice(pos, max).trim();
1184
+ if (!info.startsWith(type))
1185
+ return false;
1186
+ if (silent)
1187
+ return true;
1188
+ let line = startLine;
1189
+ let content = "";
1190
+ while (++line < endLine) {
1191
+ if (state.src.slice(state.bMarks[line], state.eMarks[line]).trim() === markup) {
1192
+ break;
1193
+ }
1194
+ content += `${state.src.slice(state.bMarks[line], state.eMarks[line])}
1195
+ `;
1196
+ }
1197
+ const token = state.push(`${type}_container`, "", 0);
1198
+ token.meta = resolveAttrs(info.slice(type.length)).attrs;
1199
+ token.content = content;
1200
+ token.markup = `${markup} ${type}`;
1201
+ token.map = [startLine, line + 1];
1202
+ state.line = line + 1;
1203
+ return true;
1204
+ }
1205
+ const defaultRender = (tokens, index) => {
1206
+ const { content } = tokens[index];
1207
+ return `<div class="custom-container ${type}">${content}</div>`;
1208
+ };
1209
+ md.block.ruler.before("fence", `${type}_definition`, defineContainer);
1210
+ md.renderer.rules[`${type}_container`] = render ?? defaultRender;
1172
1211
  }
1173
1212
 
1174
1213
  // src/node/container/align.ts
@@ -1181,13 +1220,37 @@ function alignPlugin(md) {
1181
1220
  }
1182
1221
  }
1183
1222
 
1223
+ // src/node/utils/stringifyAttrs.ts
1224
+ import { isBoolean, isNull, isNumber, isString, isUndefined, kebabCase } from "@pengzhanbo/utils";
1225
+ function stringifyAttrs(attrs2, withUndefined = false) {
1226
+ const result = Object.entries(attrs2).map(([key, value]) => {
1227
+ const k = kebabCase(key);
1228
+ if (isUndefined(value) || value === "undefined")
1229
+ return withUndefined ? `:${k}="undefined"` : "";
1230
+ if (isNull(value) || value === "null")
1231
+ return withUndefined ? `:${k}="null"` : "";
1232
+ if (value === "true")
1233
+ value = true;
1234
+ if (value === "false")
1235
+ value = false;
1236
+ if (isBoolean(value))
1237
+ return value ? `${k}` : "";
1238
+ if (isNumber(value))
1239
+ return `:${k}="${value}"`;
1240
+ if (isString(value) && (value[0] === "{" || value[0] === "["))
1241
+ return `:${k}="${value.replaceAll('"', "'")}"`;
1242
+ const hasDynamic = key[0] === ":";
1243
+ return `${hasDynamic ? ":" : ""}${k}="${String(value)}"`;
1244
+ }).filter(Boolean).join(" ");
1245
+ return result ? ` ${result}` : "";
1246
+ }
1247
+
1184
1248
  // src/node/container/card.ts
1185
1249
  function cardPlugin(md) {
1186
1250
  createContainerPlugin(md, "card", {
1187
1251
  before(info) {
1188
1252
  const { attrs: attrs2 } = resolveAttrs(info);
1189
- const { title, icon } = attrs2;
1190
- return `<VPCard${title ? ` title="${title}"` : ""}${icon ? ` icon="${icon}"` : ""}>`;
1253
+ return `<VPCard${stringifyAttrs(attrs2)}>`;
1191
1254
  },
1192
1255
  after: () => "</VPCard>"
1193
1256
  });
@@ -1198,63 +1261,17 @@ function cardPlugin(md) {
1198
1261
  createContainerPlugin(md, "card-masonry", {
1199
1262
  before: (info) => {
1200
1263
  const { attrs: attrs2 } = resolveAttrs(info);
1201
- let cols;
1202
- if (attrs2.cols) {
1203
- cols = attrs2.cols[0] === "{" ? attrs2.cols : Number.parseInt(`${attrs2.cols}`);
1204
- }
1205
- const gap = Number.parseInt(`${attrs2.gap}`);
1206
- return `<VPCardMasonry${cols ? ` :cols="${cols}"` : ""}${gap >= 0 ? ` :gap="${gap}"` : ""}>`;
1264
+ if (attrs2.cols)
1265
+ attrs2.cols = attrs2.cols[0] === "{" ? attrs2.cols : Number.parseInt(`${attrs2.cols}`);
1266
+ if (attrs2.gap)
1267
+ attrs2.gap = Number(attrs2.gap);
1268
+ return `<VPCardMasonry${stringifyAttrs(attrs2)}>`;
1207
1269
  },
1208
1270
  after: () => "</VPCardMasonry>"
1209
1271
  });
1210
1272
  }
1211
1273
 
1212
1274
  // src/node/container/chat.ts
1213
- var chatPlugin = (md) => {
1214
- md.block.ruler.before("fence", "chat_def", chatDef);
1215
- md.renderer.rules.chat_container = (tokens, idx, _, env) => {
1216
- const { meta, content } = tokens[idx];
1217
- const { title } = meta;
1218
- const messages = parseChatContent(content);
1219
- return `<div class="vp-chat">
1220
- <div class="vp-chat-header">
1221
- <p class="vp-chat-title">${title || "Chat"}</p>
1222
- </div>
1223
- <div class="vp-chat-content">
1224
- ${chatMessagesRender(md, env, messages)}
1225
- </div>
1226
- </div>`;
1227
- };
1228
- };
1229
- function chatDef(state, startLine, endLine, silent) {
1230
- const start = state.bMarks[startLine] + state.tShift[startLine];
1231
- const max = state.eMarks[startLine];
1232
- let pos = start;
1233
- if (state.src.slice(pos, pos + 3) !== ":::")
1234
- return false;
1235
- pos += 3;
1236
- const info = state.src.slice(start + 3, max).trim();
1237
- if (!info.startsWith("chat"))
1238
- return false;
1239
- if (silent)
1240
- return true;
1241
- let line = startLine;
1242
- let content = "";
1243
- while (++line < endLine) {
1244
- if (state.src.slice(state.bMarks[line], state.eMarks[line]).trim() === ":::") {
1245
- break;
1246
- }
1247
- content += `${state.src.slice(state.bMarks[line], state.eMarks[line])}
1248
- `;
1249
- }
1250
- const token = state.push("chat_container", "", 0);
1251
- token.meta = resolveAttrs(info).attrs;
1252
- token.content = content;
1253
- token.markup = "::: chat";
1254
- token.map = [startLine, line + 1];
1255
- state.line = line + 1;
1256
- return true;
1257
- }
1258
1275
  function chatMessagesRender(md, env, messages) {
1259
1276
  let currentDate = "";
1260
1277
  return messages.map(({ sender, username, date, content }) => {
@@ -1303,6 +1320,18 @@ function parseChatContent(content) {
1303
1320
  }
1304
1321
  return messages;
1305
1322
  }
1323
+ var chatPlugin = (md) => createContainerSyntaxPlugin(
1324
+ md,
1325
+ "chat",
1326
+ (tokens, idx, _, env) => `<div class="vp-chat">
1327
+ <div class="vp-chat-header">
1328
+ <p class="vp-chat-title">${tokens[idx].meta?.title || "Chat"}</p>
1329
+ </div>
1330
+ <div class="vp-chat-content">
1331
+ ${chatMessagesRender(md, env, parseChatContent(tokens[idx].content))}
1332
+ </div>
1333
+ </div>`
1334
+ );
1306
1335
 
1307
1336
  // src/node/container/collapse.ts
1308
1337
  function collapsePlugin(md) {
@@ -1311,14 +1340,14 @@ function collapsePlugin(md) {
1311
1340
  const { attrs: attrs2 } = resolveAttrs(info);
1312
1341
  const idx = parseCollapse(tokens, index, attrs2);
1313
1342
  const { accordion } = attrs2;
1314
- return `<VPCollapse${accordion ? " accordion" : ""}${idx !== void 0 ? ` :index="${idx}"` : ""}>`;
1343
+ return `<VPCollapse${stringifyAttrs({ accordion, index: idx })}>`;
1315
1344
  },
1316
1345
  after: () => `</VPCollapse>`
1317
1346
  });
1318
1347
  md.renderer.rules.collapse_item_open = (tokens, idx) => {
1319
1348
  const token = tokens[idx];
1320
1349
  const { expand, index } = token.meta;
1321
- return `<VPCollapseItem${expand ? " expand" : ""}${` :index="${index}"`}>`;
1350
+ return `<VPCollapseItem${stringifyAttrs({ expand, index })}>`;
1322
1351
  };
1323
1352
  md.renderer.rules.collapse_item_close = () => "</VPCollapseItem>";
1324
1353
  md.renderer.rules.collapse_item_title_open = () => "<template #title>";
@@ -1420,180 +1449,116 @@ function demoWrapperPlugin(md) {
1420
1449
  }
1421
1450
 
1422
1451
  // src/node/container/fileTree.ts
1423
- import container2 from "markdown-it-container";
1424
- import Token from "markdown-it/lib/token.mjs";
1425
- import { removeEndingSlash, removeLeadingSlash } from "vuepress/shared";
1426
- var type = "file-tree";
1427
- var closeType = `container_${type}_close`;
1428
- var componentName = "FileTreeItem";
1429
- var itemOpen = "file_tree_item_open";
1430
- var itemClose = "file_tree_item_close";
1452
+ import { removeEndingSlash } from "vuepress/shared";
1453
+ function parseFileTreeRawContent(content) {
1454
+ const root = { info: "", level: -1, children: [] };
1455
+ const stack = [root];
1456
+ const lines = content.trim().split("\n");
1457
+ for (const line of lines) {
1458
+ const match = line.match(/^(\s*)-(.*)$/);
1459
+ if (!match)
1460
+ continue;
1461
+ const level = Math.floor(match[1].length / 2);
1462
+ const info = match[2].trim();
1463
+ while (stack.length > 0 && stack[stack.length - 1].level >= level) {
1464
+ stack.pop();
1465
+ }
1466
+ const parent = stack[stack.length - 1];
1467
+ const node = { info, level, children: [] };
1468
+ parent.children.push(node);
1469
+ stack.push(node);
1470
+ }
1471
+ return root.children;
1472
+ }
1473
+ var RE_FOCUS = /^\*\*(.*)\*\*(?:$|\s+)/;
1474
+ function parseFileTreeNodeInfo(info) {
1475
+ let filename = "";
1476
+ let comment = "";
1477
+ let focus = false;
1478
+ let expanded = true;
1479
+ let type = "file";
1480
+ info = info.replace(RE_FOCUS, (_, matched) => {
1481
+ filename = matched;
1482
+ focus = true;
1483
+ return "";
1484
+ });
1485
+ if (filename === "" && !focus) {
1486
+ const spaceIndex = info.indexOf(" ");
1487
+ filename = info.slice(0, spaceIndex === -1 ? info.length : spaceIndex);
1488
+ info = spaceIndex === -1 ? "" : info.slice(spaceIndex);
1489
+ }
1490
+ comment = info.trim();
1491
+ if (filename.endsWith("/")) {
1492
+ type = "folder";
1493
+ expanded = false;
1494
+ filename = removeEndingSlash(filename);
1495
+ }
1496
+ return { filename, comment, focus, expanded, type };
1497
+ }
1431
1498
  function fileTreePlugin(md, options = {}) {
1432
- const getIcon = (filename, type2, mode) => {
1499
+ const getIcon = (filename, type, mode) => {
1433
1500
  mode ||= options.icon || "colored";
1434
1501
  if (mode === "simple")
1435
- return type2 === "folder" ? defaultFolder : defaultFile;
1436
- return getFileIcon(filename, type2);
1502
+ return type === "folder" ? defaultFolder : defaultFile;
1503
+ return getFileIcon(filename, type);
1437
1504
  };
1438
- const render = (tokens, idx) => {
1439
- const { attrs: attrs2 } = resolveAttrs(tokens[idx].info.slice(type.length - 1));
1440
- if (tokens[idx].nesting === 1) {
1441
- const hasRes = [];
1442
- for (let i = idx + 1; !(tokens[i].nesting === -1 && tokens[i].type === closeType); ++i) {
1443
- const token = tokens[i];
1444
- if (token.type === "list_item_open") {
1445
- const result = resolveTreeNodeInfo(tokens, token, i);
1446
- if (result) {
1447
- hasRes.push(token.level);
1448
- const [info, inline] = result;
1449
- const { filename, type: type2, expanded, empty } = info;
1450
- const icon = getIcon(filename, type2, attrs2.icon);
1451
- token.type = itemOpen;
1452
- token.tag = componentName;
1453
- token.attrSet("type", type2);
1454
- token.attrSet(":expanded", expanded ? "true" : "false");
1455
- token.attrSet(":empty", empty ? "true" : "false");
1456
- updateInlineToken(inline, info, icon);
1457
- } else {
1458
- hasRes.push(-1);
1459
- }
1460
- } else if (token.type === "list_item_close") {
1461
- if (token.level === hasRes.pop()) {
1462
- token.type = itemClose;
1463
- token.tag = componentName;
1464
- }
1465
- }
1466
- }
1467
- const title = attrs2.title;
1468
- return `<div class="vp-file-tree">${title ? `<p class="vp-file-tree-title">${title}</p>` : ""}`;
1469
- } else {
1470
- return "</div>";
1471
- }
1472
- };
1473
- md.use(container2, type, { render });
1474
- }
1475
- function resolveTreeNodeInfo(tokens, current, idx) {
1476
- let hasInline = false;
1477
- let hasChildren = false;
1478
- let inline;
1479
- for (let i = idx + 1; !(tokens[i].level === current.level && tokens[i].type === "list_item_close"); ++i) {
1480
- if (tokens[i].type === "inline" && !hasInline) {
1481
- inline = tokens[i];
1482
- hasInline = true;
1483
- } else if (tokens[i].tag === "ul") {
1484
- hasChildren = true;
1485
- }
1486
- if (hasInline && hasChildren)
1487
- break;
1488
- }
1489
- if (!hasInline)
1490
- return void 0;
1491
- const children = inline.children.filter((token) => token.type === "text" && token.content || token.tag === "strong");
1492
- const filename = children.filter((token) => token.type === "text").map((token) => token.content).join(" ").split(/\s+/)[0];
1493
- const focus = children[0]?.tag === "strong";
1494
- const type2 = hasChildren || filename.endsWith("/") ? "folder" : "file";
1495
- const info = {
1496
- filename: removeLeadingSlash(removeEndingSlash(filename)),
1497
- type: type2,
1498
- focus,
1499
- empty: !hasChildren,
1500
- expanded: type2 === "folder" && !filename.endsWith("/")
1501
- };
1502
- return [info, inline];
1503
- }
1504
- function updateInlineToken(inline, info, icon) {
1505
- const children = inline.children;
1506
- const tokens = [];
1507
- const wrapperOpen = new Token("span_open", "span", 1);
1508
- const wrapperClose = new Token("span_close", "span", -1);
1509
- wrapperOpen.attrSet("class", `tree-node ${info.type}`);
1510
- tokens.push(wrapperOpen);
1511
- if (info.filename !== "..." && info.filename !== "\u2026") {
1512
- const iconOpen = new Token("vp_iconify_open", "VPIcon", 1);
1513
- iconOpen.attrSet("name", icon);
1514
- const iconClose = new Token("vp_iconify_close", "VPIcon", -1);
1515
- tokens.push(iconOpen, iconClose);
1516
- }
1517
- const fileOpen = new Token("span_open", "span", 1);
1518
- fileOpen.attrSet("class", `name${info.focus ? " focus" : ""}`);
1519
- tokens.push(fileOpen);
1520
- let isStrongTag = false;
1521
- while (children.length) {
1522
- const token = children.shift();
1523
- if (token.type === "text" && token.content) {
1524
- if (token.content.includes(" ")) {
1525
- const [first, ...other] = token.content.split(" ");
1526
- const text = new Token("text", "", 0);
1527
- text.content = removeEndingSlash(first);
1528
- tokens.push(text);
1529
- const comment = new Token("text", "", 0);
1530
- comment.content = other.join(" ");
1531
- children.unshift(comment);
1532
- } else {
1533
- token.content = removeEndingSlash(token.content);
1534
- tokens.push(token);
1535
- }
1536
- if (!isStrongTag)
1537
- break;
1538
- } else if (token.tag === "strong") {
1539
- token.content = removeEndingSlash(token.content);
1540
- tokens.push(token);
1541
- if (token.nesting === 1) {
1542
- isStrongTag = true;
1543
- } else {
1544
- break;
1545
- }
1546
- } else {
1547
- tokens.push(token);
1505
+ const renderFileTree = (nodes, meta) => nodes.map((node) => {
1506
+ const { info, level, children } = node;
1507
+ const { filename, comment, focus, expanded, type } = parseFileTreeNodeInfo(info);
1508
+ const isOmit = filename === "\u2026" || filename === "...";
1509
+ if (children.length === 0 && type === "folder") {
1510
+ children.push({ info: "\u2026", level: level + 1, children: [] });
1511
+ }
1512
+ const nodeType = children.length > 0 ? "folder" : type;
1513
+ const renderedComment = comment ? `<template #comment>${md.renderInline(comment.replaceAll("#", "#"))}</template>` : "";
1514
+ const renderedIcon = !isOmit ? `<template #icon><VPIcon name="${getIcon(filename, nodeType, meta.icon)}" /></template>` : "";
1515
+ const props = {
1516
+ expanded: nodeType === "folder" ? expanded : false,
1517
+ focus,
1518
+ type: nodeType,
1519
+ filename
1520
+ };
1521
+ return `<FileTreeNode${stringifyAttrs(props)}>
1522
+ ${renderedIcon}${renderedComment}${children.length > 0 ? renderFileTree(children, meta) : ""}
1523
+ </FileTreeNode>`;
1524
+ }).join("\n");
1525
+ return createContainerSyntaxPlugin(
1526
+ md,
1527
+ "file-tree",
1528
+ (tokens, index) => {
1529
+ const token = tokens[index];
1530
+ const nodes = parseFileTreeRawContent(token.content);
1531
+ const meta = token.meta;
1532
+ return `<div class="vp-file-tree">${meta.title ? `<p class="vp-file-tree-title">${meta.title}</p>` : ""}${renderFileTree(nodes, meta)}</div>
1533
+ `;
1548
1534
  }
1549
- }
1550
- const fileClose = new Token("span_close", "span", -1);
1551
- tokens.push(fileClose);
1552
- if (children.filter((token) => token.type === "text" && token.content.trim()).length) {
1553
- const commentOpen = new Token("span_open", "span", 1);
1554
- commentOpen.attrSet("class", "comment");
1555
- const commentClose = new Token("span_close", "span", -1);
1556
- tokens.push(commentOpen, ...children, commentClose);
1557
- }
1558
- tokens.push(wrapperClose);
1559
- inline.children = tokens;
1535
+ );
1560
1536
  }
1561
1537
 
1562
1538
  // src/node/container/langRepl.ts
1563
1539
  import { promises as fs2 } from "node:fs";
1564
1540
  import { resolveModule } from "local-pkg";
1565
- import container3 from "markdown-it-container";
1566
1541
  import { colors, logger as logger2, path as path2 } from "vuepress/utils";
1567
- var RE_INFO = /^(#editable)?(.*)$/;
1568
- function createReplContainer(md, lang) {
1569
- const type2 = `${lang}-repl`;
1570
- const validate = (info) => info.trim().startsWith(type2);
1571
- const render = (tokens, index) => {
1572
- const token = tokens[index];
1573
- const info = token.info.trim().slice(type2.length).trim() || "";
1574
- const [, editable, title] = info.match(RE_INFO);
1575
- if (token.nesting === 1)
1576
- return `<CodeRepl ${editable ? "editable" : ""} title="${title || `${lang} playground`}">`;
1577
- else
1578
- return "</CodeRepl>";
1579
- };
1580
- md.use(container3, type2, { validate, render });
1581
- }
1582
1542
  async function langReplPlugin(app, md, {
1583
1543
  theme,
1584
1544
  go = false,
1585
1545
  kotlin = false,
1586
1546
  rust = false
1587
1547
  }) {
1588
- if (kotlin) {
1589
- createReplContainer(md, "kotlin");
1590
- }
1591
- if (go) {
1592
- createReplContainer(md, "go");
1593
- }
1594
- if (rust) {
1595
- createReplContainer(md, "rust");
1596
- }
1548
+ const container3 = (lang) => createContainerPlugin(md, `${lang}-repl`, {
1549
+ before(info) {
1550
+ const { attrs: attrs2 } = resolveAttrs(info);
1551
+ const { editable, title } = attrs2;
1552
+ return `<CodeRepl${stringifyAttrs({ editable, title: title || `${lang} playground` })}>`;
1553
+ },
1554
+ after: () => "</CodeRepl>"
1555
+ });
1556
+ if (kotlin)
1557
+ container3("kotlin");
1558
+ if (go)
1559
+ container3("go");
1560
+ if (rust)
1561
+ container3("rust");
1597
1562
  theme ??= { light: "github-light", dark: "github-dark" };
1598
1563
  const data = { grammars: {} };
1599
1564
  try {
@@ -1634,7 +1599,9 @@ async function read(file) {
1634
1599
 
1635
1600
  // src/node/container/npmTo.ts
1636
1601
  import { isArray } from "@vuepress/helper";
1637
- import container4 from "markdown-it-container";
1602
+ import { colors as colors2 } from "vuepress/utils";
1603
+
1604
+ // src/node/container/npmToPreset.ts
1638
1605
  var ALLOW_LIST = ["npm", "pnpm", "yarn", "bun", "deno"];
1639
1606
  var BOOL_FLAGS = ["--no-save", "-B", "--save-bundle", "--save-dev", "-D", "--save-prod", "-P", "--save-peer", "-O", "--save-optional", "-E", "--save-exact", "-y", "--yes", "-g", "--global"];
1640
1607
  var DEFAULT_TABS = ["npm", "pnpm", "yarn"];
@@ -1818,28 +1785,32 @@ var MANAGERS_CONFIG = {
1818
1785
  deno: { cli: "deno install --frozen" }
1819
1786
  }
1820
1787
  };
1788
+
1789
+ // src/node/container/npmTo.ts
1821
1790
  function npmToPlugins(md, options = {}) {
1822
- const type2 = "npm-to";
1823
1791
  const opt = isArray(options) ? { tabs: options } : options;
1824
1792
  const defaultTabs = opt.tabs?.length ? opt.tabs : DEFAULT_TABS;
1825
- const render = (tokens, idx) => {
1826
- const { attrs: attrs2 } = resolveAttrs(tokens[idx].info.trim().slice(type2.length));
1827
- const tabs2 = attrs2.tabs ? attrs2.tabs.split(/,\s*/) : defaultTabs;
1828
- if (tokens[idx].nesting === 1) {
1793
+ createContainerPlugin(md, "npm-to", {
1794
+ before: (info, tokens, idx, _opt, env) => {
1795
+ const { attrs: attrs2 } = resolveAttrs(info);
1796
+ const tabs2 = attrs2.tabs ? attrs2.tabs.split(/,\s*/) : defaultTabs;
1829
1797
  const token = tokens[idx + 1];
1830
- const info = token.info.trim();
1831
1798
  if (token.type === "fence") {
1832
1799
  const content = token.content;
1833
1800
  token.hidden = true;
1834
1801
  token.type = "text";
1835
1802
  token.content = "";
1836
1803
  const lines = content.split(/(\n|\s*&&\s*)/);
1837
- return md.render(resolveNpmTo(lines, info, idx, tabs2), {});
1804
+ return md.render(
1805
+ resolveNpmTo(lines, token.info.trim(), idx, tabs2),
1806
+ cleanMarkdownEnv(env)
1807
+ );
1838
1808
  }
1839
- }
1840
- return "";
1841
- };
1842
- md.use(container4, type2, { render });
1809
+ console.warn(`${colors2.yellow("[vuepress-plugin-md-power]")} Invalid npm-to container in ${colors2.gray(env.filePathRelative || env.filePath)}`);
1810
+ return "";
1811
+ },
1812
+ after: () => ""
1813
+ });
1843
1814
  }
1844
1815
  function resolveNpmTo(lines, info, idx, tabs2) {
1845
1816
  tabs2 = validateTabs(tabs2);
@@ -2017,15 +1988,17 @@ function timelinePlugin(md) {
2017
1988
  before(info, tokens, index) {
2018
1989
  parseTimeline(tokens, index);
2019
1990
  const { attrs: attrs2 } = resolveAttrs(info);
2020
- const { horizontal, card, placement, line } = attrs2;
2021
- return `<VPTimeline${horizontal ? " horizontal" : ""}${card ? " card" : ' :card="undefined"'}${placement ? ` placement="${placement}"` : ""}${line ? ` line="${line}"` : ""}>`;
1991
+ attrs2.card ??= void 0;
1992
+ return `<VPTimeline${stringifyAttrs(attrs2, true)}>`;
2022
1993
  },
2023
1994
  after: () => "</VPTimeline>"
2024
1995
  });
2025
1996
  md.renderer.rules.timeline_item_open = (tokens, idx) => {
2026
1997
  const token = tokens[idx];
2027
- const { time, type: type2, icon, color, line, card, placement } = token.meta;
2028
- return `<VPTimelineItem${time ? ` time="${time}"` : ""}${type2 ? ` type="${type2}"` : ""}${color ? ` color="${color}"` : ""}${line ? ` line="${line}"` : ""}${icon ? ` icon="${icon}"` : ""}${card === "true" ? " card" : card === "false" ? "" : ' :card="undefined"'}${placement ? ` placement="${placement}"` : ""}>${icon ? `<template #icon><VPIcon name="${icon}"/></template>` : ""}`;
1998
+ const attrs2 = token.meta;
1999
+ attrs2.card ??= void 0;
2000
+ const icon = attrs2.icon;
2001
+ return `<VPTimelineItem${stringifyAttrs(attrs2, true)}>${icon ? `<template #icon><VPIcon name="${icon}"/></template>` : ""}`;
2029
2002
  };
2030
2003
  md.renderer.rules.timeline_item_close = () => "</VPTimelineItem>";
2031
2004
  md.renderer.rules.timeline_item_title_open = () => "<template #title>";
@@ -2125,20 +2098,20 @@ async function containerPlugin(app, md, options) {
2125
2098
  }
2126
2099
 
2127
2100
  // src/node/demo/demo.ts
2128
- import container5 from "markdown-it-container";
2101
+ import container2 from "markdown-it-container";
2129
2102
 
2130
2103
  // src/node/embed/createEmbedRuleBlock.ts
2131
2104
  function createEmbedRuleBlock(md, {
2132
- type: type2,
2133
- name = type2,
2105
+ type,
2106
+ name = type,
2134
2107
  syntaxPattern,
2135
2108
  beforeName = "import_code",
2136
2109
  ruleOptions = { alt: ["paragraph", "reference", "blockquote", "list"] },
2137
2110
  meta,
2138
2111
  content
2139
2112
  }) {
2140
- const MIN_LENGTH = type2.length + 5;
2141
- const START_CODES = [64, 91, ...type2.split("").map((c) => c.charCodeAt(0))];
2113
+ const MIN_LENGTH = type.length + 5;
2114
+ const START_CODES = [64, 91, ...type.split("").map((c) => c.charCodeAt(0))];
2142
2115
  md.block.ruler.before(
2143
2116
  beforeName,
2144
2117
  name,
@@ -2219,7 +2192,7 @@ function markdownEmbed(app, md, env, { url, title, desc, codeSetting = "", expan
2219
2192
  if (!env.demoFiles.some((d) => d.path === filepath2)) {
2220
2193
  env.demoFiles.push(demo);
2221
2194
  }
2222
- return `<VPDemoBasic type="markdown"${title ? ` title="${title}"` : ""}${desc ? ` desc="${desc}"` : ""}${expanded ? " expanded" : ""}>
2195
+ return `<VPDemoBasic${stringifyAttrs({ type: "markdown", title, desc, expanded })}>
2223
2196
  ${md.render(code, { filepath: env.filePath, filepathRelative: env.filePathRelative })}
2224
2197
  <template #code>
2225
2198
  ${md.render(`\`\`\`md ${codeSetting}
@@ -2232,7 +2205,7 @@ var markdownContainerRender = {
2232
2205
  before(app, md, env, meta, codeMap) {
2233
2206
  const { title, desc, expanded = false } = meta;
2234
2207
  const code = codeMap.md || "";
2235
- return `<VPDemoBasic type="markdown"${title ? ` title="${title}"` : ""}${desc ? ` desc="${desc}"` : ""}${expanded ? " expanded" : ""}>
2208
+ return `<VPDemoBasic${stringifyAttrs({ type: "markdown", title, desc, expanded })}>
2236
2209
  ${md.render(code, { filepath: env.filePath, filepathRelative: env.filePathRelative })}
2237
2210
  <template #code>`;
2238
2211
  },
@@ -2269,8 +2242,8 @@ var compiler = {
2269
2242
  }),
2270
2243
  stylus: importer(() => import("stylus"))
2271
2244
  };
2272
- async function compileScript(source, type2) {
2273
- const key = `${type2}:::${source}`;
2245
+ async function compileScript(source, type) {
2246
+ const key = `${type}:::${source}`;
2274
2247
  if (cache2.has(key))
2275
2248
  return cache2.get(key);
2276
2249
  const transform = await compiler.script();
@@ -2278,31 +2251,31 @@ async function compileScript(source, type2) {
2278
2251
  target: "es2018",
2279
2252
  platform: "browser",
2280
2253
  format: "cjs",
2281
- loader: type2 === "ts" ? "ts" : "js",
2254
+ loader: type === "ts" ? "ts" : "js",
2282
2255
  sourcemap: false
2283
2256
  });
2284
2257
  cache2.set(key, res.code);
2285
2258
  return res.code;
2286
2259
  }
2287
- async function compileStyle(source, type2) {
2288
- const key = `${type2}:::${source}`;
2260
+ async function compileStyle(source, type) {
2261
+ const key = `${type}:::${source}`;
2289
2262
  if (cache2.has(key))
2290
2263
  return cache2.get(key);
2291
- if (type2 === "css")
2264
+ if (type === "css")
2292
2265
  return source;
2293
- if (type2 === "less") {
2266
+ if (type === "less") {
2294
2267
  const less = await compiler.less();
2295
2268
  const res = await less.render(source);
2296
2269
  cache2.set(key, res.css);
2297
2270
  return res.css;
2298
2271
  }
2299
- if (type2 === "scss") {
2272
+ if (type === "scss") {
2300
2273
  const sass = await compiler.sass();
2301
2274
  const res = sass.compileString(source);
2302
2275
  cache2.set(key, res.css);
2303
2276
  return res.css;
2304
2277
  }
2305
- if (type2 === "stylus") {
2278
+ if (type === "stylus") {
2306
2279
  const stylus = await compiler.stylus();
2307
2280
  const res = stylus.render(source);
2308
2281
  cache2.set(key, res);
@@ -2520,7 +2493,7 @@ function normalEmbed(app, md, env, { url, title, desc, codeSetting = "", expande
2520
2493
  env.demoFiles.push(demo);
2521
2494
  insertSetupScript({ ...demo, path: output }, env);
2522
2495
  }
2523
- return `<VPDemoNormal :config="${name}"${title ? ` title="${title}"` : ""}${desc ? ` desc="${desc}"` : ""}${expanded ? " expanded" : ""}>
2496
+ return `<VPDemoNormal${stringifyAttrs({ ":config": name, title, desc, expanded })}>
2524
2497
  ${codeToHtml(md, source, codeSetting)}
2525
2498
  </VPDemoNormal>`;
2526
2499
  }
@@ -2538,7 +2511,7 @@ var normalContainerRender = {
2538
2511
  }
2539
2512
  const source = parseContainerCode(codeMap);
2540
2513
  compileCode(source, output);
2541
- return `<VPDemoNormal :config="${name}"${title ? ` title="${title}"` : ""}${desc ? ` desc="${desc}"` : ""}${expanded ? " expanded" : ""}>`;
2514
+ return `<VPDemoNormal${stringifyAttrs({ ":config": name, title, desc, expanded })}>`;
2542
2515
  },
2543
2516
  after: () => "</VPDemoNormal>",
2544
2517
  token(token) {
@@ -2624,7 +2597,7 @@ function vueEmbed(app, md, env, { url, title, desc, codeSetting = "", expanded =
2624
2597
  env.demoFiles.push(demo);
2625
2598
  insertSetupScript(demo, env);
2626
2599
  }
2627
- return `<VPDemoBasic type="vue"${title ? ` title="${title}"` : ""}${desc ? ` desc="${desc}"` : ""}${expanded ? " expanded" : ""}>
2600
+ return `<VPDemoBasic${stringifyAttrs({ type: "vue", title, desc, expanded })}>
2628
2601
  <${name} />
2629
2602
  <template #code>
2630
2603
  ${md.render(`\`\`\`${ext}${codeSetting}
@@ -2637,10 +2610,10 @@ var target3 = "md-power/demo/vue";
2637
2610
  var vueContainerRender = {
2638
2611
  before: (app, md, env, meta, codeMap) => {
2639
2612
  const { url, title, desc, expanded = false } = meta;
2640
- const componentName2 = `DemoContainer${url}`;
2613
+ const componentName = `DemoContainer${url}`;
2641
2614
  const prefix = (env.filePathRelative || "").replace(/\.md$/, "").replace(/\//g, "-");
2642
2615
  env.demoFiles ??= [];
2643
- const output = app.dir.temp(path6.join(target3, `${prefix}-${componentName2}`));
2616
+ const output = app.dir.temp(path6.join(target3, `${prefix}-${componentName}`));
2644
2617
  if (codeMap.vue || codeMap.js || codeMap.ts) {
2645
2618
  let scriptOutput = output;
2646
2619
  let content = "";
@@ -2655,7 +2628,7 @@ var vueContainerRender = {
2655
2628
  content = codeMap.js;
2656
2629
  }
2657
2630
  content = transformImports(content, env.filePath || "");
2658
- const script = { type: "vue", export: componentName2, path: scriptOutput, gitignore: true };
2631
+ const script = { type: "vue", export: componentName, path: scriptOutput, gitignore: true };
2659
2632
  writeFileSync(scriptOutput, content);
2660
2633
  if (!env.demoFiles.some((d) => d.path === scriptOutput)) {
2661
2634
  env.demoFiles.push(script);
@@ -2685,8 +2658,8 @@ var vueContainerRender = {
2685
2658
  insertSetupScript(style, env);
2686
2659
  }
2687
2660
  }
2688
- return `<VPDemoBasic type="vue"${title ? ` title="${title}"` : ""}${desc ? ` desc="${desc}"` : ""}${expanded ? " expanded" : ""}>
2689
- <${componentName2} />
2661
+ return `<VPDemoBasic${stringifyAttrs({ type: "vue", title, desc, expanded })}>
2662
+ <${componentName} />
2690
2663
  <template #code>
2691
2664
  `;
2692
2665
  },
@@ -2716,24 +2689,24 @@ function demoEmbed(app, md) {
2716
2689
  createEmbedRuleBlock(md, {
2717
2690
  type: "demo",
2718
2691
  syntaxPattern: /^@\[demo(?:\s(vue|normal|markdown))?\s?(.*)\]\((.*)\)/,
2719
- meta: ([, type2, info, url]) => ({
2720
- type: type2 || "normal",
2692
+ meta: ([, type, info, url]) => ({
2693
+ type: type || "normal",
2721
2694
  url,
2722
2695
  ...resolveAttrs(info).attrs
2723
2696
  }),
2724
2697
  content: (meta, content, env) => {
2725
- const { url, type: type2 } = meta;
2698
+ const { url, type } = meta;
2726
2699
  if (!url) {
2727
2700
  console.warn("[vuepress-plugin-md-power] Invalid demo url: ", url);
2728
2701
  return content;
2729
2702
  }
2730
- if (type2 === "vue") {
2703
+ if (type === "vue") {
2731
2704
  return vueEmbed(app, md, env, meta);
2732
2705
  }
2733
- if (type2 === "normal") {
2706
+ if (type === "normal") {
2734
2707
  return normalEmbed(app, md, env, meta);
2735
2708
  }
2736
- if (type2 === "markdown") {
2709
+ if (type === "markdown") {
2737
2710
  return markdownEmbed(app, md, env, meta);
2738
2711
  }
2739
2712
  return content;
@@ -2767,7 +2740,7 @@ function demoContainer(app, md) {
2767
2740
  return res;
2768
2741
  }
2769
2742
  };
2770
- md.use(container5, "demo", { render });
2743
+ md.use(container2, "demo", { render });
2771
2744
  }
2772
2745
  function parseCodeMapping(tokens, index, cb) {
2773
2746
  const codeMap = {};
@@ -2781,11 +2754,11 @@ function parseCodeMapping(tokens, index, cb) {
2781
2754
  return codeMap;
2782
2755
  }
2783
2756
  function getContainerMeta(info) {
2784
- const [, type2, raw] = (info.trim().slice(4).trim() || "").match(INFO_RE) || [];
2757
+ const [, type, raw] = (info.trim().slice(4).trim() || "").match(INFO_RE) || [];
2785
2758
  const { attrs: attrs2 } = resolveAttrs(raw);
2786
2759
  return {
2787
2760
  url: "",
2788
- type: type2 || "normal",
2761
+ type: type || "normal",
2789
2762
  ...attrs2
2790
2763
  };
2791
2764
  }
@@ -2795,7 +2768,7 @@ function extendsPageWithDemo(page) {
2795
2768
  const markdownEnv = page.markdownEnv;
2796
2769
  const demoFiles = markdownEnv.demoFiles ?? [];
2797
2770
  page.deps.push(
2798
- ...demoFiles.filter(({ type: type2 }) => type2 === "markdown").map(({ path: path9 }) => path9)
2771
+ ...demoFiles.filter(({ type }) => type === "markdown").map(({ path: path9 }) => path9)
2799
2772
  );
2800
2773
  (page.frontmatter.gitInclude ??= []).push(
2801
2774
  ...demoFiles.filter(({ gitignore }) => !gitignore).map(({ path: path9 }) => path9)
@@ -2849,29 +2822,27 @@ var audioReader = (state, silent) => {
2849
2822
  state.posMax = labelEnd;
2850
2823
  const info = state.src.slice(labelStart, labelEnd).trim();
2851
2824
  const { attrs: attrs2 } = resolveAttrs(info);
2852
- const tokenOpen = state.push("audio_reader_open", "AudioReader", 1);
2853
- tokenOpen.info = info;
2854
- tokenOpen.attrs = [["src", href]];
2855
- if (attrs2.startTime)
2856
- tokenOpen.attrs.push([":start-time", attrs2.startTime]);
2857
- if (attrs2.endTime)
2858
- tokenOpen.attrs.push([":end-time", attrs2.endTime]);
2859
- if (attrs2.type)
2860
- tokenOpen.attrs.push(["type", attrs2.type]);
2861
- if (attrs2.volume)
2862
- tokenOpen.attrs.push([":volume", attrs2.volume]);
2863
- if (attrs2.title)
2864
- state.push("text", "", 0).content = attrs2.title;
2865
- state.push("audio_reader_close", "AudioReader", -1);
2825
+ const token = state.push("audio_reader", "AudioReader", 0);
2826
+ token.info = info;
2827
+ token.meta = { src: href, ...attrs2 };
2866
2828
  }
2867
2829
  state.pos = pos + 1;
2868
2830
  state.posMax = max;
2869
2831
  return true;
2870
2832
  };
2871
- var audioReaderPlugin = (md) => md.inline.ruler.before("link", "audio-reader", audioReader);
2872
-
2873
- // src/node/embed/caniuse.ts
2874
- import container6 from "markdown-it-container";
2833
+ var audioReaderPlugin = (md) => {
2834
+ md.renderer.rules.audio_reader = (tokens, idx) => {
2835
+ const meta = tokens[idx].meta ?? {};
2836
+ if (meta.startTime)
2837
+ meta.startTime = Number(meta.startTime);
2838
+ if (meta.endTime)
2839
+ meta.endTime = Number(meta.endTime);
2840
+ if (meta.volume)
2841
+ meta.volume = Number(meta.volume);
2842
+ return `<AudioReader${stringifyAttrs(meta)} />`;
2843
+ };
2844
+ md.inline.ruler.before("link", "audio-reader", audioReader);
2845
+ };
2875
2846
 
2876
2847
  // src/node/utils/nanoid.ts
2877
2848
  import { customAlphabet } from "nanoid";
@@ -2895,23 +2866,14 @@ function legacyCaniuse(md, { mode = "embed" } = {}) {
2895
2866
  const modeMap = ["image", "embed"];
2896
2867
  const isMode = (mode2) => modeMap.includes(mode2);
2897
2868
  mode = isMode(mode) ? mode : modeMap[0];
2898
- const type2 = "caniuse";
2899
- const validateReg = new RegExp(`^${type2}`);
2900
- const validate = (info) => {
2901
- return validateReg.test(info.trim());
2902
- };
2903
- const render = (tokens, index) => {
2904
- const token = tokens[index];
2905
- if (token.nesting === 1) {
2906
- const info = token.info.trim().slice(type2.length).trim() || "";
2869
+ createContainerPlugin(md, "caniuse", {
2870
+ before: (info) => {
2907
2871
  const feature = info.split(/\s+/)[0];
2908
2872
  const versions = info.match(/\{(.*)\}/)?.[1] || "";
2909
2873
  return feature ? resolveCanIUse({ feature, mode, versions }) : "";
2910
- } else {
2911
- return "";
2912
- }
2913
- };
2914
- md.use(container6, type2, { validate, render });
2874
+ },
2875
+ after: () => ""
2876
+ });
2915
2877
  }
2916
2878
  function resolveCanIUse({ feature, mode, versions }) {
2917
2879
  if (!feature)
@@ -2928,7 +2890,7 @@ function resolveCanIUse({ feature, mode, versions }) {
2928
2890
  feature = feature.replace(UNDERLINE_RE, "_");
2929
2891
  const { past, future } = resolveVersions(versions);
2930
2892
  const meta = nanoid();
2931
- return `<CanIUseViewer feature="${feature}" meta="${meta}" past="${past}" future="${future}" />`;
2893
+ return `<CanIUseViewer${stringifyAttrs({ feature, meta, past, future })} />`;
2932
2894
  }
2933
2895
  function resolveVersions(versions) {
2934
2896
  if (!versions)
@@ -2955,19 +2917,21 @@ var codepenPlugin = (md) => {
2955
2917
  type: "codepen",
2956
2918
  syntaxPattern: /^@\[codepen([^\]]*)\]\(([^)]*)\)/,
2957
2919
  meta: ([, info, source]) => {
2958
- const { width, height, title, tab: tab3, ...rest } = resolveAttrs(info).attrs;
2920
+ const { width, height, title, tab: tab3, preview, editable, theme } = resolveAttrs(info).attrs;
2959
2921
  const [user, slash] = source.split("/");
2960
2922
  return {
2923
+ title: title || "Code Pen",
2924
+ tab: tab3 || "result",
2961
2925
  width: width ? parseRect(width) : "100%",
2962
2926
  height: height ? parseRect(height) : "400px",
2963
2927
  user,
2964
2928
  slash,
2965
- title: title || "Code Pen",
2966
- tab: tab3 || "result",
2967
- ...rest
2929
+ preview,
2930
+ editable,
2931
+ theme
2968
2932
  };
2969
2933
  },
2970
- content: ({ title, height, width, user, slash, preview, editable, tab: tab3, theme }) => `<CodePenViewer user="${user}" slash="${slash}" title="${title}"${preview ? " preview" : ""}${editable ? " editable" : ""} tab="${tab3}"${theme ? ` theme="${theme}"` : ""} width="${width}" height="${height}" />`
2934
+ content: (meta) => `<CodePenViewer${stringifyAttrs(meta)} />`
2971
2935
  });
2972
2936
  };
2973
2937
 
@@ -2976,7 +2940,7 @@ var codeSandboxPlugin = (md) => {
2976
2940
  createEmbedRuleBlock(md, {
2977
2941
  type: "codesandbox",
2978
2942
  syntaxPattern: /^@\[codesandbox(?:\s+(embed|button))?([^\]]*)\]\(([^)]*)\)/,
2979
- meta([, type2, info, source]) {
2943
+ meta([, type, info, source]) {
2980
2944
  const { attrs: attrs2 } = resolveAttrs(info);
2981
2945
  const [profile, filepath2 = ""] = source.split("#");
2982
2946
  const [user, id] = profile.includes("/") ? profile.split("/") : ["", profile];
@@ -2989,13 +2953,11 @@ var codeSandboxPlugin = (md) => {
2989
2953
  console: attrs2.console ?? false,
2990
2954
  navbar: attrs2.navbar ?? true,
2991
2955
  layout: attrs2.layout ?? "",
2992
- type: type2 || "embed",
2956
+ type: type || "embed",
2993
2957
  filepath: filepath2
2994
2958
  };
2995
2959
  },
2996
- content({ title, height, width, user, id, type: type2, filepath: filepath2, console: console2, navbar, layout }) {
2997
- return `<CodeSandboxViewer title="${title}" height="${height}" width="${width}" user="${user}" id="${id}" type="${type2}" filepath="${filepath2}" :console=${console2} :navbar=${navbar} layout="${layout}" />`;
2998
- }
2960
+ content: (meta) => `<CodeSandboxViewer${stringifyAttrs(meta)} />`
2999
2961
  });
3000
2962
  };
3001
2963
 
@@ -3015,7 +2977,7 @@ var jsfiddlePlugin = (md) => {
3015
2977
  theme
3016
2978
  };
3017
2979
  },
3018
- content: ({ title, height, width, source, tab: tab3, theme }) => `<JSFiddleViewer source="${source}" title="${title}" tab="${tab3}" width="${width}" height="${height}"${theme ? ` theme="${theme}"` : ""} />`
2980
+ content: (meta) => `<JSFiddleViewer${stringifyAttrs(meta)} />`
3019
2981
  });
3020
2982
  };
3021
2983
 
@@ -3034,9 +2996,7 @@ var replitPlugin = (md) => {
3034
2996
  theme: attrs2.theme || ""
3035
2997
  };
3036
2998
  },
3037
- content({ title, height, width, source, theme }) {
3038
- return `<ReplitViewer title="${title || ""}" height="${height}" width="${width}" source="${source}" theme="${theme}" />`;
3039
- }
2999
+ content: (meta) => `<ReplitViewer${stringifyAttrs(meta)} />`
3040
3000
  });
3041
3001
  };
3042
3002
 
@@ -3060,15 +3020,13 @@ var pdfPlugin = (md) => {
3060
3020
  title: path7.basename(src || "")
3061
3021
  };
3062
3022
  },
3063
- content({ title, src, page, noToolbar, width, height, ratio, zoom }) {
3064
- return `<PDFViewer src="${src}" title="${title}" :page="${page}" :no-toolbar="${noToolbar}" width="${width}" height="${height}" ratio="${ratio}" :zoom="${zoom}" />`;
3065
- }
3023
+ content: (meta) => `<PDFViewer${stringifyAttrs(meta)} />`
3066
3024
  });
3067
3025
  };
3068
3026
 
3069
3027
  // src/node/embed/video/artPlayer.ts
3070
3028
  import { isPackageExists as isPackageExists2 } from "local-pkg";
3071
- import { colors as colors2 } from "vuepress/utils";
3029
+ import { colors as colors3 } from "vuepress/utils";
3072
3030
  var installed = {
3073
3031
  dashjs: isPackageExists2("dashjs"),
3074
3032
  hlsjs: isPackageExists2("hls.js"),
@@ -3085,6 +3043,8 @@ var artPlayerPlugin = (md) => {
3085
3043
  const url = source.trim();
3086
3044
  checkSupportType(attrs2.type ?? url.split(".").pop());
3087
3045
  return {
3046
+ url,
3047
+ type: attrs2.type,
3088
3048
  autoplay: attrs2.autoplay ?? false,
3089
3049
  muted: attrs2.muted ?? attrs2.autoplay ?? false,
3090
3050
  autoMini: attrs2.autoMini ?? false,
@@ -3092,23 +3052,22 @@ var artPlayerPlugin = (md) => {
3092
3052
  volume: typeof attrs2.volume !== "undefined" ? Number(attrs2.volume) : 0.75,
3093
3053
  poster: attrs2.poster,
3094
3054
  width: attrs2.width ? parseRect(attrs2.width) : "100%",
3095
- height: attrs2.height ? parseRect(attrs2.height) : "",
3096
- ratio: attrs2.ratio ? parseRect(`${attrs2.ratio}`) : "",
3097
- type: attrs2.type,
3098
- url
3055
+ height: attrs2.height ? parseRect(attrs2.height) : void 0,
3056
+ ratio: attrs2.ratio ? parseRect(`${attrs2.ratio}`) : void 0
3099
3057
  };
3100
3058
  },
3101
- content({ autoMini, autoplay, loop, muted, poster, url, type: type2, volume, width, height, ratio }) {
3102
- return `<ArtPlayer src="${url}" fullscreen flip playback-rate aspect-ratio setting pip ${loop ? " loop" : ""}${type2 ? ` type="${type2}"` : ""}${autoMini ? " auto-min" : ""}${autoplay ? " autoplay" : ""}${muted || autoplay ? " muted" : ""}${poster ? ` poster="${poster}"` : ""} :volume="${volume}" width="${width}"${height ? ` height="${height}"` : ""}${ratio ? ` ratio="${ratio}"` : ""}/>`;
3059
+ content({ url, ...meta }) {
3060
+ meta.muted = meta.muted || meta.autoplay;
3061
+ return `<ArtPlayer src="${url}" fullscreen flip playback-rate aspect-ratio setting pip${stringifyAttrs(meta)}/>`;
3103
3062
  }
3104
3063
  });
3105
3064
  };
3106
- function checkSupportType(type2) {
3107
- if (!type2)
3065
+ function checkSupportType(type) {
3066
+ if (!type)
3108
3067
  return;
3109
- if (SUPPORTED_VIDEO_TYPES.includes(type2)) {
3068
+ if (SUPPORTED_VIDEO_TYPES.includes(type)) {
3110
3069
  let name = "";
3111
- switch (type2.toLowerCase()) {
3070
+ switch (type.toLowerCase()) {
3112
3071
  case "m3u8":
3113
3072
  case "hls":
3114
3073
  name = !installed.hlsjs ? "hls.js" : "";
@@ -3124,10 +3083,10 @@ function checkSupportType(type2) {
3124
3083
  break;
3125
3084
  }
3126
3085
  if (name) {
3127
- console.warn(`${colors2.yellow("[vuepress-plugin-md-power] artPlayer: ")} ${colors2.cyan(name)} is not installed, please install it via npm or yarn or pnpm`);
3086
+ console.warn(`${colors3.yellow("[vuepress-plugin-md-power] artPlayer: ")} ${colors3.cyan(name)} is not installed, please install it via npm or yarn or pnpm`);
3128
3087
  }
3129
3088
  } else {
3130
- console.warn(`${colors2.yellow("[vuepress-plugin-md-power] artPlayer: ")} unsupported video type: ${colors2.cyan(type2)}`);
3089
+ console.warn(`${colors3.yellow("[vuepress-plugin-md-power] artPlayer: ")} unsupported video type: ${colors3.cyan(type)}`);
3131
3090
  }
3132
3091
  }
3133
3092
 
@@ -3166,31 +3125,27 @@ var bilibiliPlugin = (md) => {
3166
3125
  time: timeToSeconds(attrs2.time),
3167
3126
  title: attrs2.title,
3168
3127
  width: attrs2.width ? parseRect(attrs2.width) : "100%",
3169
- height: attrs2.height ? parseRect(attrs2.height) : "",
3170
- ratio: attrs2.ratio ? parseRect(attrs2.ratio) : ""
3128
+ height: attrs2.height ? parseRect(attrs2.height) : void 0,
3129
+ ratio: attrs2.ratio ? parseRect(attrs2.ratio) : void 0
3171
3130
  };
3172
3131
  },
3173
3132
  content(meta) {
3174
3133
  const params = new URLSearchParams();
3175
- if (meta.bvid) {
3134
+ if (meta.bvid)
3176
3135
  params.set("bvid", meta.bvid);
3177
- }
3178
- if (meta.aid) {
3136
+ if (meta.aid)
3179
3137
  params.set("aid", meta.aid);
3180
- }
3181
- if (meta.cid) {
3138
+ if (meta.cid)
3182
3139
  params.set("cid", meta.cid);
3183
- }
3184
- if (meta.page) {
3140
+ if (meta.page)
3185
3141
  params.set("p", meta.page.toString());
3186
- }
3187
- if (meta.time) {
3142
+ if (meta.time)
3188
3143
  params.set("t", meta.time.toString());
3189
- }
3190
3144
  params.set("autoplay", meta.autoplay ? "1" : "0");
3191
3145
  params.set("high_quality", "1");
3192
3146
  const source = `${BILIBILI_LINK}?${params.toString()}`;
3193
- return `<VideoBilibili src="${source}" width="${meta.width}" height="${meta.height}" ratio="${meta.ratio}" title="${meta.title}" />`;
3147
+ const { width, height, ratio, title } = meta;
3148
+ return `<VideoBilibili${stringifyAttrs({ src: source, width, height, ratio, title })} />`;
3194
3149
  }
3195
3150
  });
3196
3151
  };
@@ -3213,26 +3168,23 @@ var youtubePlugin = (md) => {
3213
3168
  end: timeToSeconds(attrs2.end),
3214
3169
  title: attrs2.title,
3215
3170
  width: attrs2.width ? parseRect(attrs2.width) : "100%",
3216
- height: attrs2.height ? parseRect(attrs2.height) : "",
3217
- ratio: attrs2.ratio ? parseRect(attrs2.ratio) : ""
3171
+ height: attrs2.height ? parseRect(attrs2.height) : void 0,
3172
+ ratio: attrs2.ratio ? parseRect(attrs2.ratio) : void 0
3218
3173
  };
3219
3174
  },
3220
3175
  content(meta) {
3221
3176
  const params = new URLSearchParams2();
3222
- if (meta.autoplay) {
3177
+ if (meta.autoplay)
3223
3178
  params.set("autoplay", "1");
3224
- }
3225
- if (meta.loop) {
3179
+ if (meta.loop)
3226
3180
  params.set("loop", "1");
3227
- }
3228
- if (meta.start) {
3181
+ if (meta.start)
3229
3182
  params.set("start", meta.start.toString());
3230
- }
3231
- if (meta.end) {
3183
+ if (meta.end)
3232
3184
  params.set("end", meta.end.toString());
3233
- }
3234
3185
  const source = `${YOUTUBE_LINK}/${meta.id}?${params.toString()}`;
3235
- return `<VideoYoutube src="${source}" width="${meta.width}" height="${meta.height}" ratio="${meta.ratio}" title="${meta.title}" />`;
3186
+ const { width, height, ratio, title } = meta;
3187
+ return `<VideoYoutube${stringifyAttrs({ src: source, width, height, ratio, title })} />`;
3236
3188
  }
3237
3189
  });
3238
3190
  };
@@ -3520,16 +3472,17 @@ var annotationPlugin = (md) => {
3520
3472
  };
3521
3473
 
3522
3474
  // src/node/inline/icons.ts
3523
- var iconsPlugin = (md, options = {}) => md.inline.ruler.before("emphasis", "iconify", createTokenizer(options));
3524
- function createTokenizer(options) {
3475
+ import { colors as colors4 } from "vuepress/utils";
3476
+ function createIconRule([l1, l2, r1, r2], deprecated) {
3525
3477
  return (state, silent) => {
3526
3478
  let found = false;
3527
3479
  const max = state.posMax;
3528
3480
  const start = state.pos;
3529
- if (state.src.charCodeAt(start) !== 58 || state.src.charCodeAt(start + 1) !== 91) {
3481
+ if (state.src.charCodeAt(start) !== l1 || state.src.charCodeAt(start + 1) !== l2) {
3530
3482
  return false;
3531
3483
  }
3532
- if (state.src.charCodeAt(start + 2) === 32)
3484
+ const next = state.src.charCodeAt(start + 2);
3485
+ if (next === 32 || next === 58)
3533
3486
  return false;
3534
3487
  if (silent)
3535
3488
  return false;
@@ -3537,7 +3490,7 @@ function createTokenizer(options) {
3537
3490
  return false;
3538
3491
  state.pos = start + 2;
3539
3492
  while (state.pos < max) {
3540
- if (state.src.charCodeAt(state.pos) === 93 && state.src.charCodeAt(state.pos + 1) === 58) {
3493
+ if (state.src.charCodeAt(state.pos) === r1 && state.src.charCodeAt(state.pos + 1) === r2) {
3541
3494
  found = true;
3542
3495
  break;
3543
3496
  }
@@ -3547,69 +3500,103 @@ function createTokenizer(options) {
3547
3500
  state.pos = start;
3548
3501
  return false;
3549
3502
  }
3550
- const content = state.src.slice(start + 2, state.pos);
3503
+ const info = state.src.slice(start + 2, state.pos);
3551
3504
  state.posMax = state.pos;
3552
3505
  state.pos = start + 2;
3553
- const [name, opt = ""] = content.split(" ");
3554
- const [size, color = options.color] = opt.trim().split("/");
3555
- const icon = state.push("vp_icon_open", "VPIcon", 1);
3556
- icon.markup = ":[";
3557
- icon.attrs = [["name", name]];
3558
- if (size || options.size)
3559
- icon.attrs.push(["size", String(size || options.size)]);
3560
- if (color)
3561
- icon.attrs.push(["color", color]);
3562
- const close = state.push("vp_icon_close", "VPIcon", -1);
3563
- close.markup = "]:";
3506
+ const icon = state.push("icon", "i", 0);
3507
+ icon.markup = "::";
3508
+ icon.content = info;
3509
+ icon.meta = { deprecated };
3564
3510
  state.pos = state.posMax + 2;
3565
3511
  state.posMax = max;
3566
3512
  return true;
3567
3513
  };
3568
3514
  }
3515
+ var RE_SIZE = /(?<=\s|^)=(.+?)(?:\s|$)/;
3516
+ var RE_COLOR = /(?<=\s|^)\/(.+?)(?:\s|$)/;
3517
+ function iconRender(content, options) {
3518
+ let size = options.size;
3519
+ let color = options.color;
3520
+ content = content.replace(RE_SIZE, (_, s) => {
3521
+ size = s;
3522
+ return "";
3523
+ }).replace(RE_COLOR, (_, c) => {
3524
+ color = c;
3525
+ return "";
3526
+ }).trim();
3527
+ const [name, ...extra] = content.split(/\s+/);
3528
+ return `<VPIcon${stringifyAttrs({ name, size, color, class: extra.length ? extra.join(" ") : void 0 })} />`;
3529
+ }
3530
+ var iconPlugin = (md, options = {}) => {
3531
+ md.inline.ruler.before(
3532
+ "link",
3533
+ "icon",
3534
+ // : : : :
3535
+ createIconRule([58, 58, 58, 58])
3536
+ );
3537
+ md.inline.ruler.before(
3538
+ "link",
3539
+ "icon_deprecated",
3540
+ // : [ ] :
3541
+ createIconRule([58, 91, 93, 58], true)
3542
+ );
3543
+ md.renderer.rules.icon = (tokens, idx, _, env) => {
3544
+ const { content, meta } = tokens[idx];
3545
+ let icon = content;
3546
+ if (meta.deprecated) {
3547
+ const [name, opt = ""] = content.split(" ");
3548
+ const [size, color] = opt.trim().split("/");
3549
+ icon = `${name}${size ? ` =${size}` : ""}${color ? ` /${color}` : ""}`;
3550
+ console.warn(`The icon syntax of \`${colors4.yellow(`:[${content}]:`)}\` is deprecated, please use \`${colors4.green(`::${icon}::`)}\` instead. (${colors4.gray(env.filePathRelative || env.filePath)})`);
3551
+ }
3552
+ return iconRender(icon, options);
3553
+ };
3554
+ };
3569
3555
 
3570
3556
  // src/node/inline/plot.ts
3571
- var plotPlugin = (md) => md.inline.ruler.before("emphasis", "plot", createTokenizer2());
3572
- function createTokenizer2() {
3573
- return (state, silent) => {
3574
- let found = false;
3575
- const max = state.posMax;
3576
- const start = state.pos;
3577
- if (state.src.charCodeAt(start) !== 33 || state.src.charCodeAt(start + 1) !== 33) {
3578
- return false;
3579
- }
3580
- const next = state.src.charCodeAt(start + 2);
3581
- if (next === 32 || next === 33)
3582
- return false;
3583
- if (silent)
3584
- return false;
3585
- if (max - start < 5)
3586
- return false;
3587
- state.pos = start + 2;
3588
- while (state.pos < max) {
3589
- if (state.src.charCodeAt(state.pos) === 33 && state.src.charCodeAt(state.pos + 1) === 33) {
3590
- found = true;
3591
- break;
3592
- }
3593
- state.md.inline.skipToken(state);
3594
- }
3595
- if (!found || start + 2 === state.pos || state.src.charCodeAt(state.pos - 1) === 32) {
3596
- state.pos = start;
3597
- return false;
3557
+ var plotDef = (state, silent) => {
3558
+ let found = false;
3559
+ const max = state.posMax;
3560
+ const start = state.pos;
3561
+ if (state.src.charCodeAt(start) !== 33 || state.src.charCodeAt(start + 1) !== 33) {
3562
+ return false;
3563
+ }
3564
+ const next = state.src.charCodeAt(start + 2);
3565
+ if (next === 32 || next === 33)
3566
+ return false;
3567
+ if (silent)
3568
+ return false;
3569
+ if (max - start < 5)
3570
+ return false;
3571
+ state.pos = start + 2;
3572
+ while (state.pos < max) {
3573
+ if (state.src.charCodeAt(state.pos) === 33 && state.src.charCodeAt(state.pos + 1) === 33) {
3574
+ found = true;
3575
+ break;
3598
3576
  }
3599
- const content = state.src.slice(start + 2, state.pos);
3600
- state.posMax = state.pos;
3601
- state.pos = start + 2;
3602
- const open = state.push("plot_open", "Plot", 1);
3603
- open.markup = "!!";
3604
- const text = state.push("text", "", 0);
3605
- text.content = content;
3606
- const close = state.push("plot_close", "Plot", -1);
3607
- close.markup = "!!";
3608
- state.pos = state.posMax + 2;
3609
- state.posMax = max;
3610
- return true;
3577
+ state.md.inline.skipToken(state);
3578
+ }
3579
+ if (!found || start + 2 === state.pos || state.src.charCodeAt(state.pos - 1) === 32) {
3580
+ state.pos = start;
3581
+ return false;
3582
+ }
3583
+ const content = state.src.slice(start + 2, state.pos);
3584
+ state.posMax = state.pos;
3585
+ state.pos = start + 2;
3586
+ const token = state.push("plot_inline", "Plot", 0);
3587
+ token.markup = "!!";
3588
+ token.content = content;
3589
+ state.pos = state.posMax + 2;
3590
+ state.posMax = max;
3591
+ return true;
3592
+ };
3593
+ var plotPlugin = (md) => {
3594
+ md.renderer.rules.plot_inline = (tokens, idx) => {
3595
+ const token = tokens[idx];
3596
+ return `<Plot>${token.content}</Plot>`;
3611
3597
  };
3612
- }
3598
+ md.inline.ruler.before("emphasis", "plot", plotDef);
3599
+ };
3613
3600
 
3614
3601
  // src/node/inline/index.ts
3615
3602
  function inlineSyntaxPlugin(md, options) {
@@ -3626,7 +3613,7 @@ function inlineSyntaxPlugin(md, options) {
3626
3613
  md.use(abbrPlugin);
3627
3614
  }
3628
3615
  if (options.icons) {
3629
- md.use(iconsPlugin, isPlainObject3(options.icons) ? options.icons : {});
3616
+ md.use(iconPlugin, isPlainObject3(options.icons) ? options.icons : {});
3630
3617
  }
3631
3618
  if (options.plot === true || isPlainObject3(options.plot) && options.plot.tag !== false) {
3632
3619
  md.use(plotPlugin);
@@ -3689,8 +3676,8 @@ async function prepareConfigFile(app, options) {
3689
3676
  enhances.add(`app.component('CanIUseViewer', CanIUse)`);
3690
3677
  }
3691
3678
  if (options.fileTree) {
3692
- imports.add(`import FileTreeItem from '${CLIENT_FOLDER}components/FileTreeItem.vue'`);
3693
- enhances.add(`app.component('FileTreeItem', FileTreeItem)`);
3679
+ imports.add(`import FileTreeNode from '${CLIENT_FOLDER}components/FileTreeNode.vue'`);
3680
+ enhances.add(`app.component('FileTreeNode', FileTreeNode)`);
3694
3681
  }
3695
3682
  if (options.artPlayer) {
3696
3683
  imports.add(`import ArtPlayer from '${CLIENT_FOLDER}components/ArtPlayer.vue'`);