vuepress-plugin-md-power 1.0.0-rc.143 → 1.0.0-rc.145

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>";
1162
+ }
1163
+ };
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
+ `;
1169
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>`;
1170
1208
  };
1171
- md.use(container, type2, { render });
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>";
@@ -1419,181 +1448,144 @@ function demoWrapperPlugin(md) {
1419
1448
  });
1420
1449
  }
1421
1450
 
1451
+ // src/node/container/field.ts
1452
+ import { isUndefined as isUndefined2 } from "@pengzhanbo/utils";
1453
+ function fieldPlugin(md) {
1454
+ createContainerPlugin(md, "field", {
1455
+ before: (info) => {
1456
+ const { attrs: attrs2 } = resolveAttrs(info);
1457
+ const { name, type, required, optional, default: defaultValue } = attrs2;
1458
+ const props = stringifyAttrs({ name, required, optional });
1459
+ return `<VPField${props}${!isUndefined2(type) ? ` type="${type}"` : ""}${!isUndefined2(defaultValue) ? ` default-value="${defaultValue}"` : ""}>`;
1460
+ },
1461
+ after: () => "</VPField>"
1462
+ });
1463
+ createContainerPlugin(md, "field-group", {
1464
+ before: () => '<div class="vp-field-group">'
1465
+ });
1466
+ }
1467
+
1422
1468
  // 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";
1469
+ import { removeEndingSlash } from "vuepress/shared";
1470
+ function parseFileTreeRawContent(content) {
1471
+ const root = { info: "", level: -1, children: [] };
1472
+ const stack = [root];
1473
+ const lines = content.trim().split("\n");
1474
+ for (const line of lines) {
1475
+ const match = line.match(/^(\s*)-(.*)$/);
1476
+ if (!match)
1477
+ continue;
1478
+ const level = Math.floor(match[1].length / 2);
1479
+ const info = match[2].trim();
1480
+ while (stack.length > 0 && stack[stack.length - 1].level >= level) {
1481
+ stack.pop();
1482
+ }
1483
+ const parent = stack[stack.length - 1];
1484
+ const node = { info, level, children: [] };
1485
+ parent.children.push(node);
1486
+ stack.push(node);
1487
+ }
1488
+ return root.children;
1489
+ }
1490
+ var RE_FOCUS = /^\*\*(.*)\*\*(?:$|\s+)/;
1491
+ function parseFileTreeNodeInfo(info) {
1492
+ let filename = "";
1493
+ let comment = "";
1494
+ let focus = false;
1495
+ let expanded = true;
1496
+ let type = "file";
1497
+ let diff;
1498
+ if (info.startsWith("++")) {
1499
+ info = info.slice(2).trim();
1500
+ diff = "add";
1501
+ } else if (info.startsWith("--")) {
1502
+ info = info.slice(2).trim();
1503
+ diff = "remove";
1504
+ }
1505
+ info = info.replace(RE_FOCUS, (_, matched) => {
1506
+ filename = matched;
1507
+ focus = true;
1508
+ return "";
1509
+ });
1510
+ if (filename === "" && !focus) {
1511
+ const spaceIndex = info.indexOf(" ");
1512
+ filename = info.slice(0, spaceIndex === -1 ? info.length : spaceIndex);
1513
+ info = spaceIndex === -1 ? "" : info.slice(spaceIndex);
1514
+ }
1515
+ comment = info.trim();
1516
+ if (filename.endsWith("/")) {
1517
+ type = "folder";
1518
+ expanded = false;
1519
+ filename = removeEndingSlash(filename);
1520
+ }
1521
+ return { filename, comment, focus, expanded, type, diff };
1522
+ }
1431
1523
  function fileTreePlugin(md, options = {}) {
1432
- const getIcon = (filename, type2, mode) => {
1524
+ const getIcon = (filename, type, mode) => {
1433
1525
  mode ||= options.icon || "colored";
1434
1526
  if (mode === "simple")
1435
- return type2 === "folder" ? defaultFolder : defaultFile;
1436
- return getFileIcon(filename, type2);
1527
+ return type === "folder" ? defaultFolder : defaultFile;
1528
+ return getFileIcon(filename, type);
1437
1529
  };
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);
1530
+ const renderFileTree = (nodes, meta) => nodes.map((node) => {
1531
+ const { info, level, children } = node;
1532
+ const { filename, comment, focus, expanded, type, diff } = parseFileTreeNodeInfo(info);
1533
+ const isOmit = filename === "\u2026" || filename === "...";
1534
+ if (children.length === 0 && type === "folder") {
1535
+ children.push({ info: "\u2026", level: level + 1, children: [] });
1536
+ }
1537
+ const nodeType = children.length > 0 ? "folder" : type;
1538
+ const renderedComment = comment ? `<template #comment>${md.renderInline(comment.replaceAll("#", "#"))}</template>` : "";
1539
+ const renderedIcon = !isOmit ? `<template #icon><VPIcon name="${getIcon(filename, nodeType, meta.icon)}" /></template>` : "";
1540
+ const props = {
1541
+ expanded: nodeType === "folder" ? expanded : false,
1542
+ focus,
1543
+ type: nodeType,
1544
+ diff,
1545
+ filename,
1546
+ level
1547
+ };
1548
+ return `<FileTreeNode${stringifyAttrs(props)}>
1549
+ ${renderedIcon}${renderedComment}${children.length > 0 ? renderFileTree(children, meta) : ""}
1550
+ </FileTreeNode>`;
1551
+ }).join("\n");
1552
+ return createContainerSyntaxPlugin(
1553
+ md,
1554
+ "file-tree",
1555
+ (tokens, index) => {
1556
+ const token = tokens[index];
1557
+ const nodes = parseFileTreeRawContent(token.content);
1558
+ const meta = token.meta;
1559
+ return `<div class="vp-file-tree">${meta.title ? `<p class="vp-file-tree-title">${meta.title}</p>` : ""}${renderFileTree(nodes, meta)}</div>
1560
+ `;
1548
1561
  }
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;
1562
+ );
1560
1563
  }
1561
1564
 
1562
1565
  // src/node/container/langRepl.ts
1563
1566
  import { promises as fs2 } from "node:fs";
1564
1567
  import { resolveModule } from "local-pkg";
1565
- import container3 from "markdown-it-container";
1566
1568
  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
1569
  async function langReplPlugin(app, md, {
1583
1570
  theme,
1584
1571
  go = false,
1585
1572
  kotlin = false,
1586
1573
  rust = false
1587
1574
  }) {
1588
- if (kotlin) {
1589
- createReplContainer(md, "kotlin");
1590
- }
1591
- if (go) {
1592
- createReplContainer(md, "go");
1593
- }
1594
- if (rust) {
1595
- createReplContainer(md, "rust");
1596
- }
1575
+ const container3 = (lang) => createContainerPlugin(md, `${lang}-repl`, {
1576
+ before(info) {
1577
+ const { attrs: attrs2 } = resolveAttrs(info);
1578
+ const { editable, title } = attrs2;
1579
+ return `<CodeRepl${stringifyAttrs({ editable, title: title || `${lang} playground` })}>`;
1580
+ },
1581
+ after: () => "</CodeRepl>"
1582
+ });
1583
+ if (kotlin)
1584
+ container3("kotlin");
1585
+ if (go)
1586
+ container3("go");
1587
+ if (rust)
1588
+ container3("rust");
1597
1589
  theme ??= { light: "github-light", dark: "github-dark" };
1598
1590
  const data = { grammars: {} };
1599
1591
  try {
@@ -1634,7 +1626,9 @@ async function read(file) {
1634
1626
 
1635
1627
  // src/node/container/npmTo.ts
1636
1628
  import { isArray } from "@vuepress/helper";
1637
- import container4 from "markdown-it-container";
1629
+ import { colors as colors2 } from "vuepress/utils";
1630
+
1631
+ // src/node/container/npmToPreset.ts
1638
1632
  var ALLOW_LIST = ["npm", "pnpm", "yarn", "bun", "deno"];
1639
1633
  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
1634
  var DEFAULT_TABS = ["npm", "pnpm", "yarn"];
@@ -1818,28 +1812,32 @@ var MANAGERS_CONFIG = {
1818
1812
  deno: { cli: "deno install --frozen" }
1819
1813
  }
1820
1814
  };
1815
+
1816
+ // src/node/container/npmTo.ts
1821
1817
  function npmToPlugins(md, options = {}) {
1822
- const type2 = "npm-to";
1823
1818
  const opt = isArray(options) ? { tabs: options } : options;
1824
1819
  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) {
1820
+ createContainerPlugin(md, "npm-to", {
1821
+ before: (info, tokens, idx, _opt, env) => {
1822
+ const { attrs: attrs2 } = resolveAttrs(info);
1823
+ const tabs2 = attrs2.tabs ? attrs2.tabs.split(/,\s*/) : defaultTabs;
1829
1824
  const token = tokens[idx + 1];
1830
- const info = token.info.trim();
1831
1825
  if (token.type === "fence") {
1832
1826
  const content = token.content;
1833
1827
  token.hidden = true;
1834
1828
  token.type = "text";
1835
1829
  token.content = "";
1836
1830
  const lines = content.split(/(\n|\s*&&\s*)/);
1837
- return md.render(resolveNpmTo(lines, info, idx, tabs2), {});
1831
+ return md.render(
1832
+ resolveNpmTo(lines, token.info.trim(), idx, tabs2),
1833
+ cleanMarkdownEnv(env)
1834
+ );
1838
1835
  }
1839
- }
1840
- return "";
1841
- };
1842
- md.use(container4, type2, { render });
1836
+ console.warn(`${colors2.yellow("[vuepress-plugin-md-power]")} Invalid npm-to container in ${colors2.gray(env.filePathRelative || env.filePath)}`);
1837
+ return "";
1838
+ },
1839
+ after: () => ""
1840
+ });
1843
1841
  }
1844
1842
  function resolveNpmTo(lines, info, idx, tabs2) {
1845
1843
  tabs2 = validateTabs(tabs2);
@@ -2017,15 +2015,17 @@ function timelinePlugin(md) {
2017
2015
  before(info, tokens, index) {
2018
2016
  parseTimeline(tokens, index);
2019
2017
  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}"` : ""}>`;
2018
+ attrs2.card ??= void 0;
2019
+ return `<VPTimeline${stringifyAttrs(attrs2, true)}>`;
2022
2020
  },
2023
2021
  after: () => "</VPTimeline>"
2024
2022
  });
2025
2023
  md.renderer.rules.timeline_item_open = (tokens, idx) => {
2026
2024
  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>` : ""}`;
2025
+ const attrs2 = token.meta;
2026
+ attrs2.card ??= void 0;
2027
+ const icon = attrs2.icon;
2028
+ return `<VPTimelineItem${stringifyAttrs(attrs2, true)}>${icon ? `<template #icon><VPIcon name="${icon}"/></template>` : ""}`;
2029
2029
  };
2030
2030
  md.renderer.rules.timeline_item_close = () => "</VPTimelineItem>";
2031
2031
  md.renderer.rules.timeline_item_title_open = () => "<template #title>";
@@ -2122,23 +2122,25 @@ async function containerPlugin(app, md, options) {
2122
2122
  collapsePlugin(md);
2123
2123
  if (options.chat)
2124
2124
  chatPlugin(md);
2125
+ if (options.field)
2126
+ fieldPlugin(md);
2125
2127
  }
2126
2128
 
2127
2129
  // src/node/demo/demo.ts
2128
- import container5 from "markdown-it-container";
2130
+ import container2 from "markdown-it-container";
2129
2131
 
2130
2132
  // src/node/embed/createEmbedRuleBlock.ts
2131
2133
  function createEmbedRuleBlock(md, {
2132
- type: type2,
2133
- name = type2,
2134
+ type,
2135
+ name = type,
2134
2136
  syntaxPattern,
2135
2137
  beforeName = "import_code",
2136
2138
  ruleOptions = { alt: ["paragraph", "reference", "blockquote", "list"] },
2137
2139
  meta,
2138
2140
  content
2139
2141
  }) {
2140
- const MIN_LENGTH = type2.length + 5;
2141
- const START_CODES = [64, 91, ...type2.split("").map((c) => c.charCodeAt(0))];
2142
+ const MIN_LENGTH = type.length + 5;
2143
+ const START_CODES = [64, 91, ...type.split("").map((c) => c.charCodeAt(0))];
2142
2144
  md.block.ruler.before(
2143
2145
  beforeName,
2144
2146
  name,
@@ -2219,7 +2221,7 @@ function markdownEmbed(app, md, env, { url, title, desc, codeSetting = "", expan
2219
2221
  if (!env.demoFiles.some((d) => d.path === filepath2)) {
2220
2222
  env.demoFiles.push(demo);
2221
2223
  }
2222
- return `<VPDemoBasic type="markdown"${title ? ` title="${title}"` : ""}${desc ? ` desc="${desc}"` : ""}${expanded ? " expanded" : ""}>
2224
+ return `<VPDemoBasic${stringifyAttrs({ type: "markdown", title, desc, expanded })}>
2223
2225
  ${md.render(code, { filepath: env.filePath, filepathRelative: env.filePathRelative })}
2224
2226
  <template #code>
2225
2227
  ${md.render(`\`\`\`md ${codeSetting}
@@ -2232,7 +2234,7 @@ var markdownContainerRender = {
2232
2234
  before(app, md, env, meta, codeMap) {
2233
2235
  const { title, desc, expanded = false } = meta;
2234
2236
  const code = codeMap.md || "";
2235
- return `<VPDemoBasic type="markdown"${title ? ` title="${title}"` : ""}${desc ? ` desc="${desc}"` : ""}${expanded ? " expanded" : ""}>
2237
+ return `<VPDemoBasic${stringifyAttrs({ type: "markdown", title, desc, expanded })}>
2236
2238
  ${md.render(code, { filepath: env.filePath, filepathRelative: env.filePathRelative })}
2237
2239
  <template #code>`;
2238
2240
  },
@@ -2269,8 +2271,8 @@ var compiler = {
2269
2271
  }),
2270
2272
  stylus: importer(() => import("stylus"))
2271
2273
  };
2272
- async function compileScript(source, type2) {
2273
- const key = `${type2}:::${source}`;
2274
+ async function compileScript(source, type) {
2275
+ const key = `${type}:::${source}`;
2274
2276
  if (cache2.has(key))
2275
2277
  return cache2.get(key);
2276
2278
  const transform = await compiler.script();
@@ -2278,31 +2280,31 @@ async function compileScript(source, type2) {
2278
2280
  target: "es2018",
2279
2281
  platform: "browser",
2280
2282
  format: "cjs",
2281
- loader: type2 === "ts" ? "ts" : "js",
2283
+ loader: type === "ts" ? "ts" : "js",
2282
2284
  sourcemap: false
2283
2285
  });
2284
2286
  cache2.set(key, res.code);
2285
2287
  return res.code;
2286
2288
  }
2287
- async function compileStyle(source, type2) {
2288
- const key = `${type2}:::${source}`;
2289
+ async function compileStyle(source, type) {
2290
+ const key = `${type}:::${source}`;
2289
2291
  if (cache2.has(key))
2290
2292
  return cache2.get(key);
2291
- if (type2 === "css")
2293
+ if (type === "css")
2292
2294
  return source;
2293
- if (type2 === "less") {
2295
+ if (type === "less") {
2294
2296
  const less = await compiler.less();
2295
2297
  const res = await less.render(source);
2296
2298
  cache2.set(key, res.css);
2297
2299
  return res.css;
2298
2300
  }
2299
- if (type2 === "scss") {
2301
+ if (type === "scss") {
2300
2302
  const sass = await compiler.sass();
2301
2303
  const res = sass.compileString(source);
2302
2304
  cache2.set(key, res.css);
2303
2305
  return res.css;
2304
2306
  }
2305
- if (type2 === "stylus") {
2307
+ if (type === "stylus") {
2306
2308
  const stylus = await compiler.stylus();
2307
2309
  const res = stylus.render(source);
2308
2310
  cache2.set(key, res);
@@ -2520,7 +2522,7 @@ function normalEmbed(app, md, env, { url, title, desc, codeSetting = "", expande
2520
2522
  env.demoFiles.push(demo);
2521
2523
  insertSetupScript({ ...demo, path: output }, env);
2522
2524
  }
2523
- return `<VPDemoNormal :config="${name}"${title ? ` title="${title}"` : ""}${desc ? ` desc="${desc}"` : ""}${expanded ? " expanded" : ""}>
2525
+ return `<VPDemoNormal${stringifyAttrs({ ":config": name, title, desc, expanded })}>
2524
2526
  ${codeToHtml(md, source, codeSetting)}
2525
2527
  </VPDemoNormal>`;
2526
2528
  }
@@ -2538,7 +2540,7 @@ var normalContainerRender = {
2538
2540
  }
2539
2541
  const source = parseContainerCode(codeMap);
2540
2542
  compileCode(source, output);
2541
- return `<VPDemoNormal :config="${name}"${title ? ` title="${title}"` : ""}${desc ? ` desc="${desc}"` : ""}${expanded ? " expanded" : ""}>`;
2543
+ return `<VPDemoNormal${stringifyAttrs({ ":config": name, title, desc, expanded })}>`;
2542
2544
  },
2543
2545
  after: () => "</VPDemoNormal>",
2544
2546
  token(token) {
@@ -2624,7 +2626,7 @@ function vueEmbed(app, md, env, { url, title, desc, codeSetting = "", expanded =
2624
2626
  env.demoFiles.push(demo);
2625
2627
  insertSetupScript(demo, env);
2626
2628
  }
2627
- return `<VPDemoBasic type="vue"${title ? ` title="${title}"` : ""}${desc ? ` desc="${desc}"` : ""}${expanded ? " expanded" : ""}>
2629
+ return `<VPDemoBasic${stringifyAttrs({ type: "vue", title, desc, expanded })}>
2628
2630
  <${name} />
2629
2631
  <template #code>
2630
2632
  ${md.render(`\`\`\`${ext}${codeSetting}
@@ -2637,10 +2639,10 @@ var target3 = "md-power/demo/vue";
2637
2639
  var vueContainerRender = {
2638
2640
  before: (app, md, env, meta, codeMap) => {
2639
2641
  const { url, title, desc, expanded = false } = meta;
2640
- const componentName2 = `DemoContainer${url}`;
2642
+ const componentName = `DemoContainer${url}`;
2641
2643
  const prefix = (env.filePathRelative || "").replace(/\.md$/, "").replace(/\//g, "-");
2642
2644
  env.demoFiles ??= [];
2643
- const output = app.dir.temp(path6.join(target3, `${prefix}-${componentName2}`));
2645
+ const output = app.dir.temp(path6.join(target3, `${prefix}-${componentName}`));
2644
2646
  if (codeMap.vue || codeMap.js || codeMap.ts) {
2645
2647
  let scriptOutput = output;
2646
2648
  let content = "";
@@ -2655,7 +2657,7 @@ var vueContainerRender = {
2655
2657
  content = codeMap.js;
2656
2658
  }
2657
2659
  content = transformImports(content, env.filePath || "");
2658
- const script = { type: "vue", export: componentName2, path: scriptOutput, gitignore: true };
2660
+ const script = { type: "vue", export: componentName, path: scriptOutput, gitignore: true };
2659
2661
  writeFileSync(scriptOutput, content);
2660
2662
  if (!env.demoFiles.some((d) => d.path === scriptOutput)) {
2661
2663
  env.demoFiles.push(script);
@@ -2685,8 +2687,8 @@ var vueContainerRender = {
2685
2687
  insertSetupScript(style, env);
2686
2688
  }
2687
2689
  }
2688
- return `<VPDemoBasic type="vue"${title ? ` title="${title}"` : ""}${desc ? ` desc="${desc}"` : ""}${expanded ? " expanded" : ""}>
2689
- <${componentName2} />
2690
+ return `<VPDemoBasic${stringifyAttrs({ type: "vue", title, desc, expanded })}>
2691
+ <${componentName} />
2690
2692
  <template #code>
2691
2693
  `;
2692
2694
  },
@@ -2716,24 +2718,24 @@ function demoEmbed(app, md) {
2716
2718
  createEmbedRuleBlock(md, {
2717
2719
  type: "demo",
2718
2720
  syntaxPattern: /^@\[demo(?:\s(vue|normal|markdown))?\s?(.*)\]\((.*)\)/,
2719
- meta: ([, type2, info, url]) => ({
2720
- type: type2 || "normal",
2721
+ meta: ([, type, info, url]) => ({
2722
+ type: type || "normal",
2721
2723
  url,
2722
2724
  ...resolveAttrs(info).attrs
2723
2725
  }),
2724
2726
  content: (meta, content, env) => {
2725
- const { url, type: type2 } = meta;
2727
+ const { url, type } = meta;
2726
2728
  if (!url) {
2727
2729
  console.warn("[vuepress-plugin-md-power] Invalid demo url: ", url);
2728
2730
  return content;
2729
2731
  }
2730
- if (type2 === "vue") {
2732
+ if (type === "vue") {
2731
2733
  return vueEmbed(app, md, env, meta);
2732
2734
  }
2733
- if (type2 === "normal") {
2735
+ if (type === "normal") {
2734
2736
  return normalEmbed(app, md, env, meta);
2735
2737
  }
2736
- if (type2 === "markdown") {
2738
+ if (type === "markdown") {
2737
2739
  return markdownEmbed(app, md, env, meta);
2738
2740
  }
2739
2741
  return content;
@@ -2767,7 +2769,7 @@ function demoContainer(app, md) {
2767
2769
  return res;
2768
2770
  }
2769
2771
  };
2770
- md.use(container5, "demo", { render });
2772
+ md.use(container2, "demo", { render });
2771
2773
  }
2772
2774
  function parseCodeMapping(tokens, index, cb) {
2773
2775
  const codeMap = {};
@@ -2781,11 +2783,11 @@ function parseCodeMapping(tokens, index, cb) {
2781
2783
  return codeMap;
2782
2784
  }
2783
2785
  function getContainerMeta(info) {
2784
- const [, type2, raw] = (info.trim().slice(4).trim() || "").match(INFO_RE) || [];
2786
+ const [, type, raw] = (info.trim().slice(4).trim() || "").match(INFO_RE) || [];
2785
2787
  const { attrs: attrs2 } = resolveAttrs(raw);
2786
2788
  return {
2787
2789
  url: "",
2788
- type: type2 || "normal",
2790
+ type: type || "normal",
2789
2791
  ...attrs2
2790
2792
  };
2791
2793
  }
@@ -2795,7 +2797,7 @@ function extendsPageWithDemo(page) {
2795
2797
  const markdownEnv = page.markdownEnv;
2796
2798
  const demoFiles = markdownEnv.demoFiles ?? [];
2797
2799
  page.deps.push(
2798
- ...demoFiles.filter(({ type: type2 }) => type2 === "markdown").map(({ path: path9 }) => path9)
2800
+ ...demoFiles.filter(({ type }) => type === "markdown").map(({ path: path9 }) => path9)
2799
2801
  );
2800
2802
  (page.frontmatter.gitInclude ??= []).push(
2801
2803
  ...demoFiles.filter(({ gitignore }) => !gitignore).map(({ path: path9 }) => path9)
@@ -2849,29 +2851,27 @@ var audioReader = (state, silent) => {
2849
2851
  state.posMax = labelEnd;
2850
2852
  const info = state.src.slice(labelStart, labelEnd).trim();
2851
2853
  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);
2854
+ const token = state.push("audio_reader", "AudioReader", 0);
2855
+ token.info = info;
2856
+ token.meta = { src: href, ...attrs2 };
2866
2857
  }
2867
2858
  state.pos = pos + 1;
2868
2859
  state.posMax = max;
2869
2860
  return true;
2870
2861
  };
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";
2862
+ var audioReaderPlugin = (md) => {
2863
+ md.renderer.rules.audio_reader = (tokens, idx) => {
2864
+ const meta = tokens[idx].meta ?? {};
2865
+ if (meta.startTime)
2866
+ meta.startTime = Number(meta.startTime);
2867
+ if (meta.endTime)
2868
+ meta.endTime = Number(meta.endTime);
2869
+ if (meta.volume)
2870
+ meta.volume = Number(meta.volume);
2871
+ return `<AudioReader${stringifyAttrs(meta)} />`;
2872
+ };
2873
+ md.inline.ruler.before("link", "audio-reader", audioReader);
2874
+ };
2875
2875
 
2876
2876
  // src/node/utils/nanoid.ts
2877
2877
  import { customAlphabet } from "nanoid";
@@ -2895,23 +2895,14 @@ function legacyCaniuse(md, { mode = "embed" } = {}) {
2895
2895
  const modeMap = ["image", "embed"];
2896
2896
  const isMode = (mode2) => modeMap.includes(mode2);
2897
2897
  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() || "";
2898
+ createContainerPlugin(md, "caniuse", {
2899
+ before: (info) => {
2907
2900
  const feature = info.split(/\s+/)[0];
2908
2901
  const versions = info.match(/\{(.*)\}/)?.[1] || "";
2909
2902
  return feature ? resolveCanIUse({ feature, mode, versions }) : "";
2910
- } else {
2911
- return "";
2912
- }
2913
- };
2914
- md.use(container6, type2, { validate, render });
2903
+ },
2904
+ after: () => ""
2905
+ });
2915
2906
  }
2916
2907
  function resolveCanIUse({ feature, mode, versions }) {
2917
2908
  if (!feature)
@@ -2928,7 +2919,7 @@ function resolveCanIUse({ feature, mode, versions }) {
2928
2919
  feature = feature.replace(UNDERLINE_RE, "_");
2929
2920
  const { past, future } = resolveVersions(versions);
2930
2921
  const meta = nanoid();
2931
- return `<CanIUseViewer feature="${feature}" meta="${meta}" past="${past}" future="${future}" />`;
2922
+ return `<CanIUseViewer${stringifyAttrs({ feature, meta, past, future })} />`;
2932
2923
  }
2933
2924
  function resolveVersions(versions) {
2934
2925
  if (!versions)
@@ -2955,19 +2946,21 @@ var codepenPlugin = (md) => {
2955
2946
  type: "codepen",
2956
2947
  syntaxPattern: /^@\[codepen([^\]]*)\]\(([^)]*)\)/,
2957
2948
  meta: ([, info, source]) => {
2958
- const { width, height, title, tab: tab3, ...rest } = resolveAttrs(info).attrs;
2949
+ const { width, height, title, tab: tab3, preview, editable, theme } = resolveAttrs(info).attrs;
2959
2950
  const [user, slash] = source.split("/");
2960
2951
  return {
2952
+ title: title || "Code Pen",
2953
+ tab: tab3 || "result",
2961
2954
  width: width ? parseRect(width) : "100%",
2962
2955
  height: height ? parseRect(height) : "400px",
2963
2956
  user,
2964
2957
  slash,
2965
- title: title || "Code Pen",
2966
- tab: tab3 || "result",
2967
- ...rest
2958
+ preview,
2959
+ editable,
2960
+ theme
2968
2961
  };
2969
2962
  },
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}" />`
2963
+ content: (meta) => `<CodePenViewer${stringifyAttrs(meta)} />`
2971
2964
  });
2972
2965
  };
2973
2966
 
@@ -2976,7 +2969,7 @@ var codeSandboxPlugin = (md) => {
2976
2969
  createEmbedRuleBlock(md, {
2977
2970
  type: "codesandbox",
2978
2971
  syntaxPattern: /^@\[codesandbox(?:\s+(embed|button))?([^\]]*)\]\(([^)]*)\)/,
2979
- meta([, type2, info, source]) {
2972
+ meta([, type, info, source]) {
2980
2973
  const { attrs: attrs2 } = resolveAttrs(info);
2981
2974
  const [profile, filepath2 = ""] = source.split("#");
2982
2975
  const [user, id] = profile.includes("/") ? profile.split("/") : ["", profile];
@@ -2989,13 +2982,11 @@ var codeSandboxPlugin = (md) => {
2989
2982
  console: attrs2.console ?? false,
2990
2983
  navbar: attrs2.navbar ?? true,
2991
2984
  layout: attrs2.layout ?? "",
2992
- type: type2 || "embed",
2985
+ type: type || "embed",
2993
2986
  filepath: filepath2
2994
2987
  };
2995
2988
  },
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
- }
2989
+ content: (meta) => `<CodeSandboxViewer${stringifyAttrs(meta)} />`
2999
2990
  });
3000
2991
  };
3001
2992
 
@@ -3015,7 +3006,7 @@ var jsfiddlePlugin = (md) => {
3015
3006
  theme
3016
3007
  };
3017
3008
  },
3018
- content: ({ title, height, width, source, tab: tab3, theme }) => `<JSFiddleViewer source="${source}" title="${title}" tab="${tab3}" width="${width}" height="${height}"${theme ? ` theme="${theme}"` : ""} />`
3009
+ content: (meta) => `<JSFiddleViewer${stringifyAttrs(meta)} />`
3019
3010
  });
3020
3011
  };
3021
3012
 
@@ -3034,9 +3025,7 @@ var replitPlugin = (md) => {
3034
3025
  theme: attrs2.theme || ""
3035
3026
  };
3036
3027
  },
3037
- content({ title, height, width, source, theme }) {
3038
- return `<ReplitViewer title="${title || ""}" height="${height}" width="${width}" source="${source}" theme="${theme}" />`;
3039
- }
3028
+ content: (meta) => `<ReplitViewer${stringifyAttrs(meta)} />`
3040
3029
  });
3041
3030
  };
3042
3031
 
@@ -3060,15 +3049,13 @@ var pdfPlugin = (md) => {
3060
3049
  title: path7.basename(src || "")
3061
3050
  };
3062
3051
  },
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
- }
3052
+ content: (meta) => `<PDFViewer${stringifyAttrs(meta)} />`
3066
3053
  });
3067
3054
  };
3068
3055
 
3069
3056
  // src/node/embed/video/artPlayer.ts
3070
3057
  import { isPackageExists as isPackageExists2 } from "local-pkg";
3071
- import { colors as colors2 } from "vuepress/utils";
3058
+ import { colors as colors3 } from "vuepress/utils";
3072
3059
  var installed = {
3073
3060
  dashjs: isPackageExists2("dashjs"),
3074
3061
  hlsjs: isPackageExists2("hls.js"),
@@ -3085,6 +3072,8 @@ var artPlayerPlugin = (md) => {
3085
3072
  const url = source.trim();
3086
3073
  checkSupportType(attrs2.type ?? url.split(".").pop());
3087
3074
  return {
3075
+ url,
3076
+ type: attrs2.type,
3088
3077
  autoplay: attrs2.autoplay ?? false,
3089
3078
  muted: attrs2.muted ?? attrs2.autoplay ?? false,
3090
3079
  autoMini: attrs2.autoMini ?? false,
@@ -3092,23 +3081,22 @@ var artPlayerPlugin = (md) => {
3092
3081
  volume: typeof attrs2.volume !== "undefined" ? Number(attrs2.volume) : 0.75,
3093
3082
  poster: attrs2.poster,
3094
3083
  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
3084
+ height: attrs2.height ? parseRect(attrs2.height) : void 0,
3085
+ ratio: attrs2.ratio ? parseRect(`${attrs2.ratio}`) : void 0
3099
3086
  };
3100
3087
  },
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}"` : ""}/>`;
3088
+ content({ url, ...meta }) {
3089
+ meta.muted = meta.muted || meta.autoplay;
3090
+ return `<ArtPlayer src="${url}" fullscreen flip playback-rate aspect-ratio setting pip${stringifyAttrs(meta)}/>`;
3103
3091
  }
3104
3092
  });
3105
3093
  };
3106
- function checkSupportType(type2) {
3107
- if (!type2)
3094
+ function checkSupportType(type) {
3095
+ if (!type)
3108
3096
  return;
3109
- if (SUPPORTED_VIDEO_TYPES.includes(type2)) {
3097
+ if (SUPPORTED_VIDEO_TYPES.includes(type)) {
3110
3098
  let name = "";
3111
- switch (type2.toLowerCase()) {
3099
+ switch (type.toLowerCase()) {
3112
3100
  case "m3u8":
3113
3101
  case "hls":
3114
3102
  name = !installed.hlsjs ? "hls.js" : "";
@@ -3124,10 +3112,10 @@ function checkSupportType(type2) {
3124
3112
  break;
3125
3113
  }
3126
3114
  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`);
3115
+ 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
3116
  }
3129
3117
  } else {
3130
- console.warn(`${colors2.yellow("[vuepress-plugin-md-power] artPlayer: ")} unsupported video type: ${colors2.cyan(type2)}`);
3118
+ console.warn(`${colors3.yellow("[vuepress-plugin-md-power] artPlayer: ")} unsupported video type: ${colors3.cyan(type)}`);
3131
3119
  }
3132
3120
  }
3133
3121
 
@@ -3166,31 +3154,27 @@ var bilibiliPlugin = (md) => {
3166
3154
  time: timeToSeconds(attrs2.time),
3167
3155
  title: attrs2.title,
3168
3156
  width: attrs2.width ? parseRect(attrs2.width) : "100%",
3169
- height: attrs2.height ? parseRect(attrs2.height) : "",
3170
- ratio: attrs2.ratio ? parseRect(attrs2.ratio) : ""
3157
+ height: attrs2.height ? parseRect(attrs2.height) : void 0,
3158
+ ratio: attrs2.ratio ? parseRect(attrs2.ratio) : void 0
3171
3159
  };
3172
3160
  },
3173
3161
  content(meta) {
3174
3162
  const params = new URLSearchParams();
3175
- if (meta.bvid) {
3163
+ if (meta.bvid)
3176
3164
  params.set("bvid", meta.bvid);
3177
- }
3178
- if (meta.aid) {
3165
+ if (meta.aid)
3179
3166
  params.set("aid", meta.aid);
3180
- }
3181
- if (meta.cid) {
3167
+ if (meta.cid)
3182
3168
  params.set("cid", meta.cid);
3183
- }
3184
- if (meta.page) {
3169
+ if (meta.page)
3185
3170
  params.set("p", meta.page.toString());
3186
- }
3187
- if (meta.time) {
3171
+ if (meta.time)
3188
3172
  params.set("t", meta.time.toString());
3189
- }
3190
3173
  params.set("autoplay", meta.autoplay ? "1" : "0");
3191
3174
  params.set("high_quality", "1");
3192
3175
  const source = `${BILIBILI_LINK}?${params.toString()}`;
3193
- return `<VideoBilibili src="${source}" width="${meta.width}" height="${meta.height}" ratio="${meta.ratio}" title="${meta.title}" />`;
3176
+ const { width, height, ratio, title } = meta;
3177
+ return `<VideoBilibili${stringifyAttrs({ src: source, width, height, ratio, title })} />`;
3194
3178
  }
3195
3179
  });
3196
3180
  };
@@ -3213,26 +3197,23 @@ var youtubePlugin = (md) => {
3213
3197
  end: timeToSeconds(attrs2.end),
3214
3198
  title: attrs2.title,
3215
3199
  width: attrs2.width ? parseRect(attrs2.width) : "100%",
3216
- height: attrs2.height ? parseRect(attrs2.height) : "",
3217
- ratio: attrs2.ratio ? parseRect(attrs2.ratio) : ""
3200
+ height: attrs2.height ? parseRect(attrs2.height) : void 0,
3201
+ ratio: attrs2.ratio ? parseRect(attrs2.ratio) : void 0
3218
3202
  };
3219
3203
  },
3220
3204
  content(meta) {
3221
3205
  const params = new URLSearchParams2();
3222
- if (meta.autoplay) {
3206
+ if (meta.autoplay)
3223
3207
  params.set("autoplay", "1");
3224
- }
3225
- if (meta.loop) {
3208
+ if (meta.loop)
3226
3209
  params.set("loop", "1");
3227
- }
3228
- if (meta.start) {
3210
+ if (meta.start)
3229
3211
  params.set("start", meta.start.toString());
3230
- }
3231
- if (meta.end) {
3212
+ if (meta.end)
3232
3213
  params.set("end", meta.end.toString());
3233
- }
3234
3214
  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}" />`;
3215
+ const { width, height, ratio, title } = meta;
3216
+ return `<VideoYoutube${stringifyAttrs({ src: source, width, height, ratio, title })} />`;
3236
3217
  }
3237
3218
  });
3238
3219
  };
@@ -3520,16 +3501,17 @@ var annotationPlugin = (md) => {
3520
3501
  };
3521
3502
 
3522
3503
  // src/node/inline/icons.ts
3523
- var iconsPlugin = (md, options = {}) => md.inline.ruler.before("emphasis", "iconify", createTokenizer(options));
3524
- function createTokenizer(options) {
3504
+ import { colors as colors4 } from "vuepress/utils";
3505
+ function createIconRule([l1, l2, r1, r2], deprecated) {
3525
3506
  return (state, silent) => {
3526
3507
  let found = false;
3527
3508
  const max = state.posMax;
3528
3509
  const start = state.pos;
3529
- if (state.src.charCodeAt(start) !== 58 || state.src.charCodeAt(start + 1) !== 91) {
3510
+ if (state.src.charCodeAt(start) !== l1 || state.src.charCodeAt(start + 1) !== l2) {
3530
3511
  return false;
3531
3512
  }
3532
- if (state.src.charCodeAt(start + 2) === 32)
3513
+ const next = state.src.charCodeAt(start + 2);
3514
+ if (next === 32 || next === 58)
3533
3515
  return false;
3534
3516
  if (silent)
3535
3517
  return false;
@@ -3537,7 +3519,7 @@ function createTokenizer(options) {
3537
3519
  return false;
3538
3520
  state.pos = start + 2;
3539
3521
  while (state.pos < max) {
3540
- if (state.src.charCodeAt(state.pos) === 93 && state.src.charCodeAt(state.pos + 1) === 58) {
3522
+ if (state.src.charCodeAt(state.pos) === r1 && state.src.charCodeAt(state.pos + 1) === r2) {
3541
3523
  found = true;
3542
3524
  break;
3543
3525
  }
@@ -3547,69 +3529,103 @@ function createTokenizer(options) {
3547
3529
  state.pos = start;
3548
3530
  return false;
3549
3531
  }
3550
- const content = state.src.slice(start + 2, state.pos);
3532
+ const info = state.src.slice(start + 2, state.pos);
3551
3533
  state.posMax = state.pos;
3552
3534
  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 = "]:";
3535
+ const icon = state.push("icon", "i", 0);
3536
+ icon.markup = "::";
3537
+ icon.content = info;
3538
+ icon.meta = { deprecated };
3564
3539
  state.pos = state.posMax + 2;
3565
3540
  state.posMax = max;
3566
3541
  return true;
3567
3542
  };
3568
3543
  }
3544
+ var RE_SIZE = /(?<=\s|^)=(.+?)(?:\s|$)/;
3545
+ var RE_COLOR = /(?<=\s|^)\/(.+?)(?:\s|$)/;
3546
+ function iconRender(content, options) {
3547
+ let size = options.size;
3548
+ let color = options.color;
3549
+ content = content.replace(RE_SIZE, (_, s) => {
3550
+ size = s;
3551
+ return "";
3552
+ }).replace(RE_COLOR, (_, c) => {
3553
+ color = c;
3554
+ return "";
3555
+ }).trim();
3556
+ const [name, ...extra] = content.split(/\s+/);
3557
+ return `<VPIcon${stringifyAttrs({ name, size, color, class: extra.length ? extra.join(" ") : void 0 })} />`;
3558
+ }
3559
+ var iconPlugin = (md, options = {}) => {
3560
+ md.inline.ruler.before(
3561
+ "link",
3562
+ "icon",
3563
+ // : : : :
3564
+ createIconRule([58, 58, 58, 58])
3565
+ );
3566
+ md.inline.ruler.before(
3567
+ "link",
3568
+ "icon_deprecated",
3569
+ // : [ ] :
3570
+ createIconRule([58, 91, 93, 58], true)
3571
+ );
3572
+ md.renderer.rules.icon = (tokens, idx, _, env) => {
3573
+ const { content, meta } = tokens[idx];
3574
+ let icon = content;
3575
+ if (meta.deprecated) {
3576
+ const [name, opt = ""] = content.split(" ");
3577
+ const [size, color] = opt.trim().split("/");
3578
+ icon = `${name}${size ? ` =${size}` : ""}${color ? ` /${color}` : ""}`;
3579
+ console.warn(`The icon syntax of \`${colors4.yellow(`:[${content}]:`)}\` is deprecated, please use \`${colors4.green(`::${icon}::`)}\` instead. (${colors4.gray(env.filePathRelative || env.filePath)})`);
3580
+ }
3581
+ return iconRender(icon, options);
3582
+ };
3583
+ };
3569
3584
 
3570
3585
  // 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;
3586
+ var plotDef = (state, silent) => {
3587
+ let found = false;
3588
+ const max = state.posMax;
3589
+ const start = state.pos;
3590
+ if (state.src.charCodeAt(start) !== 33 || state.src.charCodeAt(start + 1) !== 33) {
3591
+ return false;
3592
+ }
3593
+ const next = state.src.charCodeAt(start + 2);
3594
+ if (next === 32 || next === 33)
3595
+ return false;
3596
+ if (silent)
3597
+ return false;
3598
+ if (max - start < 5)
3599
+ return false;
3600
+ state.pos = start + 2;
3601
+ while (state.pos < max) {
3602
+ if (state.src.charCodeAt(state.pos) === 33 && state.src.charCodeAt(state.pos + 1) === 33) {
3603
+ found = true;
3604
+ break;
3598
3605
  }
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;
3606
+ state.md.inline.skipToken(state);
3607
+ }
3608
+ if (!found || start + 2 === state.pos || state.src.charCodeAt(state.pos - 1) === 32) {
3609
+ state.pos = start;
3610
+ return false;
3611
+ }
3612
+ const content = state.src.slice(start + 2, state.pos);
3613
+ state.posMax = state.pos;
3614
+ state.pos = start + 2;
3615
+ const token = state.push("plot_inline", "Plot", 0);
3616
+ token.markup = "!!";
3617
+ token.content = content;
3618
+ state.pos = state.posMax + 2;
3619
+ state.posMax = max;
3620
+ return true;
3621
+ };
3622
+ var plotPlugin = (md) => {
3623
+ md.renderer.rules.plot_inline = (tokens, idx) => {
3624
+ const token = tokens[idx];
3625
+ return `<Plot>${token.content}</Plot>`;
3611
3626
  };
3612
- }
3627
+ md.inline.ruler.before("emphasis", "plot", plotDef);
3628
+ };
3613
3629
 
3614
3630
  // src/node/inline/index.ts
3615
3631
  function inlineSyntaxPlugin(md, options) {
@@ -3626,7 +3642,7 @@ function inlineSyntaxPlugin(md, options) {
3626
3642
  md.use(abbrPlugin);
3627
3643
  }
3628
3644
  if (options.icons) {
3629
- md.use(iconsPlugin, isPlainObject3(options.icons) ? options.icons : {});
3645
+ md.use(iconPlugin, isPlainObject3(options.icons) ? options.icons : {});
3630
3646
  }
3631
3647
  if (options.plot === true || isPlainObject3(options.plot) && options.plot.tag !== false) {
3632
3648
  md.use(plotPlugin);
@@ -3689,8 +3705,8 @@ async function prepareConfigFile(app, options) {
3689
3705
  enhances.add(`app.component('CanIUseViewer', CanIUse)`);
3690
3706
  }
3691
3707
  if (options.fileTree) {
3692
- imports.add(`import FileTreeItem from '${CLIENT_FOLDER}components/FileTreeItem.vue'`);
3693
- enhances.add(`app.component('FileTreeItem', FileTreeItem)`);
3708
+ imports.add(`import FileTreeNode from '${CLIENT_FOLDER}components/FileTreeNode.vue'`);
3709
+ enhances.add(`app.component('FileTreeNode', FileTreeNode)`);
3694
3710
  }
3695
3711
  if (options.artPlayer) {
3696
3712
  imports.add(`import ArtPlayer from '${CLIENT_FOLDER}components/ArtPlayer.vue'`);
@@ -3729,6 +3745,10 @@ async function prepareConfigFile(app, options) {
3729
3745
  if (options.chat) {
3730
3746
  imports.add(`import '${CLIENT_FOLDER}styles/chat.css'`);
3731
3747
  }
3748
+ if (options.field) {
3749
+ imports.add(`import VPField from '${CLIENT_FOLDER}components/VPField.vue'`);
3750
+ enhances.add(`app.component('VPField', VPField)`);
3751
+ }
3732
3752
  return app.writeTemp(
3733
3753
  "md-power/config.js",
3734
3754
  `import { defineClientConfig } from 'vuepress/client'