@slidev/cli 0.48.0-beta.15 → 0.48.0-beta.16

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.
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  resolveImportPath,
6
6
  toAtFS
7
- } from "./chunk-7HOZGSL4.mjs";
7
+ } from "./chunk-G3BP3FUT.mjs";
8
8
  import {
9
9
  __commonJS,
10
10
  __toESM
@@ -2496,7 +2496,7 @@ var require_semver2 = __commonJS({
2496
2496
  });
2497
2497
 
2498
2498
  // package.json
2499
- var version = "0.48.0-beta.15";
2499
+ var version = "0.48.0-beta.16";
2500
2500
 
2501
2501
  // node/common.ts
2502
2502
  import { existsSync, promises as fs } from "node:fs";
@@ -2563,9 +2563,9 @@ async function mergeViteConfigs({ roots, entry }, viteConfig, config, command) {
2563
2563
  }
2564
2564
 
2565
2565
  // node/plugins/preset.ts
2566
- import { join as join7 } from "node:path";
2566
+ import { join as join6 } from "node:path";
2567
2567
  import { existsSync as existsSync3 } from "node:fs";
2568
- import process3 from "node:process";
2568
+ import process2 from "node:process";
2569
2569
  import { fileURLToPath } from "node:url";
2570
2570
  import Vue from "@vitejs/plugin-vue";
2571
2571
  import VueJsx from "@vitejs/plugin-vue-jsx";
@@ -2645,6 +2645,11 @@ var EXCLUDE = [
2645
2645
  "vue-demi",
2646
2646
  "vue"
2647
2647
  ];
2648
+ var ASYNC_MODULES = [
2649
+ "file-saver",
2650
+ "vue",
2651
+ "@vue"
2652
+ ];
2648
2653
  function createConfigPlugin(options) {
2649
2654
  return {
2650
2655
  name: "slidev:config",
@@ -2680,8 +2685,40 @@ function createConfigPlugin(options) {
2680
2685
  ])
2681
2686
  }
2682
2687
  },
2683
- publicDir: join3(options.userRoot, "public")
2688
+ publicDir: join3(options.userRoot, "public"),
2689
+ build: {
2690
+ rollupOptions: {
2691
+ output: {
2692
+ chunkFileNames(chunkInfo) {
2693
+ const DEFAULT = "[name]-[hash].js";
2694
+ if (chunkInfo.name.includes("/") || chunkInfo.name === "entry")
2695
+ return DEFAULT;
2696
+ if (chunkInfo.moduleIds.filter((i) => isSlidevClient(i)).length > chunkInfo.moduleIds.length * 0.6)
2697
+ return "slidev/[name]-[hash].js";
2698
+ if (chunkInfo.moduleIds.filter((i) => i.includes("/monaco-editor/")).length > chunkInfo.moduleIds.length * 0.6)
2699
+ return "monaco/[name]-[hash].js";
2700
+ return DEFAULT;
2701
+ },
2702
+ manualChunks(id) {
2703
+ if (id.startsWith("/@slidev-monaco-types/") || id.includes("/@slidev/monaco-types") || id.match(/(\.d\.[mc]?ts|package.json)\?raw$/))
2704
+ return "monaco/bundled-types";
2705
+ if (id.includes("/shiki/") || id.includes("/@shikijs/"))
2706
+ return `modules/shiki`;
2707
+ if (id.startsWith("~icons/"))
2708
+ return "modules/unplugin-icons";
2709
+ if (id.includes("/client/main.ts"))
2710
+ return "entry";
2711
+ const matchedAsyncModule = ASYNC_MODULES.find((i) => id.includes(`/node_modules/${i}`));
2712
+ if (matchedAsyncModule)
2713
+ return `modules/${matchedAsyncModule.replace("@", "").replace("/", "-")}`;
2714
+ }
2715
+ }
2716
+ }
2717
+ }
2684
2718
  };
2719
+ function isSlidevClient(id) {
2720
+ return id.includes("/@slidev/") || id.includes("/slidev/packages/client/") || id.includes("/@vueuse/");
2721
+ }
2685
2722
  if (isInstalledGlobally) {
2686
2723
  injection.cacheDir = join3(options.cliRoot, "node_modules/.vite");
2687
2724
  injection.root = options.cliRoot;
@@ -2718,1494 +2755,1560 @@ function getDefine(options) {
2718
2755
  }
2719
2756
 
2720
2757
  // node/plugins/loaders.ts
2721
- import { basename as basename2, join as join4 } from "node:path";
2722
- import { isString, isTruthy, notNullish, objectMap, range } from "@antfu/utils";
2758
+ import { basename as basename2, join as join4, resolve as resolve2 } from "node:path";
2759
+ import { builtinModules } from "node:module";
2760
+ import { isString, isTruthy as isTruthy2, notNullish, objectMap, range } from "@antfu/utils";
2723
2761
  import fg2 from "fast-glob";
2724
- import fs3 from "fs-extra";
2725
- import Markdown from "markdown-it";
2762
+ import fs5 from "fs-extra";
2763
+ import Markdown2 from "markdown-it";
2726
2764
  import { bold, gray, red, yellow } from "kolorist";
2727
- import mila from "markdown-it-link-attributes";
2765
+ import mila2 from "markdown-it-link-attributes";
2728
2766
  import * as parser from "@slidev/parser/fs";
2729
2767
  import equal from "fast-deep-equal";
2730
- var regexId = /^\/\@slidev\/slide\/(\d+)\.(md|json)(?:\?import)?$/;
2731
- var regexIdQuery = /(\d+?)\.(md|json|frontmatter)$/;
2732
- var templateInjectionMarker = "/* @slidev-injection */";
2733
- var templateImportContextUtils = `import {
2734
- useSlideContext,
2735
- provideFrontmatter as _provideFrontmatter,
2736
- frontmatterToProps as _frontmatterToProps,
2737
- } from "@slidev/client/context.ts"`.replace(/\n\s*/g, " ");
2738
- var templateInitContext = `const { $slidev, $nav, $clicksContext, $clicks, $page, $renderContext, $frontmatter } = useSlideContext()`;
2739
- function getBodyJson(req) {
2740
- return new Promise((resolve3, reject) => {
2741
- let body = "";
2742
- req.on("data", (chunk) => body += chunk);
2743
- req.on("error", reject);
2744
- req.on("end", () => {
2745
- try {
2746
- resolve3(JSON.parse(body) || {});
2747
- } catch (e) {
2748
- reject(e);
2768
+
2769
+ // node/plugins/markdown.ts
2770
+ import fs4 from "node:fs/promises";
2771
+ import Markdown from "unplugin-vue-markdown/vite";
2772
+ import { isTruthy, slash } from "@antfu/utils";
2773
+
2774
+ // ../../node_modules/.pnpm/@hedgedoc+markdown-it-plugins@2.1.4_patch_hash=tuyuxytl56b2vxulpkzt2wf4o4_markdown-it@14.0.0/node_modules/@hedgedoc/markdown-it-plugins/dist/esm/image-size/specialCharacters.js
2775
+ var SpecialCharacters;
2776
+ (function(SpecialCharacters2) {
2777
+ SpecialCharacters2[SpecialCharacters2["EXCLAMATION_MARK"] = 33] = "EXCLAMATION_MARK";
2778
+ SpecialCharacters2[SpecialCharacters2["OPENING_BRACKET"] = 91] = "OPENING_BRACKET";
2779
+ SpecialCharacters2[SpecialCharacters2["OPENING_PARENTHESIS"] = 40] = "OPENING_PARENTHESIS";
2780
+ SpecialCharacters2[SpecialCharacters2["WHITESPACE"] = 32] = "WHITESPACE";
2781
+ SpecialCharacters2[SpecialCharacters2["NEW_LINE"] = 10] = "NEW_LINE";
2782
+ SpecialCharacters2[SpecialCharacters2["EQUALS"] = 61] = "EQUALS";
2783
+ SpecialCharacters2[SpecialCharacters2["LOWER_CASE_X"] = 120] = "LOWER_CASE_X";
2784
+ SpecialCharacters2[SpecialCharacters2["NUMBER_ZERO"] = 48] = "NUMBER_ZERO";
2785
+ SpecialCharacters2[SpecialCharacters2["NUMBER_NINE"] = 57] = "NUMBER_NINE";
2786
+ SpecialCharacters2[SpecialCharacters2["PERCENTAGE"] = 37] = "PERCENTAGE";
2787
+ SpecialCharacters2[SpecialCharacters2["CLOSING_PARENTHESIS"] = 41] = "CLOSING_PARENTHESIS";
2788
+ })(SpecialCharacters || (SpecialCharacters = {}));
2789
+
2790
+ // ../../node_modules/.pnpm/@hedgedoc+markdown-it-plugins@2.1.4_patch_hash=tuyuxytl56b2vxulpkzt2wf4o4_markdown-it@14.0.0/node_modules/@hedgedoc/markdown-it-plugins/dist/esm/task-lists/index.js
2791
+ import Token from "markdown-it/lib/token.mjs";
2792
+ var checkboxRegex = /^ *\[([\sx])] /i;
2793
+ function taskLists(md2, options = { enabled: false, label: false, lineNumber: false }) {
2794
+ md2.core.ruler.after("inline", "task-lists", (state) => processToken(state, options));
2795
+ md2.renderer.rules.taskListItemCheckbox = (tokens) => {
2796
+ const token = tokens[0];
2797
+ const checkedAttribute = token.attrGet("checked") ? 'checked="" ' : "";
2798
+ const disabledAttribute = token.attrGet("disabled") ? 'disabled="" ' : "";
2799
+ const line = token.attrGet("line");
2800
+ const idAttribute = `id="${token.attrGet("id")}" `;
2801
+ const dataLineAttribute = line && options.lineNumber ? `data-line="${line}" ` : "";
2802
+ return `<input class="task-list-item-checkbox" type="checkbox" ${checkedAttribute}${disabledAttribute}${dataLineAttribute}${idAttribute}/>`;
2803
+ };
2804
+ md2.renderer.rules.taskListItemLabel_close = () => {
2805
+ return "</label>";
2806
+ };
2807
+ md2.renderer.rules.taskListItemLabel_open = (tokens) => {
2808
+ const token = tokens[0];
2809
+ const id = token.attrGet("id");
2810
+ return `<label for="${id}">`;
2811
+ };
2812
+ }
2813
+ function processToken(state, options) {
2814
+ const allTokens = state.tokens;
2815
+ for (let i = 2; i < allTokens.length; i++) {
2816
+ if (!isTodoItem(allTokens, i)) {
2817
+ continue;
2818
+ }
2819
+ todoify(allTokens[i], options);
2820
+ allTokens[i - 2].attrJoin("class", `task-list-item ${options.enabled ? " enabled" : ""}`);
2821
+ const parentToken = findParentToken(allTokens, i - 2);
2822
+ if (parentToken) {
2823
+ const classes = parentToken.attrGet("class") ?? "";
2824
+ if (!classes.match(/(^| )contains-task-list/)) {
2825
+ parentToken.attrJoin("class", "contains-task-list");
2749
2826
  }
2750
- });
2751
- });
2827
+ }
2828
+ }
2829
+ return false;
2752
2830
  }
2753
- var md = Markdown({ html: true });
2754
- md.use(mila, {
2755
- attrs: {
2756
- target: "_blank",
2757
- rel: "noopener"
2831
+ function findParentToken(tokens, index) {
2832
+ const targetLevel = tokens[index].level - 1;
2833
+ for (let currentTokenIndex = index - 1; currentTokenIndex >= 0; currentTokenIndex--) {
2834
+ if (tokens[currentTokenIndex].level === targetLevel) {
2835
+ return tokens[currentTokenIndex];
2836
+ }
2758
2837
  }
2759
- });
2760
- function renderNote(text = "") {
2761
- let clickCount = 0;
2762
- const html = md.render(
2763
- text.replace(/\[click(?::(\d+))?\]/gi, (_, count = 1) => {
2764
- clickCount += Number(count);
2765
- return `<span class="slidev-note-click-mark" data-clicks="${clickCount}"></span>`;
2766
- })
2767
- );
2768
- return html;
2838
+ return void 0;
2769
2839
  }
2770
- function withRenderedNote(data) {
2840
+ function isTodoItem(tokens, index) {
2841
+ return isInline(tokens[index]) && isParagraph(tokens[index - 1]) && isListItem(tokens[index - 2]) && startsWithTodoMarkdown(tokens[index]);
2842
+ }
2843
+ function todoify(token, options) {
2844
+ if (token.children == null) {
2845
+ return;
2846
+ }
2847
+ const id = generateIdForToken(token);
2848
+ token.children.splice(0, 0, createCheckboxToken(token, options.enabled, id));
2849
+ token.children[1].content = token.children[1].content.replace(checkboxRegex, "");
2850
+ if (options.label) {
2851
+ token.children.splice(1, 0, createLabelBeginToken(id));
2852
+ token.children.push(createLabelEndToken());
2853
+ }
2854
+ }
2855
+ function generateIdForToken(token) {
2856
+ if (token.map) {
2857
+ return `task-item-${token.map[0]}`;
2858
+ } else {
2859
+ return `task-item-${Math.ceil(Math.random() * (1e4 * 1e3) - 1e3)}`;
2860
+ }
2861
+ }
2862
+ function createCheckboxToken(token, enabled, id) {
2863
+ const checkbox = new Token("taskListItemCheckbox", "", 0);
2864
+ if (!enabled) {
2865
+ checkbox.attrSet("disabled", "true");
2866
+ }
2867
+ if (token.map) {
2868
+ checkbox.attrSet("line", token.map[0].toString());
2869
+ }
2870
+ checkbox.attrSet("id", id);
2871
+ const checkboxRegexResult = checkboxRegex.exec(token.content);
2872
+ const isChecked = checkboxRegexResult?.[1].toLowerCase() === "x";
2873
+ if (isChecked) {
2874
+ checkbox.attrSet("checked", "true");
2875
+ }
2876
+ return checkbox;
2877
+ }
2878
+ function createLabelBeginToken(id) {
2879
+ const labelBeginToken = new Token("taskListItemLabel_open", "", 1);
2880
+ labelBeginToken.attrSet("id", id);
2881
+ return labelBeginToken;
2882
+ }
2883
+ function createLabelEndToken() {
2884
+ return new Token("taskListItemLabel_close", "", -1);
2885
+ }
2886
+ function isInline(token) {
2887
+ return token.type === "inline";
2888
+ }
2889
+ function isParagraph(token) {
2890
+ return token.type === "paragraph_open";
2891
+ }
2892
+ function isListItem(token) {
2893
+ return token.type === "list_item_open";
2894
+ }
2895
+ function startsWithTodoMarkdown(token) {
2896
+ return checkboxRegex.test(token.content);
2897
+ }
2898
+
2899
+ // ../../node_modules/.pnpm/@hedgedoc+markdown-it-plugins@2.1.4_patch_hash=tuyuxytl56b2vxulpkzt2wf4o4_markdown-it@14.0.0/node_modules/@hedgedoc/markdown-it-plugins/dist/esm/toc/plugin.js
2900
+ import { Optional } from "@mrdrogdrog/optional";
2901
+
2902
+ // node/plugins/markdown.ts
2903
+ import { encode as encodePlantUml } from "plantuml-encoder";
2904
+ import Mdc from "markdown-it-mdc";
2905
+ import { codeToKeyedTokens, createMagicMoveMachine } from "shiki-magic-move/core";
2906
+ import mila from "markdown-it-link-attributes";
2907
+ import mif from "markdown-it-footnote";
2908
+ import lz from "lz-string";
2909
+
2910
+ // node/plugins/markdown-it-katex.ts
2911
+ import katex from "katex";
2912
+ function isValidDelim(state, pos) {
2913
+ const max = state.posMax;
2914
+ let can_open = true;
2915
+ let can_close = true;
2916
+ const prevChar = pos > 0 ? state.src.charCodeAt(pos - 1) : -1;
2917
+ const nextChar = pos + 1 <= max ? state.src.charCodeAt(pos + 1) : -1;
2918
+ if (prevChar === 32 || prevChar === 9 || /* \t */
2919
+ nextChar >= 48 && nextChar <= 57)
2920
+ can_close = false;
2921
+ if (nextChar === 32 || nextChar === 9)
2922
+ can_open = false;
2771
2923
  return {
2772
- ...data,
2773
- noteHTML: renderNote(data?.note)
2924
+ can_open,
2925
+ can_close
2774
2926
  };
2775
2927
  }
2776
- function createSlidesLoader({ data, clientRoot, roots, remote, mode }, pluginOptions, serverOptions) {
2777
- const slidePrefix = "/@slidev/slides/";
2778
- const hmrPages = /* @__PURE__ */ new Set();
2779
- let server;
2780
- let _layouts_cache_time = 0;
2781
- let _layouts_cache = {};
2782
- return [
2783
- {
2784
- name: "slidev:loader",
2785
- configureServer(_server) {
2786
- server = _server;
2787
- updateServerWatcher();
2788
- server.middlewares.use(async (req, res, next) => {
2789
- const match = req.url?.match(regexId);
2790
- if (!match)
2791
- return next();
2792
- const [, no, type] = match;
2793
- const idx = Number.parseInt(no);
2794
- if (type === "json" && req.method === "GET") {
2795
- res.write(JSON.stringify(withRenderedNote(data.slides[idx])));
2796
- return res.end();
2797
- }
2798
- if (type === "json" && req.method === "POST") {
2799
- const body = await getBodyJson(req);
2800
- const slide = data.slides[idx];
2801
- if (body.content && body.content !== slide.source.content)
2802
- hmrPages.add(idx);
2803
- Object.assign(slide.source, body);
2804
- parser.prettifySlide(slide.source);
2805
- await parser.save(data.markdownFiles[slide.source.filepath]);
2806
- res.statusCode = 200;
2807
- res.write(JSON.stringify(withRenderedNote(slide)));
2808
- return res.end();
2809
- }
2810
- next();
2811
- });
2812
- },
2813
- async handleHotUpdate(ctx) {
2814
- if (!data.watchFiles.includes(ctx.file))
2815
- return;
2816
- await ctx.read();
2817
- const newData = await serverOptions.loadData?.();
2818
- if (!newData)
2819
- return [];
2820
- const moduleIds = /* @__PURE__ */ new Set();
2821
- if (data.slides.length !== newData.slides.length) {
2822
- moduleIds.add("/@slidev/routes");
2823
- range(newData.slides.length).map((i) => hmrPages.add(i));
2824
- }
2825
- if (!equal(data.headmatter.defaults, newData.headmatter.defaults)) {
2826
- moduleIds.add("/@slidev/routes");
2827
- range(data.slides.length).map((i) => hmrPages.add(i));
2828
- }
2829
- if (!equal(data.config, newData.config))
2830
- moduleIds.add("/@slidev/configs");
2831
- if (!equal(data.features, newData.features)) {
2832
- setTimeout(() => {
2833
- ctx.server.ws.send({ type: "full-reload" });
2834
- }, 1);
2835
- }
2836
- const length = Math.max(data.slides.length, newData.slides.length);
2837
- for (let i = 0; i < length; i++) {
2838
- const a = data.slides[i];
2839
- const b = newData.slides[i];
2840
- if (a?.content.trim() === b?.content.trim() && a?.title?.trim() === b?.title?.trim() && equal(a.frontmatter, b.frontmatter) && Object.entries(a.snippetsUsed ?? {}).every(([file, oldContent]) => {
2841
- try {
2842
- const newContent = fs3.readFileSync(file, "utf-8");
2843
- return oldContent === newContent;
2844
- } catch {
2845
- return false;
2846
- }
2847
- })) {
2848
- if (a?.note !== b?.note) {
2849
- ctx.server.ws.send({
2850
- type: "custom",
2851
- event: "slidev-update-note",
2852
- data: {
2853
- id: i,
2854
- note: b.note || "",
2855
- noteHTML: renderNote(b.note || "")
2856
- }
2857
- });
2858
- }
2859
- continue;
2860
- }
2861
- ctx.server.ws.send({
2862
- type: "custom",
2863
- event: "slidev-update",
2864
- data: {
2865
- id: i,
2866
- data: withRenderedNote(newData.slides[i])
2867
- }
2868
- });
2869
- hmrPages.add(i);
2870
- }
2871
- Object.assign(data, newData);
2872
- if (hmrPages.size > 0)
2873
- moduleIds.add("/@slidev/titles.md");
2874
- const vueModules = Array.from(hmrPages).flatMap((i) => [
2875
- ctx.server.moduleGraph.getModuleById(`${slidePrefix}${i + 1}.frontmatter`),
2876
- ctx.server.moduleGraph.getModuleById(`${slidePrefix}${i + 1}.md`)
2877
- ]);
2878
- hmrPages.clear();
2879
- const moduleEntries = [
2880
- ...vueModules,
2881
- ...Array.from(moduleIds).map((id) => ctx.server.moduleGraph.getModuleById(id))
2882
- ].filter(notNullish).filter((i) => !i.id?.startsWith("/@id/@vite-icons"));
2883
- updateServerWatcher();
2884
- return moduleEntries;
2885
- },
2886
- resolveId(id) {
2887
- if (id.startsWith(slidePrefix) || id.startsWith("/@slidev/"))
2888
- return id;
2889
- return null;
2890
- },
2891
- load(id) {
2892
- if (id === "/@slidev/routes")
2893
- return generateRoutes();
2894
- if (id === "/@slidev/layouts")
2895
- return generateLayouts();
2896
- if (id === "/@slidev/styles")
2897
- return generateUserStyles();
2898
- if (id === "/@slidev/monaco-types")
2899
- return generateMonacoTypes();
2900
- if (id === "/@slidev/configs")
2901
- return generateConfigs();
2902
- if (id === "/@slidev/global-components/top")
2903
- return generateGlobalComponents("top");
2904
- if (id === "/@slidev/global-components/bottom")
2905
- return generateGlobalComponents("bottom");
2906
- if (id === "/@slidev/custom-nav-controls")
2907
- return generateCustomNavControls();
2908
- if (id === "/@slidev/titles.md") {
2909
- return {
2910
- code: data.slides.map(({ title }, i) => `<template ${i === 0 ? "v-if" : "v-else-if"}="+no === ${i + 1}">
2911
-
2912
- ${title}
2913
-
2914
- </template>`).join(""),
2915
- map: { mappings: "" }
2916
- };
2917
- }
2918
- if (id.startsWith(slidePrefix)) {
2919
- const remaning = id.slice(slidePrefix.length);
2920
- const match = remaning.match(regexIdQuery);
2921
- if (match) {
2922
- const [, no, type] = match;
2923
- const pageNo = Number.parseInt(no) - 1;
2924
- const slide = data.slides[pageNo];
2925
- if (!slide)
2926
- return;
2927
- if (type === "md") {
2928
- return {
2929
- code: slide?.content,
2930
- map: { mappings: "" }
2931
- };
2932
- } else if (type === "frontmatter") {
2933
- const slideBase = {
2934
- ...withRenderedNote(slide),
2935
- frontmatter: void 0,
2936
- source: void 0,
2937
- // remove raw content in build, optimize the bundle size
2938
- ...mode === "build" ? { raw: "", content: "", note: "" } : {}
2939
- };
2940
- const fontmatter = getFrontmatter(pageNo);
2941
- return {
2942
- code: [
2943
- "// @unocss-include",
2944
- 'import { reactive, computed } from "vue"',
2945
- `export const frontmatter = reactive(${JSON.stringify(fontmatter)})`,
2946
- `export const meta = reactive({
2947
- layout: computed(() => frontmatter.layout),
2948
- transition: computed(() => frontmatter.transition),
2949
- class: computed(() => frontmatter.class),
2950
- clicks: computed(() => frontmatter.clicks),
2951
- name: computed(() => frontmatter.name),
2952
- preload: computed(() => frontmatter.preload),
2953
- slide: {
2954
- ...(${JSON.stringify(slideBase)}),
2955
- frontmatter,
2956
- filepath: ${JSON.stringify(slide.source.filepath)},
2957
- start: ${JSON.stringify(slide.source.start)},
2958
- id: ${pageNo},
2959
- no: ${no},
2960
- },
2961
- __clicksContext: null,
2962
- __preloaded: false,
2963
- })`,
2964
- "export default frontmatter",
2965
- // handle HMR, update frontmatter with update
2966
- "if (import.meta.hot) {",
2967
- " import.meta.hot.accept(({ frontmatter: update }) => {",
2968
- " if(!update) return",
2969
- " Object.keys(frontmatter).forEach(key => {",
2970
- " if (!(key in update)) delete frontmatter[key]",
2971
- " })",
2972
- " Object.assign(frontmatter, update)",
2973
- " })",
2974
- "}"
2975
- ].join("\n"),
2976
- map: { mappings: "" }
2977
- };
2978
- }
2979
- }
2980
- return {
2981
- code: "",
2982
- map: { mappings: "" }
2983
- };
2984
- }
2985
- }
2986
- },
2987
- {
2988
- name: "slidev:layout-transform:pre",
2989
- enforce: "pre",
2990
- async transform(code, id) {
2991
- if (!id.startsWith(slidePrefix))
2992
- return;
2993
- const remaning = id.slice(slidePrefix.length);
2994
- const match = remaning.match(regexIdQuery);
2995
- if (!match)
2996
- return;
2997
- const [, no, type] = match;
2998
- if (type !== "md")
2999
- return;
3000
- const pageNo = Number.parseInt(no) - 1;
3001
- return transformMarkdown(code, pageNo);
3002
- }
3003
- },
3004
- {
3005
- name: "slidev:context-transform:pre",
3006
- enforce: "pre",
3007
- async transform(code, id) {
3008
- if (!id.endsWith(".vue") || id.includes("/@slidev/client/") || id.includes("/packages/client/"))
3009
- return;
3010
- return transformVue(code);
3011
- }
3012
- },
3013
- {
3014
- name: "slidev:title-transform:pre",
3015
- enforce: "pre",
3016
- transform(code, id) {
3017
- if (id !== "/@slidev/titles.md")
3018
- return;
3019
- return transformTitles(code);
3020
- }
3021
- },
3022
- {
3023
- name: "slidev:slide-transform:post",
3024
- enforce: "post",
3025
- transform(code, id) {
3026
- if (!id.match(/\/@slidev\/slides\/\d+\.md($|\?)/))
3027
- return;
3028
- const replaced = code.replace("if (_rerender_only)", "if (false)");
3029
- if (replaced !== code)
3030
- return replaced;
3031
- }
3032
- },
3033
- {
3034
- name: "slidev:index-html-transform",
3035
- transformIndexHtml() {
3036
- const { info, author, keywords } = data.headmatter;
3037
- return [
3038
- {
3039
- tag: "title",
3040
- children: getTitle()
3041
- },
3042
- info && {
3043
- tag: "meta",
3044
- attrs: {
3045
- name: "description",
3046
- content: info
3047
- }
3048
- },
3049
- author && {
3050
- tag: "meta",
3051
- attrs: {
3052
- name: "author",
3053
- content: author
3054
- }
3055
- },
3056
- keywords && {
3057
- tag: "meta",
3058
- attrs: {
3059
- name: "keywords",
3060
- content: Array.isArray(keywords) ? keywords.join(", ") : keywords
3061
- }
3062
- }
3063
- ].filter(isTruthy);
3064
- }
3065
- }
3066
- ];
3067
- function updateServerWatcher() {
3068
- if (!server)
3069
- return;
3070
- server.watcher.add(data.watchFiles);
3071
- }
3072
- function getFrontmatter(pageNo) {
3073
- return {
3074
- ...data.headmatter?.defaults || {},
3075
- ...data.slides[pageNo]?.frontmatter || {}
3076
- };
3077
- }
3078
- async function transformMarkdown(code, pageNo) {
3079
- const layouts = await getLayouts();
3080
- const frontmatter = getFrontmatter(pageNo);
3081
- let layoutName = frontmatter?.layout || (pageNo === 0 ? "cover" : "default");
3082
- if (!layouts[layoutName]) {
3083
- console.error(red(`
3084
- Unknown layout "${bold(layoutName)}".${yellow(" Available layouts are:")}`) + Object.keys(layouts).map((i, idx) => (idx % 3 === 0 ? "\n " : "") + gray(i.padEnd(15, " "))).join(" "));
3085
- console.error();
3086
- layoutName = "default";
3087
- }
3088
- delete frontmatter.title;
3089
- const imports = [
3090
- `import InjectedLayout from "${toAtFS(layouts[layoutName])}"`,
3091
- `import frontmatter from "${toAtFS(`${slidePrefix + (pageNo + 1)}.frontmatter`)}"`,
3092
- templateImportContextUtils,
3093
- "_provideFrontmatter(frontmatter)",
3094
- templateInitContext,
3095
- templateInjectionMarker
3096
- ];
3097
- code = code.replace(/(<script setup.*>)/g, `$1
3098
- ${imports.join("\n")}
3099
- `);
3100
- const injectA = code.indexOf("<template>") + "<template>".length;
3101
- const injectB = code.lastIndexOf("</template>");
3102
- let body = code.slice(injectA, injectB).trim();
3103
- if (body.startsWith("<div>") && body.endsWith("</div>"))
3104
- body = body.slice(5, -6);
3105
- code = `${code.slice(0, injectA)}
3106
- <InjectedLayout v-bind="_frontmatterToProps(frontmatter,${pageNo})">
3107
- ${body}
3108
- </InjectedLayout>
3109
- ${code.slice(injectB)}`;
3110
- return code;
3111
- }
3112
- function transformVue(code) {
3113
- if (code.includes(templateInjectionMarker) || code.includes("useSlideContext()"))
3114
- return code;
3115
- const imports = [
3116
- templateImportContextUtils,
3117
- templateInitContext,
3118
- templateInjectionMarker
3119
- ];
3120
- const matchScript = code.match(/<script((?!setup).)*(setup)?.*>/);
3121
- if (matchScript && matchScript[2]) {
3122
- return code.replace(/(<script.*>)/g, `$1
3123
- ${imports.join("\n")}
3124
- `);
3125
- } else if (matchScript && !matchScript[2]) {
3126
- const matchExport = code.match(/export\s+default\s+{/);
3127
- if (matchExport) {
3128
- const exportIndex = (matchExport.index || 0) + matchExport[0].length;
3129
- let component = code.slice(exportIndex);
3130
- component = component.slice(0, component.indexOf("</script>"));
3131
- const scriptIndex = (matchScript.index || 0) + matchScript[0].length;
3132
- const provideImport = '\nimport { injectionSlidevContext } from "@slidev/client/constants.ts"\n';
3133
- code = `${code.slice(0, scriptIndex)}${provideImport}${code.slice(scriptIndex)}`;
3134
- let injectIndex = exportIndex + provideImport.length;
3135
- let injectObject = "$slidev: { from: injectionSlidevContext },";
3136
- const matchInject = component.match(/.*inject\s*:\s*([\[{])/);
3137
- if (matchInject) {
3138
- injectIndex += (matchInject.index || 0) + matchInject[0].length;
3139
- if (matchInject[1] === "[") {
3140
- let injects = component.slice((matchInject.index || 0) + matchInject[0].length);
3141
- const injectEndIndex = injects.indexOf("]");
3142
- injects = injects.slice(0, injectEndIndex);
3143
- injectObject += injects.split(",").map((inject) => `${inject}: {from: ${inject}}`).join(",");
3144
- return `${code.slice(0, injectIndex - 1)}{
3145
- ${injectObject}
3146
- }${code.slice(injectIndex + injectEndIndex + 1)}`;
3147
- } else {
3148
- return `${code.slice(0, injectIndex)}
3149
- ${injectObject}
3150
- ${code.slice(injectIndex)}`;
3151
- }
3152
- }
3153
- return `${code.slice(0, injectIndex)}
3154
- inject: { ${injectObject} },
3155
- ${code.slice(injectIndex)}`;
3156
- }
3157
- }
3158
- return `<script setup>
3159
- ${imports.join("\n")}
3160
- </script>
3161
- ${code}`;
3162
- }
3163
- function transformTitles(code) {
3164
- return code.replace(/<template>\s*<div>\s*<p>/, "<template>").replace(/<\/p>\s*<\/div>\s*<\/template>/, "</template>").replace(/<script\ssetup>/, `<script setup lang="ts">
3165
- defineProps<{ no: number | string }>()`);
3166
- }
3167
- async function getLayouts() {
3168
- const now = Date.now();
3169
- if (now - _layouts_cache_time < 2e3)
3170
- return _layouts_cache;
3171
- const layouts = {};
3172
- for (const root of [...roots, clientRoot]) {
3173
- const layoutPaths = await fg2("layouts/**/*.{vue,ts}", {
3174
- cwd: root,
3175
- absolute: true,
3176
- suppressErrors: true
3177
- });
3178
- for (const layoutPath of layoutPaths) {
3179
- const layout = basename2(layoutPath).replace(/\.\w+$/, "");
3180
- if (layouts[layout])
3181
- continue;
3182
- layouts[layout] = layoutPath;
3183
- }
3184
- }
3185
- _layouts_cache_time = now;
3186
- _layouts_cache = layouts;
3187
- return layouts;
3188
- }
3189
- async function resolveUrl(id) {
3190
- return toAtFS(await resolveImportPath(id, true));
2928
+ function math_inline(state, silent) {
2929
+ let match, token, res, pos;
2930
+ if (state.src[state.pos] !== "$")
2931
+ return false;
2932
+ res = isValidDelim(state, state.pos);
2933
+ if (!res.can_open) {
2934
+ if (!silent)
2935
+ state.pending += "$";
2936
+ state.pos += 1;
2937
+ return true;
3191
2938
  }
3192
- function resolveUrlOfClient(name) {
3193
- return toAtFS(join4(clientRoot, name));
2939
+ const start = state.pos + 1;
2940
+ match = start;
2941
+ while ((match = state.src.indexOf("$", match)) !== -1) {
2942
+ pos = match - 1;
2943
+ while (state.src[pos] === "\\")
2944
+ pos -= 1;
2945
+ if ((match - pos) % 2 === 1)
2946
+ break;
2947
+ match += 1;
3194
2948
  }
3195
- async function generateUserStyles() {
3196
- const imports = [
3197
- `import "${resolveUrlOfClient("styles/vars.css")}"`,
3198
- `import "${resolveUrlOfClient("styles/index.css")}"`,
3199
- `import "${resolveUrlOfClient("styles/code.css")}"`,
3200
- `import "${resolveUrlOfClient("styles/katex.css")}"`,
3201
- `import "${resolveUrlOfClient("styles/transitions.css")}"`
3202
- ];
3203
- for (const root of roots) {
3204
- const styles = [
3205
- join4(root, "styles", "index.ts"),
3206
- join4(root, "styles", "index.js"),
3207
- join4(root, "styles", "index.css"),
3208
- join4(root, "styles.css"),
3209
- join4(root, "style.css")
3210
- ];
3211
- for (const style of styles) {
3212
- if (fs3.existsSync(style)) {
3213
- imports.push(`import "${toAtFS(style)}"`);
3214
- continue;
3215
- }
3216
- }
3217
- }
3218
- if (data.features.katex)
3219
- imports.push(`import "${await resolveUrl("katex/dist/katex.min.css")}"`);
3220
- if (data.config.highlighter === "shiki") {
3221
- imports.push(
3222
- `import "${await resolveUrl("@shikijs/vitepress-twoslash/style.css")}"`,
3223
- `import "${resolveUrlOfClient("styles/shiki-twoslash.css")}"`
3224
- );
3225
- }
3226
- if (data.config.css === "unocss") {
3227
- imports.unshift(
3228
- `import "${await resolveUrl("@unocss/reset/tailwind.css")}"`,
3229
- 'import "uno:preflights.css"',
3230
- 'import "uno:typography.css"',
3231
- 'import "uno:shortcuts.css"'
3232
- );
3233
- imports.push('import "uno.css"');
3234
- }
3235
- return imports.join("\n");
2949
+ if (match === -1) {
2950
+ if (!silent)
2951
+ state.pending += "$";
2952
+ state.pos = start;
2953
+ return true;
3236
2954
  }
3237
- async function generateMonacoTypes() {
3238
- return `void 0; ${parser.scanMonacoModules(data.slides.map((s) => s.source.raw).join()).map((i) => `import('/@slidev-monaco-types/${i}')`).join("\n")}`;
2955
+ if (match - start === 0) {
2956
+ if (!silent)
2957
+ state.pending += "$$";
2958
+ state.pos = start + 1;
2959
+ return true;
3239
2960
  }
3240
- async function generateLayouts() {
3241
- const imports = [];
3242
- const layouts = objectMap(
3243
- await getLayouts(),
3244
- (k, v) => {
3245
- imports.push(`import __layout_${k} from "${toAtFS(v)}"`);
3246
- return [k, `__layout_${k}`];
3247
- }
3248
- );
3249
- return [
3250
- imports.join("\n"),
3251
- `export default {
3252
- ${Object.entries(layouts).map(([k, v]) => `"${k}": ${v}`).join(",\n")}
3253
- }`
3254
- ].join("\n\n");
2961
+ res = isValidDelim(state, match);
2962
+ if (!res.can_close) {
2963
+ if (!silent)
2964
+ state.pending += "$";
2965
+ state.pos = start;
2966
+ return true;
3255
2967
  }
3256
- async function generateRoutes() {
3257
- const imports = [];
3258
- const redirects = [];
3259
- const layouts = await getLayouts();
3260
- imports.push(
3261
- `import { markRaw } from 'vue'`,
3262
- `import __layout__end from '${layouts.end}'`
3263
- );
3264
- let no = 1;
3265
- const routes = data.slides.map((i, idx) => {
3266
- imports.push(`import n${no} from '${slidePrefix}${idx + 1}.md'`);
3267
- imports.push(`import { meta as f${no} } from '${slidePrefix}${idx + 1}.frontmatter'`);
3268
- const route = `{ path: '${no}', name: 'page-${no}', component: n${no}, meta: f${no} }`;
3269
- if (i.frontmatter?.routeAlias)
3270
- redirects.push(`{ path: '${i.frontmatter?.routeAlias}', redirect: { path: '${no}' } }`);
3271
- no += 1;
3272
- return route;
3273
- });
3274
- const routesStr = `export const rawRoutes = [
3275
- ${routes.join(",\n")}
3276
- ].map(markRaw)`;
3277
- const redirectsStr = `export const redirects = [
3278
- ${redirects.join(",\n")}
3279
- ].map(markRaw)`;
3280
- return [...imports, routesStr, redirectsStr].join("\n");
2968
+ if (!silent) {
2969
+ token = state.push("math_inline", "math", 0);
2970
+ token.markup = "$";
2971
+ token.content = state.src.slice(start, match);
3281
2972
  }
3282
- function getTitle() {
3283
- if (isString(data.config.title)) {
3284
- const tokens = md.parseInline(data.config.title, {});
3285
- return stringifyMarkdownTokens(tokens);
2973
+ state.pos = match + 1;
2974
+ return true;
2975
+ }
2976
+ function math_block(state, start, end, silent) {
2977
+ let firstLine;
2978
+ let lastLine;
2979
+ let next;
2980
+ let lastPos;
2981
+ let found = false;
2982
+ let pos = state.bMarks[start] + state.tShift[start];
2983
+ let max = state.eMarks[start];
2984
+ if (pos + 2 > max)
2985
+ return false;
2986
+ if (state.src.slice(pos, pos + 2) !== "$$")
2987
+ return false;
2988
+ pos += 2;
2989
+ firstLine = state.src.slice(pos, max);
2990
+ if (silent)
2991
+ return true;
2992
+ if (firstLine.trim().slice(-2) === "$$") {
2993
+ firstLine = firstLine.trim().slice(0, -2);
2994
+ found = true;
2995
+ }
2996
+ for (next = start; !found; ) {
2997
+ next++;
2998
+ if (next >= end)
2999
+ break;
3000
+ pos = state.bMarks[next] + state.tShift[next];
3001
+ max = state.eMarks[next];
3002
+ if (pos < max && state.tShift[next] < state.blkIndent) {
3003
+ break;
3004
+ }
3005
+ if (state.src.slice(pos, max).trim().slice(-2) === "$$") {
3006
+ lastPos = state.src.slice(0, max).lastIndexOf("$$");
3007
+ lastLine = state.src.slice(pos, lastPos);
3008
+ found = true;
3286
3009
  }
3287
- return data.config.title;
3288
3010
  }
3289
- function generateConfigs() {
3290
- const config = {
3291
- ...data.config,
3292
- remote,
3293
- title: getTitle()
3294
- };
3295
- if (isString(config.info))
3296
- config.info = md.render(config.info);
3297
- return `export default ${JSON.stringify(config)}`;
3011
+ state.line = next + 1;
3012
+ const token = state.push("math_block", "math", 0);
3013
+ token.block = true;
3014
+ token.content = (firstLine && firstLine.trim() ? `${firstLine}
3015
+ ` : "") + state.getLines(start + 1, next, state.tShift[start], true) + (lastLine && lastLine.trim() ? lastLine : "");
3016
+ token.map = [start, state.line];
3017
+ token.markup = "$$";
3018
+ return true;
3019
+ }
3020
+ function math_plugin(md2, options) {
3021
+ options = options || {};
3022
+ const katexInline = function(latex) {
3023
+ options.displayMode = false;
3024
+ try {
3025
+ return katex.renderToString(latex, options);
3026
+ } catch (error) {
3027
+ if (options.throwOnError)
3028
+ console.warn(error);
3029
+ return latex;
3030
+ }
3031
+ };
3032
+ const inlineRenderer = function(tokens, idx) {
3033
+ return katexInline(tokens[idx].content);
3034
+ };
3035
+ const katexBlock = function(latex) {
3036
+ options.displayMode = true;
3037
+ try {
3038
+ return `<p>${katex.renderToString(latex, options)}</p>`;
3039
+ } catch (error) {
3040
+ if (options.throwOnError)
3041
+ console.warn(error);
3042
+ return latex;
3043
+ }
3044
+ };
3045
+ const blockRenderer = function(tokens, idx) {
3046
+ return `${katexBlock(tokens[idx].content)}
3047
+ `;
3048
+ };
3049
+ md2.inline.ruler.after("escape", "math_inline", math_inline);
3050
+ md2.block.ruler.after("blockquote", "math_block", math_block, {
3051
+ alt: ["paragraph", "reference", "blockquote", "list"]
3052
+ });
3053
+ md2.renderer.rules.math_inline = inlineRenderer;
3054
+ md2.renderer.rules.math_block = blockRenderer;
3055
+ }
3056
+
3057
+ // node/plugins/markdown-it-prism.ts
3058
+ import { createRequire } from "node:module";
3059
+ import Prism from "prismjs";
3060
+ import loadLanguages from "prismjs/components/index.js";
3061
+ import * as htmlparser2 from "htmlparser2";
3062
+ var require2 = createRequire(import.meta.url);
3063
+ var Tag = class {
3064
+ tagname;
3065
+ attributes;
3066
+ constructor(tagname, attributes) {
3067
+ this.tagname = tagname;
3068
+ this.attributes = attributes;
3298
3069
  }
3299
- async function generateGlobalComponents(layer) {
3300
- const components = roots.flatMap((root) => {
3301
- if (layer === "top") {
3302
- return [
3303
- join4(root, "global.vue"),
3304
- join4(root, "global-top.vue"),
3305
- join4(root, "GlobalTop.vue")
3306
- ];
3307
- } else {
3308
- return [
3309
- join4(root, "global-bottom.vue"),
3310
- join4(root, "GlobalBottom.vue")
3311
- ];
3312
- }
3313
- }).filter((i) => fs3.existsSync(i));
3314
- const imports = components.map((i, idx) => `import __n${idx} from '${toAtFS(i)}'`).join("\n");
3315
- const render = components.map((i, idx) => `h(__n${idx})`).join(",");
3316
- return `
3317
- ${imports}
3318
- import { h } from 'vue'
3319
- export default {
3320
- render() {
3321
- return [${render}]
3070
+ asOpen() {
3071
+ return `<${this.tagname} ${Object.entries(this.attributes).map(([key, value]) => `${key}="${value}"`).join(" ")}>`;
3322
3072
  }
3073
+ asClosed() {
3074
+ return `</${this.tagname}>`;
3075
+ }
3076
+ };
3077
+ var DEFAULTS = {
3078
+ plugins: [],
3079
+ init: () => {
3080
+ },
3081
+ defaultLanguageForUnknown: void 0,
3082
+ defaultLanguageForUnspecified: void 0,
3083
+ defaultLanguage: void 0
3084
+ };
3085
+ function loadPrismLang(lang) {
3086
+ if (!lang)
3087
+ return void 0;
3088
+ let langObject = Prism.languages[lang];
3089
+ if (langObject === void 0) {
3090
+ loadLanguages([lang]);
3091
+ langObject = Prism.languages[lang];
3092
+ }
3093
+ return langObject;
3323
3094
  }
3324
- `;
3095
+ function loadPrismPlugin(name) {
3096
+ try {
3097
+ require2(`prismjs/plugins/${name}/prism-${name}`);
3098
+ } catch (e) {
3099
+ throw new Error(`Cannot load Prism plugin "${name}". Please check the spelling.`);
3325
3100
  }
3326
- async function generateCustomNavControls() {
3327
- const components = roots.flatMap((root) => {
3328
- return [
3329
- join4(root, "custom-nav-controls.vue"),
3330
- join4(root, "CustomNavControls.vue")
3331
- ];
3332
- }).filter((i) => fs3.existsSync(i));
3333
- const imports = components.map((i, idx) => `import __n${idx} from '${toAtFS(i)}'`).join("\n");
3334
- const render = components.map((i, idx) => `h(__n${idx})`).join(",");
3335
- return `
3336
- ${imports}
3337
- import { h } from 'vue'
3338
- export default {
3339
- render() {
3340
- return [${render}]
3101
+ }
3102
+ function selectLanguage(options, lang) {
3103
+ let langToUse = lang;
3104
+ if (langToUse === "" && options.defaultLanguageForUnspecified !== void 0)
3105
+ langToUse = options.defaultLanguageForUnspecified;
3106
+ let prismLang = loadPrismLang(langToUse);
3107
+ if (prismLang === void 0 && options.defaultLanguageForUnknown !== void 0) {
3108
+ langToUse = options.defaultLanguageForUnknown;
3109
+ prismLang = loadPrismLang(langToUse);
3341
3110
  }
3111
+ return [langToUse, prismLang];
3112
+ }
3113
+ function highlight(markdownit, options, text, lang) {
3114
+ const [langToUse, prismLang] = selectLanguage(options, lang);
3115
+ let code = text.trimEnd();
3116
+ code = prismLang ? highlightPrism(code, prismLang, langToUse) : markdownit.utils.escapeHtml(code);
3117
+ code = code.split(/\r?\n/g).map((line) => `<span class="line">${line}</span>`).join("\n");
3118
+ const classAttribute = langToUse ? ` class="slidev-code ${markdownit.options.langPrefix}${markdownit.utils.escapeHtml(langToUse)}"` : "";
3119
+ return escapeVueInCode(`<pre${classAttribute}><code>${code}</code></pre>`);
3120
+ }
3121
+ function highlightPrism(code, prismLang, langToUse) {
3122
+ const openTags = [];
3123
+ const parser2 = new htmlparser2.Parser({
3124
+ onopentag(tagname, attributes) {
3125
+ openTags.push(new Tag(tagname, attributes));
3126
+ },
3127
+ onclosetag() {
3128
+ openTags.pop();
3129
+ }
3130
+ });
3131
+ code = Prism.highlight(code, prismLang, langToUse);
3132
+ code = code.split(/\r?\n/g).map((line) => {
3133
+ const prefix = openTags.map((tag) => tag.asOpen()).join("");
3134
+ parser2.write(line);
3135
+ const postfix = openTags.reverse().map((tag) => tag.asClosed()).join("");
3136
+ return prefix + line + postfix;
3137
+ }).join("\n");
3138
+ parser2.end();
3139
+ return code;
3342
3140
  }
3343
- `;
3344
- }
3141
+ function checkLanguageOption(options, optionName) {
3142
+ const language = options[optionName];
3143
+ if (language !== void 0 && loadPrismLang(language) === void 0)
3144
+ throw new Error(`Bad option ${optionName}: There is no Prism language '${language}'.`);
3145
+ }
3146
+ function markdownItPrism(markdownit, useroptions) {
3147
+ const options = Object.assign({}, DEFAULTS, useroptions);
3148
+ checkLanguageOption(options, "defaultLanguage");
3149
+ checkLanguageOption(options, "defaultLanguageForUnknown");
3150
+ checkLanguageOption(options, "defaultLanguageForUnspecified");
3151
+ options.defaultLanguageForUnknown = options.defaultLanguageForUnknown || options.defaultLanguage;
3152
+ options.defaultLanguageForUnspecified = options.defaultLanguageForUnspecified || options.defaultLanguage;
3153
+ options.plugins.forEach(loadPrismPlugin);
3154
+ options.init(Prism);
3155
+ markdownit.options.highlight = (text, lang) => highlight(markdownit, options, text, lang);
3345
3156
  }
3346
3157
 
3347
- // node/plugins/monacoTransform.ts
3348
- import { dirname as dirname2, join as join5 } from "node:path";
3349
- import fs4 from "node:fs/promises";
3350
- import process2 from "node:process";
3351
- import { slash } from "@antfu/utils";
3352
- import { findDepPkgJsonPath } from "vitefu";
3353
- async function getPackageData(pkg) {
3354
- const pkgJsonPath = await findDepPkgJsonPath(pkg, process2.cwd());
3355
- if (!pkgJsonPath)
3356
- return;
3357
- const pkgJson = JSON.parse(await fs4.readFile(pkgJsonPath, "utf-8"));
3358
- const typePath = pkgJson.types || pkgJson.typings;
3359
- if (!typePath)
3360
- return;
3361
- return [dirname2(pkgJsonPath), pkgJson, typePath];
3158
+ // node/plugins/transformSnippet.ts
3159
+ import path from "node:path";
3160
+ import fs3 from "fs-extra";
3161
+ function dedent(text) {
3162
+ const lines = text.split("\n");
3163
+ const minIndentLength = lines.reduce((acc, line) => {
3164
+ for (let i = 0; i < line.length; i++) {
3165
+ if (line[i] !== " " && line[i] !== " ")
3166
+ return Math.min(i, acc);
3167
+ }
3168
+ return acc;
3169
+ }, Number.POSITIVE_INFINITY);
3170
+ if (minIndentLength < Number.POSITIVE_INFINITY)
3171
+ return lines.map((x) => x.slice(minIndentLength)).join("\n");
3172
+ return text;
3362
3173
  }
3363
- function createMonacoTypesLoader() {
3364
- return {
3365
- name: "slidev:monaco-types-loader",
3366
- resolveId(id) {
3367
- if (id.startsWith("/@slidev-monaco-types/"))
3368
- return id;
3369
- return null;
3370
- },
3371
- async load(id) {
3372
- const match = id.match(/^\/\@slidev-monaco-types\/(.*)$/);
3373
- if (match) {
3374
- const pkg = match[1];
3375
- const packageData = await getPackageData(pkg) || await getPackageData(`@types/${pkg}`);
3376
- if (!packageData)
3377
- return;
3378
- const [pkgDir, pkgJson, typePath] = packageData;
3379
- return [
3380
- "import * as monaco from 'monaco-editor'",
3381
- `import Type from "${slash(join5(pkgDir, typePath))}?raw"`,
3382
- ...Object.keys(pkgJson.dependencies || {}).map((i) => `import "/@slidev-monaco-types/${i}"`),
3383
- `monaco.languages.typescript.typescriptDefaults.addExtraLib(\`declare module "${pkg}" { \${Type} }\`)`
3384
- ].join("\n");
3174
+ function testLine(line, regexp, regionName, end = false) {
3175
+ const [full, tag, name] = regexp.exec(line.trim()) || [];
3176
+ return full && tag && name === regionName && tag.match(end ? /^[Ee]nd ?[rR]egion$/ : /^[rR]egion$/);
3177
+ }
3178
+ function findRegion(lines, regionName) {
3179
+ const regionRegexps = [
3180
+ /^\/\/ ?#?((?:end)?region) ([\w*-]+)$/,
3181
+ // javascript, typescript, java
3182
+ /^\/\* ?#((?:end)?region) ([\w*-]+) ?\*\/$/,
3183
+ // css, less, scss
3184
+ /^#pragma ((?:end)?region) ([\w*-]+)$/,
3185
+ // C, C++
3186
+ /^<!-- #?((?:end)?region) ([\w*-]+) -->$/,
3187
+ // HTML, markdown
3188
+ /^#((?:End )Region) ([\w*-]+)$/,
3189
+ // Visual Basic
3190
+ /^::#((?:end)region) ([\w*-]+)$/,
3191
+ // Bat
3192
+ /^# ?((?:end)?region) ([\w*-]+)$/
3193
+ // C#, PHP, Powershell, Python, perl & misc
3194
+ ];
3195
+ let regexp = null;
3196
+ let start = -1;
3197
+ for (const [lineId, line] of lines.entries()) {
3198
+ if (regexp === null) {
3199
+ for (const reg of regionRegexps) {
3200
+ if (testLine(line, reg, regionName)) {
3201
+ start = lineId + 1;
3202
+ regexp = reg;
3203
+ break;
3204
+ }
3385
3205
  }
3206
+ } else if (testLine(line, regexp, regionName, true)) {
3207
+ return { start, end: lineId, regexp };
3386
3208
  }
3387
- };
3209
+ }
3210
+ return null;
3211
+ }
3212
+ function transformSnippet(md2, options, id) {
3213
+ const slideId = id.match(/(\d+)\.md$/)?.[1];
3214
+ if (!slideId)
3215
+ return md2;
3216
+ const data = options.data;
3217
+ const slideInfo = data.slides[+slideId - 1];
3218
+ const dir = path.dirname(slideInfo.source?.filepath ?? options.entry ?? options.userRoot);
3219
+ return md2.replace(
3220
+ /^<<< *(.+?)(#[\w-]+)? *(?: (\S+?))? *(\{.*)?$/mg,
3221
+ (full, filepath = "", regionName = "", lang = "", meta = "") => {
3222
+ const firstLine = `\`\`\`${lang || path.extname(filepath).slice(1)} ${meta}`;
3223
+ const src = /^\@[\/]/.test(filepath) ? path.resolve(options.userRoot, filepath.slice(2)) : path.resolve(dir, filepath);
3224
+ data.watchFiles.push(src);
3225
+ const isAFile = fs3.statSync(src).isFile();
3226
+ if (!fs3.existsSync(src) || !isAFile) {
3227
+ throw new Error(isAFile ? `Code snippet path not found: ${src}` : `Invalid code snippet option`);
3228
+ }
3229
+ let content = fs3.readFileSync(src, "utf8");
3230
+ slideInfo.snippetsUsed ??= {};
3231
+ slideInfo.snippetsUsed[src] = content;
3232
+ if (regionName) {
3233
+ const lines = content.split(/\r?\n/);
3234
+ const region = findRegion(lines, regionName.slice(1));
3235
+ if (region) {
3236
+ content = dedent(
3237
+ lines.slice(region.start, region.end).filter((line) => !region.regexp.test(line.trim())).join("\n")
3238
+ );
3239
+ }
3240
+ }
3241
+ return `${firstLine}
3242
+ ${content}
3243
+ \`\`\``;
3244
+ }
3245
+ );
3388
3246
  }
3389
3247
 
3390
- // node/plugins/setupClient.ts
3391
- import { existsSync as existsSync2 } from "node:fs";
3392
- import { join as join6, resolve as resolve2 } from "node:path";
3393
- import { slash as slash2, uniq as uniq2 } from "@antfu/utils";
3394
- function createClientSetupPlugin({ themeRoots, addonRoots, userRoot, clientRoot }) {
3395
- const setupEntry = slash2(resolve2(clientRoot, "setup"));
3396
- return {
3397
- name: "slidev:setup",
3398
- enforce: "pre",
3399
- async transform(code, id) {
3400
- if (id.startsWith(setupEntry)) {
3401
- let getInjections2 = function(isAwait = false, isChained = false) {
3402
- return injections.join("\n").replace(/:AWAIT:/g, isAwait ? "await " : "").replace(/(,\s*)?:LAST:/g, isChained ? "$1injection_return" : "");
3403
- };
3404
- var getInjections = getInjections2;
3405
- const name = id.slice(setupEntry.length + 1).replace(/\?.*$/, "");
3406
- const imports = [];
3407
- const injections = [];
3408
- const setups = uniq2([
3409
- ...themeRoots,
3410
- ...addonRoots,
3411
- userRoot
3412
- ]).map((i) => join6(i, "setup", name));
3413
- setups.forEach((path2, idx) => {
3414
- if (!existsSync2(path2))
3415
- return;
3416
- imports.push(`import __n${idx} from '${toAtFS(path2)}'`);
3417
- let fn = `:AWAIT:__n${idx}`;
3418
- if (/\binjection_return\b/g.test(code))
3419
- fn = `injection_return = ${fn}`;
3420
- if (/\binjection_arg\b/g.test(code)) {
3421
- fn += "(";
3422
- const matches = Array.from(code.matchAll(/\binjection_arg(_\d+)?\b/g));
3423
- const dedupedMatches = Array.from(new Set(matches.map((m) => m[0])));
3424
- fn += dedupedMatches.join(", ");
3425
- fn += ", :LAST:)";
3426
- } else {
3427
- fn += "(:LAST:)";
3248
+ // node/plugins/markdown.ts
3249
+ var shiki;
3250
+ var shikiOptions;
3251
+ async function createMarkdownPlugin(options, { markdown: mdOptions }) {
3252
+ const { data: { config }, roots, mode, entry, clientRoot } = options;
3253
+ const setups = [];
3254
+ const entryPath = slash(entry);
3255
+ if (config.highlighter === "shiki") {
3256
+ const [
3257
+ options2,
3258
+ { getHighlighter, bundledLanguages },
3259
+ markdownItShiki,
3260
+ transformerTwoslash
3261
+ ] = await Promise.all([
3262
+ loadShikiSetups(clientRoot, roots),
3263
+ import("shiki").then(({ getHighlighter: getHighlighter2, bundledLanguages: bundledLanguages2 }) => ({ bundledLanguages: bundledLanguages2, getHighlighter: getHighlighter2 })),
3264
+ import("@shikijs/markdown-it/core").then(({ fromHighlighter }) => fromHighlighter),
3265
+ import("@shikijs/vitepress-twoslash").then(({ transformerTwoslash: transformerTwoslash2 }) => transformerTwoslash2)
3266
+ ]);
3267
+ shikiOptions = options2;
3268
+ shiki = await getHighlighter({
3269
+ ...options2,
3270
+ langs: options2.langs ?? Object.keys(bundledLanguages),
3271
+ themes: "themes" in options2 ? Object.values(options2.themes) : [options2.theme]
3272
+ });
3273
+ const transformers = [
3274
+ ...options2.transformers || [],
3275
+ transformerTwoslash({
3276
+ explicitTrigger: true,
3277
+ twoslashOptions: {
3278
+ handbookOptions: {
3279
+ noErrorValidation: true
3428
3280
  }
3429
- injections.push(
3430
- `// ${path2}`,
3431
- fn
3432
- );
3433
- });
3434
- code = code.replace("/* __imports__ */", imports.join("\n"));
3435
- code = code.replace("/* __injections__ */", getInjections2());
3436
- code = code.replace("/* __async_injections__ */", getInjections2(true));
3437
- code = code.replace("/* __chained_injections__ */", getInjections2(false, true));
3438
- code = code.replace("/* __chained_async_injections__ */", getInjections2(true, true));
3281
+ }
3282
+ }),
3283
+ {
3284
+ pre(pre) {
3285
+ this.addClassToHast(pre, "slidev-code");
3286
+ delete pre.properties.tabindex;
3287
+ },
3288
+ postprocess(code) {
3289
+ return escapeVueInCode(code);
3290
+ }
3291
+ }
3292
+ ];
3293
+ const plugin = markdownItShiki(shiki, {
3294
+ ...options2,
3295
+ transformers
3296
+ });
3297
+ setups.push((md2) => md2.use(plugin));
3298
+ } else {
3299
+ setups.push((md2) => md2.use(markdownItPrism));
3300
+ }
3301
+ if (config.mdc)
3302
+ setups.push((md2) => md2.use(Mdc));
3303
+ const KatexOptions = await loadSetups(options.clientRoot, roots, "katex.ts", {}, { strict: false }, false);
3304
+ return Markdown({
3305
+ include: [/\.md$/],
3306
+ wrapperClasses: "",
3307
+ headEnabled: false,
3308
+ frontmatter: false,
3309
+ escapeCodeTagInterpolation: false,
3310
+ markdownItOptions: {
3311
+ quotes: `""''`,
3312
+ html: true,
3313
+ xhtmlOut: true,
3314
+ linkify: true,
3315
+ ...mdOptions?.markdownItOptions
3316
+ },
3317
+ ...mdOptions,
3318
+ markdownItSetup(md2) {
3319
+ md2.use(mila, {
3320
+ attrs: {
3321
+ target: "_blank",
3322
+ rel: "noopener"
3323
+ }
3324
+ });
3325
+ md2.use(mif);
3326
+ md2.use(taskLists, { enabled: true, lineNumber: true, label: true });
3327
+ md2.use(math_plugin, KatexOptions);
3328
+ setups.forEach((i) => i(md2));
3329
+ mdOptions?.markdownItSetup?.(md2);
3330
+ },
3331
+ transforms: {
3332
+ before(code, id) {
3333
+ if (id === entryPath)
3334
+ return "";
3335
+ const monaco = config.monaco === true || config.monaco === mode ? transformMarkdownMonaco : truncateMancoMark;
3336
+ if (config.highlighter === "shiki")
3337
+ code = transformMagicMove(code, shiki, shikiOptions);
3338
+ code = transformSlotSugar(code);
3339
+ code = transformSnippet(code, options, id);
3340
+ code = transformMermaid(code);
3341
+ code = transformPlantUml(code, config.plantUmlServer);
3342
+ code = monaco(code);
3343
+ code = transformHighlighter(code);
3344
+ code = transformPageCSS(code, id);
3345
+ code = transformKaTex(code);
3439
3346
  return code;
3440
3347
  }
3441
- return null;
3442
3348
  }
3443
- };
3349
+ });
3444
3350
  }
3351
+ function transformKaTex(md2) {
3352
+ return md2.replace(
3353
+ /^\$\$(?:\s*{([\d\w*,\|-]+)}\s*?({.*?})?\s*?)?\n([\s\S]+?)^\$\$/mg,
3354
+ (full, rangeStr = "", options = "", code) => {
3355
+ const ranges = rangeStr.split(/\|/g).map((i) => i.trim());
3356
+ code = code.trimEnd();
3357
+ options = options.trim() || "{}";
3358
+ return `<KaTexBlockWrapper v-bind="${options}" :ranges='${JSON.stringify(ranges)}'>
3445
3359
 
3446
- // node/plugins/markdown.ts
3447
- import fs6 from "node:fs/promises";
3448
- import Markdown2 from "unplugin-vue-markdown/vite";
3449
- import { slash as slash3 } from "@antfu/utils";
3450
-
3451
- // ../../node_modules/.pnpm/@hedgedoc+markdown-it-plugins@2.1.4_patch_hash=tuyuxytl56b2vxulpkzt2wf4o4_markdown-it@14.0.0/node_modules/@hedgedoc/markdown-it-plugins/dist/esm/image-size/specialCharacters.js
3452
- var SpecialCharacters;
3453
- (function(SpecialCharacters2) {
3454
- SpecialCharacters2[SpecialCharacters2["EXCLAMATION_MARK"] = 33] = "EXCLAMATION_MARK";
3455
- SpecialCharacters2[SpecialCharacters2["OPENING_BRACKET"] = 91] = "OPENING_BRACKET";
3456
- SpecialCharacters2[SpecialCharacters2["OPENING_PARENTHESIS"] = 40] = "OPENING_PARENTHESIS";
3457
- SpecialCharacters2[SpecialCharacters2["WHITESPACE"] = 32] = "WHITESPACE";
3458
- SpecialCharacters2[SpecialCharacters2["NEW_LINE"] = 10] = "NEW_LINE";
3459
- SpecialCharacters2[SpecialCharacters2["EQUALS"] = 61] = "EQUALS";
3460
- SpecialCharacters2[SpecialCharacters2["LOWER_CASE_X"] = 120] = "LOWER_CASE_X";
3461
- SpecialCharacters2[SpecialCharacters2["NUMBER_ZERO"] = 48] = "NUMBER_ZERO";
3462
- SpecialCharacters2[SpecialCharacters2["NUMBER_NINE"] = 57] = "NUMBER_NINE";
3463
- SpecialCharacters2[SpecialCharacters2["PERCENTAGE"] = 37] = "PERCENTAGE";
3464
- SpecialCharacters2[SpecialCharacters2["CLOSING_PARENTHESIS"] = 41] = "CLOSING_PARENTHESIS";
3465
- })(SpecialCharacters || (SpecialCharacters = {}));
3466
-
3467
- // ../../node_modules/.pnpm/@hedgedoc+markdown-it-plugins@2.1.4_patch_hash=tuyuxytl56b2vxulpkzt2wf4o4_markdown-it@14.0.0/node_modules/@hedgedoc/markdown-it-plugins/dist/esm/task-lists/index.js
3468
- import Token from "markdown-it/lib/token.mjs";
3469
- var checkboxRegex = /^ *\[([\sx])] /i;
3470
- function taskLists(md2, options = { enabled: false, label: false, lineNumber: false }) {
3471
- md2.core.ruler.after("inline", "task-lists", (state) => processToken(state, options));
3472
- md2.renderer.rules.taskListItemCheckbox = (tokens) => {
3473
- const token = tokens[0];
3474
- const checkedAttribute = token.attrGet("checked") ? 'checked="" ' : "";
3475
- const disabledAttribute = token.attrGet("disabled") ? 'disabled="" ' : "";
3476
- const line = token.attrGet("line");
3477
- const idAttribute = `id="${token.attrGet("id")}" `;
3478
- const dataLineAttribute = line && options.lineNumber ? `data-line="${line}" ` : "";
3479
- return `<input class="task-list-item-checkbox" type="checkbox" ${checkedAttribute}${disabledAttribute}${dataLineAttribute}${idAttribute}/>`;
3480
- };
3481
- md2.renderer.rules.taskListItemLabel_close = () => {
3482
- return "</label>";
3483
- };
3484
- md2.renderer.rules.taskListItemLabel_open = (tokens) => {
3485
- const token = tokens[0];
3486
- const id = token.attrGet("id");
3487
- return `<label for="${id}">`;
3488
- };
3360
+ $$
3361
+ ${code}
3362
+ $$
3363
+ </KaTexBlockWrapper>
3364
+ `;
3365
+ }
3366
+ );
3489
3367
  }
3490
- function processToken(state, options) {
3491
- const allTokens = state.tokens;
3492
- for (let i = 2; i < allTokens.length; i++) {
3493
- if (!isTodoItem(allTokens, i)) {
3494
- continue;
3368
+ function transformMarkdownMonaco(md2) {
3369
+ md2 = md2.replace(
3370
+ /^```(\w+?)\s*{monaco-diff}\s*?({.*?})?\s*?\n([\s\S]+?)^~~~\s*?\n([\s\S]+?)^```/mg,
3371
+ (full, lang = "ts", options = "{}", code, diff) => {
3372
+ lang = lang.trim();
3373
+ options = options.trim() || "{}";
3374
+ const encoded = lz.compressToBase64(code);
3375
+ const encodedDiff = lz.compressToBase64(diff);
3376
+ return `<Monaco code-lz="${encoded}" diff-lz="${encodedDiff}" lang="${lang}" v-bind="${options}" />`;
3495
3377
  }
3496
- todoify(allTokens[i], options);
3497
- allTokens[i - 2].attrJoin("class", `task-list-item ${options.enabled ? " enabled" : ""}`);
3498
- const parentToken = findParentToken(allTokens, i - 2);
3499
- if (parentToken) {
3500
- const classes = parentToken.attrGet("class") ?? "";
3501
- if (!classes.match(/(^| )contains-task-list/)) {
3502
- parentToken.attrJoin("class", "contains-task-list");
3503
- }
3378
+ );
3379
+ md2 = md2.replace(
3380
+ /^```(\w+?)\s*{monaco}\s*?({.*?})?\s*?\n([\s\S]+?)^```/mg,
3381
+ (full, lang = "ts", options = "{}", code) => {
3382
+ lang = lang.trim();
3383
+ options = options.trim() || "{}";
3384
+ const encoded = lz.compressToBase64(code);
3385
+ return `<Monaco code-lz="${encoded}" lang="${lang}" v-bind="${options}" />`;
3504
3386
  }
3505
- }
3506
- return false;
3387
+ );
3388
+ return md2;
3507
3389
  }
3508
- function findParentToken(tokens, index) {
3509
- const targetLevel = tokens[index].level - 1;
3510
- for (let currentTokenIndex = index - 1; currentTokenIndex >= 0; currentTokenIndex--) {
3511
- if (tokens[currentTokenIndex].level === targetLevel) {
3512
- return tokens[currentTokenIndex];
3390
+ function scanMonacoModules(md2) {
3391
+ const typeModules = /* @__PURE__ */ new Set();
3392
+ md2.replace(
3393
+ /^```(\w+?)\s*{monaco([\w:,-]*)}[\s\n]*([\s\S]+?)^```/mg,
3394
+ (full, lang = "ts", options, code) => {
3395
+ options = options || "";
3396
+ lang = lang.trim();
3397
+ if (lang === "ts" || lang === "typescript") {
3398
+ Array.from(code.matchAll(/\s+from\s+(["'])([\/\w@-]+)\1/g)).map((i) => i[2]).filter(isTruthy).map((i) => typeModules.add(i));
3399
+ }
3400
+ return "";
3513
3401
  }
3514
- }
3515
- return void 0;
3516
- }
3517
- function isTodoItem(tokens, index) {
3518
- return isInline(tokens[index]) && isParagraph(tokens[index - 1]) && isListItem(tokens[index - 2]) && startsWithTodoMarkdown(tokens[index]);
3519
- }
3520
- function todoify(token, options) {
3521
- if (token.children == null) {
3522
- return;
3523
- }
3524
- const id = generateIdForToken(token);
3525
- token.children.splice(0, 0, createCheckboxToken(token, options.enabled, id));
3526
- token.children[1].content = token.children[1].content.replace(checkboxRegex, "");
3527
- if (options.label) {
3528
- token.children.splice(1, 0, createLabelBeginToken(id));
3529
- token.children.push(createLabelEndToken());
3530
- }
3531
- }
3532
- function generateIdForToken(token) {
3533
- if (token.map) {
3534
- return `task-item-${token.map[0]}`;
3535
- } else {
3536
- return `task-item-${Math.ceil(Math.random() * (1e4 * 1e3) - 1e3)}`;
3537
- }
3538
- }
3539
- function createCheckboxToken(token, enabled, id) {
3540
- const checkbox = new Token("taskListItemCheckbox", "", 0);
3541
- if (!enabled) {
3542
- checkbox.attrSet("disabled", "true");
3543
- }
3544
- if (token.map) {
3545
- checkbox.attrSet("line", token.map[0].toString());
3546
- }
3547
- checkbox.attrSet("id", id);
3548
- const checkboxRegexResult = checkboxRegex.exec(token.content);
3549
- const isChecked = checkboxRegexResult?.[1].toLowerCase() === "x";
3550
- if (isChecked) {
3551
- checkbox.attrSet("checked", "true");
3552
- }
3553
- return checkbox;
3554
- }
3555
- function createLabelBeginToken(id) {
3556
- const labelBeginToken = new Token("taskListItemLabel_open", "", 1);
3557
- labelBeginToken.attrSet("id", id);
3558
- return labelBeginToken;
3559
- }
3560
- function createLabelEndToken() {
3561
- return new Token("taskListItemLabel_close", "", -1);
3562
- }
3563
- function isInline(token) {
3564
- return token.type === "inline";
3402
+ );
3403
+ return Array.from(typeModules);
3565
3404
  }
3566
- function isParagraph(token) {
3567
- return token.type === "paragraph_open";
3405
+ function truncateMancoMark(md2) {
3406
+ return md2.replace(/{monaco.*?}/g, "");
3568
3407
  }
3569
- function isListItem(token) {
3570
- return token.type === "list_item_open";
3408
+ function transformSlotSugar(md2) {
3409
+ const lines = md2.split(/\r?\n/g);
3410
+ let prevSlot = false;
3411
+ const { isLineInsideCodeblocks } = getCodeBlocks(md2);
3412
+ lines.forEach((line, idx) => {
3413
+ if (isLineInsideCodeblocks(idx))
3414
+ return;
3415
+ const match = line.trimEnd().match(/^::\s*([\w\.\-\:]+)\s*::$/);
3416
+ if (match) {
3417
+ lines[idx] = `${prevSlot ? "\n\n</template>\n" : "\n"}<template v-slot:${match[1]}="slotProps">
3418
+ `;
3419
+ prevSlot = true;
3420
+ }
3421
+ });
3422
+ if (prevSlot)
3423
+ lines[lines.length - 1] += "\n\n</template>";
3424
+ return lines.join("\n");
3571
3425
  }
3572
- function startsWithTodoMarkdown(token) {
3573
- return checkboxRegex.test(token.content);
3426
+ var reMagicMoveBlock = /^````(?:md|markdown) magic-move(?:[ ]*?({.*?})?([^\n]*?))?\n([\s\S]+?)^````$/mg;
3427
+ var reCodeBlock = /^```(\w+?)(?:\s*{([\d\w*,\|-]+)}\s*?({.*?})?(.*?))?\n([\s\S]+?)^```$/mg;
3428
+ function transformMagicMove(md2, shiki2, shikiOptions2) {
3429
+ return md2.replace(
3430
+ reMagicMoveBlock,
3431
+ (full, _options = "", _attrs = "", body) => {
3432
+ if (!shiki2 || !shikiOptions2)
3433
+ throw new Error("Shiki is required for Magic Move. You may need to set `highlighter: shiki` in your Slidev config.");
3434
+ const matches = Array.from(body.matchAll(reCodeBlock));
3435
+ if (!matches.length)
3436
+ throw new Error("Magic Move block must contain at least one code block");
3437
+ const langs = new Set(matches.map((i) => i[1]));
3438
+ if (langs.size > 1)
3439
+ throw new Error(`Magic Move block must contain code blocks with the same language, got ${Array.from(langs).join(", ")}`);
3440
+ const lang = Array.from(langs)[0];
3441
+ const magicMove = createMagicMoveMachine(
3442
+ (code) => codeToKeyedTokens(shiki2, code, {
3443
+ ...shikiOptions2,
3444
+ lang
3445
+ })
3446
+ );
3447
+ const steps = matches.map((i) => magicMove.commit((i[5] || "").trimEnd()));
3448
+ const compressed = lz.compressToBase64(JSON.stringify(steps));
3449
+ return `<ShikiMagicMove steps-lz="${compressed}" />`;
3450
+ }
3451
+ );
3574
3452
  }
3453
+ function transformHighlighter(md2) {
3454
+ return md2.replace(
3455
+ reCodeBlock,
3456
+ (full, lang = "", rangeStr = "", options = "", attrs = "", code) => {
3457
+ const ranges = rangeStr.split(/\|/g).map((i) => i.trim());
3458
+ code = code.trimEnd();
3459
+ options = options.trim() || "{}";
3460
+ return `
3461
+ <CodeBlockWrapper v-bind="${options}" :ranges='${JSON.stringify(ranges)}'>
3575
3462
 
3576
- // ../../node_modules/.pnpm/@hedgedoc+markdown-it-plugins@2.1.4_patch_hash=tuyuxytl56b2vxulpkzt2wf4o4_markdown-it@14.0.0/node_modules/@hedgedoc/markdown-it-plugins/dist/esm/toc/plugin.js
3577
- import { Optional } from "@mrdrogdrog/optional";
3578
-
3579
- // node/plugins/markdown.ts
3580
- import { encode as encodePlantUml } from "plantuml-encoder";
3581
- import Mdc from "markdown-it-mdc";
3582
- import { codeToKeyedTokens, createMagicMoveMachine } from "shiki-magic-move/core";
3583
- import mila2 from "markdown-it-link-attributes";
3584
- import mif from "markdown-it-footnote";
3585
- import lz from "lz-string";
3463
+ \`\`\`${lang}${attrs}
3464
+ ${code}
3465
+ \`\`\`
3586
3466
 
3587
- // node/plugins/markdown-it-katex.ts
3588
- import katex from "katex";
3589
- function isValidDelim(state, pos) {
3590
- const max = state.posMax;
3591
- let can_open = true;
3592
- let can_close = true;
3593
- const prevChar = pos > 0 ? state.src.charCodeAt(pos - 1) : -1;
3594
- const nextChar = pos + 1 <= max ? state.src.charCodeAt(pos + 1) : -1;
3595
- if (prevChar === 32 || prevChar === 9 || /* \t */
3596
- nextChar >= 48 && nextChar <= 57)
3597
- can_close = false;
3598
- if (nextChar === 32 || nextChar === 9)
3599
- can_open = false;
3467
+ </CodeBlockWrapper>`;
3468
+ }
3469
+ );
3470
+ }
3471
+ function getCodeBlocks(md2) {
3472
+ const codeblocks = Array.from(md2.matchAll(/^```[\s\S]*?^```/mg)).map((m) => {
3473
+ const start = m.index;
3474
+ const end = m.index + m[0].length;
3475
+ const startLine = md2.slice(0, start).match(/\n/g)?.length || 0;
3476
+ const endLine = md2.slice(0, end).match(/\n/g)?.length || 0;
3477
+ return [start, end, startLine, endLine];
3478
+ });
3600
3479
  return {
3601
- can_open,
3602
- can_close
3480
+ codeblocks,
3481
+ isInsideCodeblocks(idx) {
3482
+ return codeblocks.some(([s, e]) => s <= idx && idx <= e);
3483
+ },
3484
+ isLineInsideCodeblocks(line) {
3485
+ return codeblocks.some(([, , s, e]) => s <= line && line <= e);
3486
+ }
3603
3487
  };
3604
3488
  }
3605
- function math_inline(state, silent) {
3606
- let match, token, res, pos;
3607
- if (state.src[state.pos] !== "$")
3608
- return false;
3609
- res = isValidDelim(state, state.pos);
3610
- if (!res.can_open) {
3611
- if (!silent)
3612
- state.pending += "$";
3613
- state.pos += 1;
3614
- return true;
3615
- }
3616
- const start = state.pos + 1;
3617
- match = start;
3618
- while ((match = state.src.indexOf("$", match)) !== -1) {
3619
- pos = match - 1;
3620
- while (state.src[pos] === "\\")
3621
- pos -= 1;
3622
- if ((match - pos) % 2 === 1)
3623
- break;
3624
- match += 1;
3625
- }
3626
- if (match === -1) {
3627
- if (!silent)
3628
- state.pending += "$";
3629
- state.pos = start;
3630
- return true;
3631
- }
3632
- if (match - start === 0) {
3633
- if (!silent)
3634
- state.pending += "$$";
3635
- state.pos = start + 1;
3636
- return true;
3637
- }
3638
- res = isValidDelim(state, match);
3639
- if (!res.can_close) {
3640
- if (!silent)
3641
- state.pending += "$";
3642
- state.pos = start;
3643
- return true;
3489
+ function transformPageCSS(md2, id) {
3490
+ const page = id.match(/(\d+)\.md$/)?.[1];
3491
+ if (!page)
3492
+ return md2;
3493
+ const { isInsideCodeblocks } = getCodeBlocks(md2);
3494
+ const result = md2.replace(
3495
+ /(\n<style[^>]*?>)([\s\S]+?)(<\/style>)/g,
3496
+ (full, start, css, end, index) => {
3497
+ if (index < 0 || isInsideCodeblocks(index))
3498
+ return full;
3499
+ if (!start.includes("scoped"))
3500
+ start = start.replace("<style", "<style scoped");
3501
+ return `${start}
3502
+ ${css}${end}`;
3503
+ }
3504
+ );
3505
+ return result;
3506
+ }
3507
+ function transformMermaid(md2) {
3508
+ return md2.replace(/^```mermaid\s*?({.*?})?\n([\s\S]+?)\n```/mg, (full, options = "", code = "") => {
3509
+ code = code.trim();
3510
+ options = options.trim() || "{}";
3511
+ const encoded = lz.compressToBase64(code);
3512
+ return `<Mermaid code-lz="${encoded}" v-bind="${options}" />`;
3513
+ });
3514
+ }
3515
+ function transformPlantUml(md2, server) {
3516
+ return md2.replace(/^```plantuml\s*?({.*?})?\n([\s\S]+?)\n```/mg, (full, options = "", content = "") => {
3517
+ const code = encodePlantUml(content.trim());
3518
+ options = options.trim() || "{}";
3519
+ return `<PlantUml :code="'${code}'" :server="'${server}'" v-bind="${options}" />`;
3520
+ });
3521
+ }
3522
+ function escapeVueInCode(md2) {
3523
+ return md2.replace(/{{/g, "&lbrace;&lbrace;");
3524
+ }
3525
+ async function loadShikiSetups(clientRoot, roots) {
3526
+ const result = await loadSetups(
3527
+ clientRoot,
3528
+ roots,
3529
+ "shiki.ts",
3530
+ {
3531
+ /** @deprecated */
3532
+ async loadTheme(path2) {
3533
+ console.warn("[slidev] `loadTheme` in `setup/shiki.ts` is deprecated. Pass directly the theme name it's supported by Shiki. For custom themes, load it manually via `JSON.parse(fs.readFileSync(path, 'utf-8'))` and pass the raw JSON object instead.");
3534
+ return JSON.parse(await fs4.readFile(path2, "utf-8"));
3535
+ }
3536
+ },
3537
+ {},
3538
+ false
3539
+ );
3540
+ if ("theme" in result && "themes" in result)
3541
+ delete result.theme;
3542
+ if (result.theme && typeof result.theme !== "string" && !result.theme.name && !result.theme.tokenColors) {
3543
+ result.themes = result.theme;
3544
+ delete result.theme;
3644
3545
  }
3645
- if (!silent) {
3646
- token = state.push("math_inline", "math", 0);
3647
- token.markup = "$";
3648
- token.content = state.src.slice(start, match);
3546
+ if (!result.theme && !result.themes) {
3547
+ result.themes = {
3548
+ dark: "vitesse-dark",
3549
+ light: "vitesse-light"
3550
+ };
3649
3551
  }
3650
- state.pos = match + 1;
3651
- return true;
3552
+ if (result.themes)
3553
+ result.defaultColor = false;
3554
+ return result;
3652
3555
  }
3653
- function math_block(state, start, end, silent) {
3654
- let firstLine;
3655
- let lastLine;
3656
- let next;
3657
- let lastPos;
3658
- let found = false;
3659
- let pos = state.bMarks[start] + state.tShift[start];
3660
- let max = state.eMarks[start];
3661
- if (pos + 2 > max)
3662
- return false;
3663
- if (state.src.slice(pos, pos + 2) !== "$$")
3664
- return false;
3665
- pos += 2;
3666
- firstLine = state.src.slice(pos, max);
3667
- if (silent)
3668
- return true;
3669
- if (firstLine.trim().slice(-2) === "$$") {
3670
- firstLine = firstLine.trim().slice(0, -2);
3671
- found = true;
3672
- }
3673
- for (next = start; !found; ) {
3674
- next++;
3675
- if (next >= end)
3676
- break;
3677
- pos = state.bMarks[next] + state.tShift[next];
3678
- max = state.eMarks[next];
3679
- if (pos < max && state.tShift[next] < state.blkIndent) {
3680
- break;
3681
- }
3682
- if (state.src.slice(pos, max).trim().slice(-2) === "$$") {
3683
- lastPos = state.src.slice(0, max).lastIndexOf("$$");
3684
- lastLine = state.src.slice(pos, lastPos);
3685
- found = true;
3686
- }
3556
+
3557
+ // node/plugins/loaders.ts
3558
+ var regexId = /^\/\@slidev\/slide\/(\d+)\.(md|json)(?:\?import)?$/;
3559
+ var regexIdQuery = /(\d+?)\.(md|json|frontmatter)$/;
3560
+ var templateInjectionMarker = "/* @slidev-injection */";
3561
+ var templateImportContextUtils = `import {
3562
+ useSlideContext,
3563
+ provideFrontmatter as _provideFrontmatter,
3564
+ frontmatterToProps as _frontmatterToProps,
3565
+ } from "@slidev/client/context.ts"`.replace(/\n\s*/g, " ");
3566
+ var templateInitContext = `const { $slidev, $nav, $clicksContext, $clicks, $page, $renderContext, $frontmatter } = useSlideContext()`;
3567
+ function getBodyJson(req) {
3568
+ return new Promise((resolve5, reject) => {
3569
+ let body = "";
3570
+ req.on("data", (chunk) => body += chunk);
3571
+ req.on("error", reject);
3572
+ req.on("end", () => {
3573
+ try {
3574
+ resolve5(JSON.parse(body) || {});
3575
+ } catch (e) {
3576
+ reject(e);
3577
+ }
3578
+ });
3579
+ });
3580
+ }
3581
+ var md = Markdown2({ html: true });
3582
+ md.use(mila2, {
3583
+ attrs: {
3584
+ target: "_blank",
3585
+ rel: "noopener"
3687
3586
  }
3688
- state.line = next + 1;
3689
- const token = state.push("math_block", "math", 0);
3690
- token.block = true;
3691
- token.content = (firstLine && firstLine.trim() ? `${firstLine}
3692
- ` : "") + state.getLines(start + 1, next, state.tShift[start], true) + (lastLine && lastLine.trim() ? lastLine : "");
3693
- token.map = [start, state.line];
3694
- token.markup = "$$";
3695
- return true;
3587
+ });
3588
+ function renderNote(text = "") {
3589
+ let clickCount = 0;
3590
+ const html = md.render(
3591
+ text.replace(/\[click(?::(\d+))?\]/gi, (_, count = 1) => {
3592
+ clickCount += Number(count);
3593
+ return `<span class="slidev-note-click-mark" data-clicks="${clickCount}"></span>`;
3594
+ })
3595
+ );
3596
+ return html;
3696
3597
  }
3697
- function math_plugin(md2, options) {
3698
- options = options || {};
3699
- const katexInline = function(latex) {
3700
- options.displayMode = false;
3701
- try {
3702
- return katex.renderToString(latex, options);
3703
- } catch (error) {
3704
- if (options.throwOnError)
3705
- console.warn(error);
3706
- return latex;
3707
- }
3708
- };
3709
- const inlineRenderer = function(tokens, idx) {
3710
- return katexInline(tokens[idx].content);
3711
- };
3712
- const katexBlock = function(latex) {
3713
- options.displayMode = true;
3714
- try {
3715
- return `<p>${katex.renderToString(latex, options)}</p>`;
3716
- } catch (error) {
3717
- if (options.throwOnError)
3718
- console.warn(error);
3719
- return latex;
3720
- }
3721
- };
3722
- const blockRenderer = function(tokens, idx) {
3723
- return `${katexBlock(tokens[idx].content)}
3724
- `;
3598
+ function withRenderedNote(data) {
3599
+ return {
3600
+ ...data,
3601
+ noteHTML: renderNote(data?.note)
3725
3602
  };
3726
- md2.inline.ruler.after("escape", "math_inline", math_inline);
3727
- md2.block.ruler.after("blockquote", "math_block", math_block, {
3728
- alt: ["paragraph", "reference", "blockquote", "list"]
3729
- });
3730
- md2.renderer.rules.math_inline = inlineRenderer;
3731
- md2.renderer.rules.math_block = blockRenderer;
3732
3603
  }
3604
+ function createSlidesLoader({ data, clientRoot, roots, remote, mode, userRoot }, pluginOptions, serverOptions) {
3605
+ const slidePrefix = "/@slidev/slides/";
3606
+ const hmrPages = /* @__PURE__ */ new Set();
3607
+ let server;
3608
+ let _layouts_cache_time = 0;
3609
+ let _layouts_cache = {};
3610
+ return [
3611
+ {
3612
+ name: "slidev:loader",
3613
+ configureServer(_server) {
3614
+ server = _server;
3615
+ updateServerWatcher();
3616
+ server.middlewares.use(async (req, res, next) => {
3617
+ const match = req.url?.match(regexId);
3618
+ if (!match)
3619
+ return next();
3620
+ const [, no, type] = match;
3621
+ const idx = Number.parseInt(no);
3622
+ if (type === "json" && req.method === "GET") {
3623
+ res.write(JSON.stringify(withRenderedNote(data.slides[idx])));
3624
+ return res.end();
3625
+ }
3626
+ if (type === "json" && req.method === "POST") {
3627
+ const body = await getBodyJson(req);
3628
+ const slide = data.slides[idx];
3629
+ if (body.content && body.content !== slide.source.content)
3630
+ hmrPages.add(idx);
3631
+ Object.assign(slide.source, body);
3632
+ parser.prettifySlide(slide.source);
3633
+ await parser.save(data.markdownFiles[slide.source.filepath]);
3634
+ res.statusCode = 200;
3635
+ res.write(JSON.stringify(withRenderedNote(slide)));
3636
+ return res.end();
3637
+ }
3638
+ next();
3639
+ });
3640
+ },
3641
+ async handleHotUpdate(ctx) {
3642
+ if (!data.watchFiles.includes(ctx.file))
3643
+ return;
3644
+ await ctx.read();
3645
+ const newData = await serverOptions.loadData?.();
3646
+ if (!newData)
3647
+ return [];
3648
+ const moduleIds = /* @__PURE__ */ new Set();
3649
+ if (data.slides.length !== newData.slides.length) {
3650
+ moduleIds.add("/@slidev/routes");
3651
+ range(newData.slides.length).map((i) => hmrPages.add(i));
3652
+ }
3653
+ if (!equal(data.headmatter.defaults, newData.headmatter.defaults)) {
3654
+ moduleIds.add("/@slidev/routes");
3655
+ range(data.slides.length).map((i) => hmrPages.add(i));
3656
+ }
3657
+ if (!equal(data.config, newData.config))
3658
+ moduleIds.add("/@slidev/configs");
3659
+ if (!equal(data.features, newData.features)) {
3660
+ setTimeout(() => {
3661
+ ctx.server.ws.send({ type: "full-reload" });
3662
+ }, 1);
3663
+ }
3664
+ const length = Math.max(data.slides.length, newData.slides.length);
3665
+ for (let i = 0; i < length; i++) {
3666
+ const a = data.slides[i];
3667
+ const b = newData.slides[i];
3668
+ if (a?.content.trim() === b?.content.trim() && a?.title?.trim() === b?.title?.trim() && equal(a.frontmatter, b.frontmatter) && Object.entries(a.snippetsUsed ?? {}).every(([file, oldContent]) => {
3669
+ try {
3670
+ const newContent = fs5.readFileSync(file, "utf-8");
3671
+ return oldContent === newContent;
3672
+ } catch {
3673
+ return false;
3674
+ }
3675
+ })) {
3676
+ if (a?.note !== b?.note) {
3677
+ ctx.server.ws.send({
3678
+ type: "custom",
3679
+ event: "slidev-update-note",
3680
+ data: {
3681
+ id: i,
3682
+ note: b.note || "",
3683
+ noteHTML: renderNote(b.note || "")
3684
+ }
3685
+ });
3686
+ }
3687
+ continue;
3688
+ }
3689
+ ctx.server.ws.send({
3690
+ type: "custom",
3691
+ event: "slidev-update",
3692
+ data: {
3693
+ id: i,
3694
+ data: withRenderedNote(newData.slides[i])
3695
+ }
3696
+ });
3697
+ hmrPages.add(i);
3698
+ }
3699
+ Object.assign(data, newData);
3700
+ if (hmrPages.size > 0)
3701
+ moduleIds.add("/@slidev/titles.md");
3702
+ const vueModules = Array.from(hmrPages).flatMap((i) => [
3703
+ ctx.server.moduleGraph.getModuleById(`${slidePrefix}${i + 1}.frontmatter`),
3704
+ ctx.server.moduleGraph.getModuleById(`${slidePrefix}${i + 1}.md`)
3705
+ ]);
3706
+ hmrPages.clear();
3707
+ const moduleEntries = [
3708
+ ...vueModules,
3709
+ ...Array.from(moduleIds).map((id) => ctx.server.moduleGraph.getModuleById(id))
3710
+ ].filter(notNullish).filter((i) => !i.id?.startsWith("/@id/@vite-icons"));
3711
+ updateServerWatcher();
3712
+ return moduleEntries;
3713
+ },
3714
+ resolveId(id) {
3715
+ if (id.startsWith(slidePrefix) || id.startsWith("/@slidev/"))
3716
+ return id;
3717
+ return null;
3718
+ },
3719
+ load(id) {
3720
+ if (id === "/@slidev/routes")
3721
+ return generateRoutes();
3722
+ if (id === "/@slidev/layouts")
3723
+ return generateLayouts();
3724
+ if (id === "/@slidev/styles")
3725
+ return generateUserStyles();
3726
+ if (id === "/@slidev/monaco-types")
3727
+ return generateMonacoTypes();
3728
+ if (id === "/@slidev/configs")
3729
+ return generateConfigs();
3730
+ if (id === "/@slidev/global-components/top")
3731
+ return generateGlobalComponents("top");
3732
+ if (id === "/@slidev/global-components/bottom")
3733
+ return generateGlobalComponents("bottom");
3734
+ if (id === "/@slidev/custom-nav-controls")
3735
+ return generateCustomNavControls();
3736
+ if (id === "/@slidev/shiki")
3737
+ return generteShikiBundle();
3738
+ if (id === "/@slidev/titles.md") {
3739
+ return {
3740
+ code: data.slides.map(({ title }, i) => `<template ${i === 0 ? "v-if" : "v-else-if"}="+no === ${i + 1}">
3733
3741
 
3734
- // node/plugins/markdown-it-prism.ts
3735
- import { createRequire } from "node:module";
3736
- import Prism from "prismjs";
3737
- import loadLanguages from "prismjs/components/index.js";
3738
- import * as htmlparser2 from "htmlparser2";
3739
- var require2 = createRequire(import.meta.url);
3740
- var Tag = class {
3741
- tagname;
3742
- attributes;
3743
- constructor(tagname, attributes) {
3744
- this.tagname = tagname;
3745
- this.attributes = attributes;
3746
- }
3747
- asOpen() {
3748
- return `<${this.tagname} ${Object.entries(this.attributes).map(([key, value]) => `${key}="${value}"`).join(" ")}>`;
3742
+ ${title}
3743
+
3744
+ </template>`).join(""),
3745
+ map: { mappings: "" }
3746
+ };
3747
+ }
3748
+ if (id.startsWith(slidePrefix)) {
3749
+ const remaning = id.slice(slidePrefix.length);
3750
+ const match = remaning.match(regexIdQuery);
3751
+ if (match) {
3752
+ const [, no, type] = match;
3753
+ const pageNo = Number.parseInt(no) - 1;
3754
+ const slide = data.slides[pageNo];
3755
+ if (!slide)
3756
+ return;
3757
+ if (type === "md") {
3758
+ return {
3759
+ code: slide?.content,
3760
+ map: { mappings: "" }
3761
+ };
3762
+ } else if (type === "frontmatter") {
3763
+ const slideBase = {
3764
+ ...withRenderedNote(slide),
3765
+ frontmatter: void 0,
3766
+ source: void 0,
3767
+ // remove raw content in build, optimize the bundle size
3768
+ ...mode === "build" ? { raw: "", content: "", note: "" } : {}
3769
+ };
3770
+ const fontmatter = getFrontmatter(pageNo);
3771
+ return {
3772
+ code: [
3773
+ "// @unocss-include",
3774
+ 'import { reactive, computed } from "vue"',
3775
+ `export const frontmatter = reactive(${JSON.stringify(fontmatter)})`,
3776
+ `export const meta = reactive({
3777
+ layout: computed(() => frontmatter.layout),
3778
+ transition: computed(() => frontmatter.transition),
3779
+ class: computed(() => frontmatter.class),
3780
+ clicks: computed(() => frontmatter.clicks),
3781
+ name: computed(() => frontmatter.name),
3782
+ preload: computed(() => frontmatter.preload),
3783
+ slide: {
3784
+ ...(${JSON.stringify(slideBase)}),
3785
+ frontmatter,
3786
+ filepath: ${JSON.stringify(slide.source.filepath)},
3787
+ start: ${JSON.stringify(slide.source.start)},
3788
+ id: ${pageNo},
3789
+ no: ${no},
3790
+ },
3791
+ __clicksContext: null,
3792
+ __preloaded: false,
3793
+ })`,
3794
+ "export default frontmatter",
3795
+ // handle HMR, update frontmatter with update
3796
+ "if (import.meta.hot) {",
3797
+ " import.meta.hot.accept(({ frontmatter: update }) => {",
3798
+ " if(!update) return",
3799
+ " Object.keys(frontmatter).forEach(key => {",
3800
+ " if (!(key in update)) delete frontmatter[key]",
3801
+ " })",
3802
+ " Object.assign(frontmatter, update)",
3803
+ " })",
3804
+ "}"
3805
+ ].join("\n"),
3806
+ map: { mappings: "" }
3807
+ };
3808
+ }
3809
+ }
3810
+ return {
3811
+ code: "",
3812
+ map: { mappings: "" }
3813
+ };
3814
+ }
3815
+ }
3816
+ },
3817
+ {
3818
+ name: "slidev:layout-transform:pre",
3819
+ enforce: "pre",
3820
+ async transform(code, id) {
3821
+ if (!id.startsWith(slidePrefix))
3822
+ return;
3823
+ const remaning = id.slice(slidePrefix.length);
3824
+ const match = remaning.match(regexIdQuery);
3825
+ if (!match)
3826
+ return;
3827
+ const [, no, type] = match;
3828
+ if (type !== "md")
3829
+ return;
3830
+ const pageNo = Number.parseInt(no) - 1;
3831
+ return transformMarkdown(code, pageNo);
3832
+ }
3833
+ },
3834
+ {
3835
+ name: "slidev:context-transform:pre",
3836
+ enforce: "pre",
3837
+ async transform(code, id) {
3838
+ if (!id.endsWith(".vue") || id.includes("/@slidev/client/") || id.includes("/packages/client/"))
3839
+ return;
3840
+ return transformVue(code);
3841
+ }
3842
+ },
3843
+ {
3844
+ name: "slidev:title-transform:pre",
3845
+ enforce: "pre",
3846
+ transform(code, id) {
3847
+ if (id !== "/@slidev/titles.md")
3848
+ return;
3849
+ return transformTitles(code);
3850
+ }
3851
+ },
3852
+ {
3853
+ name: "slidev:slide-transform:post",
3854
+ enforce: "post",
3855
+ transform(code, id) {
3856
+ if (!id.match(/\/@slidev\/slides\/\d+\.md($|\?)/))
3857
+ return;
3858
+ const replaced = code.replace("if (_rerender_only)", "if (false)");
3859
+ if (replaced !== code)
3860
+ return replaced;
3861
+ }
3862
+ },
3863
+ {
3864
+ name: "slidev:index-html-transform",
3865
+ transformIndexHtml() {
3866
+ const { info, author, keywords } = data.headmatter;
3867
+ return [
3868
+ {
3869
+ tag: "title",
3870
+ children: getTitle()
3871
+ },
3872
+ info && {
3873
+ tag: "meta",
3874
+ attrs: {
3875
+ name: "description",
3876
+ content: info
3877
+ }
3878
+ },
3879
+ author && {
3880
+ tag: "meta",
3881
+ attrs: {
3882
+ name: "author",
3883
+ content: author
3884
+ }
3885
+ },
3886
+ keywords && {
3887
+ tag: "meta",
3888
+ attrs: {
3889
+ name: "keywords",
3890
+ content: Array.isArray(keywords) ? keywords.join(", ") : keywords
3891
+ }
3892
+ }
3893
+ ].filter(isTruthy2);
3894
+ }
3895
+ }
3896
+ ];
3897
+ function updateServerWatcher() {
3898
+ if (!server)
3899
+ return;
3900
+ server.watcher.add(data.watchFiles);
3749
3901
  }
3750
- asClosed() {
3751
- return `</${this.tagname}>`;
3902
+ function getFrontmatter(pageNo) {
3903
+ return {
3904
+ ...data.headmatter?.defaults || {},
3905
+ ...data.slides[pageNo]?.frontmatter || {}
3906
+ };
3752
3907
  }
3753
- };
3754
- var DEFAULTS = {
3755
- plugins: [],
3756
- init: () => {
3757
- },
3758
- defaultLanguageForUnknown: void 0,
3759
- defaultLanguageForUnspecified: void 0,
3760
- defaultLanguage: void 0
3761
- };
3762
- function loadPrismLang(lang) {
3763
- if (!lang)
3764
- return void 0;
3765
- let langObject = Prism.languages[lang];
3766
- if (langObject === void 0) {
3767
- loadLanguages([lang]);
3768
- langObject = Prism.languages[lang];
3908
+ async function transformMarkdown(code, pageNo) {
3909
+ const layouts = await getLayouts();
3910
+ const frontmatter = getFrontmatter(pageNo);
3911
+ let layoutName = frontmatter?.layout || (pageNo === 0 ? "cover" : "default");
3912
+ if (!layouts[layoutName]) {
3913
+ console.error(red(`
3914
+ Unknown layout "${bold(layoutName)}".${yellow(" Available layouts are:")}`) + Object.keys(layouts).map((i, idx) => (idx % 3 === 0 ? "\n " : "") + gray(i.padEnd(15, " "))).join(" "));
3915
+ console.error();
3916
+ layoutName = "default";
3917
+ }
3918
+ delete frontmatter.title;
3919
+ const imports = [
3920
+ `import InjectedLayout from "${toAtFS(layouts[layoutName])}"`,
3921
+ `import frontmatter from "${toAtFS(`${slidePrefix + (pageNo + 1)}.frontmatter`)}"`,
3922
+ templateImportContextUtils,
3923
+ "_provideFrontmatter(frontmatter)",
3924
+ templateInitContext,
3925
+ templateInjectionMarker
3926
+ ];
3927
+ code = code.replace(/(<script setup.*>)/g, `$1
3928
+ ${imports.join("\n")}
3929
+ `);
3930
+ const injectA = code.indexOf("<template>") + "<template>".length;
3931
+ const injectB = code.lastIndexOf("</template>");
3932
+ let body = code.slice(injectA, injectB).trim();
3933
+ if (body.startsWith("<div>") && body.endsWith("</div>"))
3934
+ body = body.slice(5, -6);
3935
+ code = `${code.slice(0, injectA)}
3936
+ <InjectedLayout v-bind="_frontmatterToProps(frontmatter,${pageNo})">
3937
+ ${body}
3938
+ </InjectedLayout>
3939
+ ${code.slice(injectB)}`;
3940
+ return code;
3769
3941
  }
3770
- return langObject;
3771
- }
3772
- function loadPrismPlugin(name) {
3773
- try {
3774
- require2(`prismjs/plugins/${name}/prism-${name}`);
3775
- } catch (e) {
3776
- throw new Error(`Cannot load Prism plugin "${name}". Please check the spelling.`);
3942
+ function transformVue(code) {
3943
+ if (code.includes(templateInjectionMarker) || code.includes("useSlideContext()"))
3944
+ return code;
3945
+ const imports = [
3946
+ templateImportContextUtils,
3947
+ templateInitContext,
3948
+ templateInjectionMarker
3949
+ ];
3950
+ const matchScript = code.match(/<script((?!setup).)*(setup)?.*>/);
3951
+ if (matchScript && matchScript[2]) {
3952
+ return code.replace(/(<script.*>)/g, `$1
3953
+ ${imports.join("\n")}
3954
+ `);
3955
+ } else if (matchScript && !matchScript[2]) {
3956
+ const matchExport = code.match(/export\s+default\s+{/);
3957
+ if (matchExport) {
3958
+ const exportIndex = (matchExport.index || 0) + matchExport[0].length;
3959
+ let component = code.slice(exportIndex);
3960
+ component = component.slice(0, component.indexOf("</script>"));
3961
+ const scriptIndex = (matchScript.index || 0) + matchScript[0].length;
3962
+ const provideImport = '\nimport { injectionSlidevContext } from "@slidev/client/constants.ts"\n';
3963
+ code = `${code.slice(0, scriptIndex)}${provideImport}${code.slice(scriptIndex)}`;
3964
+ let injectIndex = exportIndex + provideImport.length;
3965
+ let injectObject = "$slidev: { from: injectionSlidevContext },";
3966
+ const matchInject = component.match(/.*inject\s*:\s*([\[{])/);
3967
+ if (matchInject) {
3968
+ injectIndex += (matchInject.index || 0) + matchInject[0].length;
3969
+ if (matchInject[1] === "[") {
3970
+ let injects = component.slice((matchInject.index || 0) + matchInject[0].length);
3971
+ const injectEndIndex = injects.indexOf("]");
3972
+ injects = injects.slice(0, injectEndIndex);
3973
+ injectObject += injects.split(",").map((inject) => `${inject}: {from: ${inject}}`).join(",");
3974
+ return `${code.slice(0, injectIndex - 1)}{
3975
+ ${injectObject}
3976
+ }${code.slice(injectIndex + injectEndIndex + 1)}`;
3977
+ } else {
3978
+ return `${code.slice(0, injectIndex)}
3979
+ ${injectObject}
3980
+ ${code.slice(injectIndex)}`;
3981
+ }
3982
+ }
3983
+ return `${code.slice(0, injectIndex)}
3984
+ inject: { ${injectObject} },
3985
+ ${code.slice(injectIndex)}`;
3986
+ }
3987
+ }
3988
+ return `<script setup>
3989
+ ${imports.join("\n")}
3990
+ </script>
3991
+ ${code}`;
3777
3992
  }
3778
- }
3779
- function selectLanguage(options, lang) {
3780
- let langToUse = lang;
3781
- if (langToUse === "" && options.defaultLanguageForUnspecified !== void 0)
3782
- langToUse = options.defaultLanguageForUnspecified;
3783
- let prismLang = loadPrismLang(langToUse);
3784
- if (prismLang === void 0 && options.defaultLanguageForUnknown !== void 0) {
3785
- langToUse = options.defaultLanguageForUnknown;
3786
- prismLang = loadPrismLang(langToUse);
3993
+ function transformTitles(code) {
3994
+ return code.replace(/<template>\s*<div>\s*<p>/, "<template>").replace(/<\/p>\s*<\/div>\s*<\/template>/, "</template>").replace(/<script\ssetup>/, `<script setup lang="ts">
3995
+ defineProps<{ no: number | string }>()`);
3787
3996
  }
3788
- return [langToUse, prismLang];
3789
- }
3790
- function highlight(markdownit, options, text, lang) {
3791
- const [langToUse, prismLang] = selectLanguage(options, lang);
3792
- let code = text.trimEnd();
3793
- code = prismLang ? highlightPrism(code, prismLang, langToUse) : markdownit.utils.escapeHtml(code);
3794
- code = code.split(/\r?\n/g).map((line) => `<span class="line">${line}</span>`).join("\n");
3795
- const classAttribute = langToUse ? ` class="slidev-code ${markdownit.options.langPrefix}${markdownit.utils.escapeHtml(langToUse)}"` : "";
3796
- return escapeVueInCode(`<pre${classAttribute}><code>${code}</code></pre>`);
3797
- }
3798
- function highlightPrism(code, prismLang, langToUse) {
3799
- const openTags = [];
3800
- const parser2 = new htmlparser2.Parser({
3801
- onopentag(tagname, attributes) {
3802
- openTags.push(new Tag(tagname, attributes));
3803
- },
3804
- onclosetag() {
3805
- openTags.pop();
3806
- }
3807
- });
3808
- code = Prism.highlight(code, prismLang, langToUse);
3809
- code = code.split(/\r?\n/g).map((line) => {
3810
- const prefix = openTags.map((tag) => tag.asOpen()).join("");
3811
- parser2.write(line);
3812
- const postfix = openTags.reverse().map((tag) => tag.asClosed()).join("");
3813
- return prefix + line + postfix;
3814
- }).join("\n");
3815
- parser2.end();
3816
- return code;
3817
- }
3818
- function checkLanguageOption(options, optionName) {
3819
- const language = options[optionName];
3820
- if (language !== void 0 && loadPrismLang(language) === void 0)
3821
- throw new Error(`Bad option ${optionName}: There is no Prism language '${language}'.`);
3822
- }
3823
- function markdownItPrism(markdownit, useroptions) {
3824
- const options = Object.assign({}, DEFAULTS, useroptions);
3825
- checkLanguageOption(options, "defaultLanguage");
3826
- checkLanguageOption(options, "defaultLanguageForUnknown");
3827
- checkLanguageOption(options, "defaultLanguageForUnspecified");
3828
- options.defaultLanguageForUnknown = options.defaultLanguageForUnknown || options.defaultLanguage;
3829
- options.defaultLanguageForUnspecified = options.defaultLanguageForUnspecified || options.defaultLanguage;
3830
- options.plugins.forEach(loadPrismPlugin);
3831
- options.init(Prism);
3832
- markdownit.options.highlight = (text, lang) => highlight(markdownit, options, text, lang);
3833
- }
3834
-
3835
- // node/plugins/transformSnippet.ts
3836
- import path from "node:path";
3837
- import fs5 from "fs-extra";
3838
- function dedent(text) {
3839
- const lines = text.split("\n");
3840
- const minIndentLength = lines.reduce((acc, line) => {
3841
- for (let i = 0; i < line.length; i++) {
3842
- if (line[i] !== " " && line[i] !== " ")
3843
- return Math.min(i, acc);
3844
- }
3845
- return acc;
3846
- }, Number.POSITIVE_INFINITY);
3847
- if (minIndentLength < Number.POSITIVE_INFINITY)
3848
- return lines.map((x) => x.slice(minIndentLength)).join("\n");
3849
- return text;
3850
- }
3851
- function testLine(line, regexp, regionName, end = false) {
3852
- const [full, tag, name] = regexp.exec(line.trim()) || [];
3853
- return full && tag && name === regionName && tag.match(end ? /^[Ee]nd ?[rR]egion$/ : /^[rR]egion$/);
3854
- }
3855
- function findRegion(lines, regionName) {
3856
- const regionRegexps = [
3857
- /^\/\/ ?#?((?:end)?region) ([\w*-]+)$/,
3858
- // javascript, typescript, java
3859
- /^\/\* ?#((?:end)?region) ([\w*-]+) ?\*\/$/,
3860
- // css, less, scss
3861
- /^#pragma ((?:end)?region) ([\w*-]+)$/,
3862
- // C, C++
3863
- /^<!-- #?((?:end)?region) ([\w*-]+) -->$/,
3864
- // HTML, markdown
3865
- /^#((?:End )Region) ([\w*-]+)$/,
3866
- // Visual Basic
3867
- /^::#((?:end)region) ([\w*-]+)$/,
3868
- // Bat
3869
- /^# ?((?:end)?region) ([\w*-]+)$/
3870
- // C#, PHP, Powershell, Python, perl & misc
3871
- ];
3872
- let regexp = null;
3873
- let start = -1;
3874
- for (const [lineId, line] of lines.entries()) {
3875
- if (regexp === null) {
3876
- for (const reg of regionRegexps) {
3877
- if (testLine(line, reg, regionName)) {
3878
- start = lineId + 1;
3879
- regexp = reg;
3880
- break;
3881
- }
3997
+ async function getLayouts() {
3998
+ const now = Date.now();
3999
+ if (now - _layouts_cache_time < 2e3)
4000
+ return _layouts_cache;
4001
+ const layouts = {};
4002
+ for (const root of [...roots, clientRoot]) {
4003
+ const layoutPaths = await fg2("layouts/**/*.{vue,ts}", {
4004
+ cwd: root,
4005
+ absolute: true,
4006
+ suppressErrors: true
4007
+ });
4008
+ for (const layoutPath of layoutPaths) {
4009
+ const layout = basename2(layoutPath).replace(/\.\w+$/, "");
4010
+ if (layouts[layout])
4011
+ continue;
4012
+ layouts[layout] = layoutPath;
3882
4013
  }
3883
- } else if (testLine(line, regexp, regionName, true)) {
3884
- return { start, end: lineId, regexp };
3885
4014
  }
4015
+ _layouts_cache_time = now;
4016
+ _layouts_cache = layouts;
4017
+ return layouts;
3886
4018
  }
3887
- return null;
3888
- }
3889
- function transformSnippet(md2, options, id) {
3890
- const slideId = id.match(/(\d+)\.md$/)?.[1];
3891
- if (!slideId)
3892
- return md2;
3893
- const data = options.data;
3894
- const slideInfo = data.slides[+slideId - 1];
3895
- const dir = path.dirname(slideInfo.source?.filepath ?? options.entry ?? options.userRoot);
3896
- return md2.replace(
3897
- /^<<< *(.+?)(#[\w-]+)? *(?: (\S+?))? *(\{.*)?$/mg,
3898
- (full, filepath = "", regionName = "", lang = "", meta = "") => {
3899
- const firstLine = `\`\`\`${lang || path.extname(filepath).slice(1)} ${meta}`;
3900
- const src = /^\@[\/]/.test(filepath) ? path.resolve(options.userRoot, filepath.slice(2)) : path.resolve(dir, filepath);
3901
- data.watchFiles.push(src);
3902
- const isAFile = fs5.statSync(src).isFile();
3903
- if (!fs5.existsSync(src) || !isAFile) {
3904
- throw new Error(isAFile ? `Code snippet path not found: ${src}` : `Invalid code snippet option`);
3905
- }
3906
- let content = fs5.readFileSync(src, "utf8");
3907
- slideInfo.snippetsUsed ??= {};
3908
- slideInfo.snippetsUsed[src] = content;
3909
- if (regionName) {
3910
- const lines = content.split(/\r?\n/);
3911
- const region = findRegion(lines, regionName.slice(1));
3912
- if (region) {
3913
- content = dedent(
3914
- lines.slice(region.start, region.end).filter((line) => !region.regexp.test(line.trim())).join("\n")
3915
- );
4019
+ async function resolveUrl(id) {
4020
+ return toAtFS(await resolveImportPath(id, true));
4021
+ }
4022
+ function resolveUrlOfClient(name) {
4023
+ return toAtFS(join4(clientRoot, name));
4024
+ }
4025
+ async function generateUserStyles() {
4026
+ const imports = [
4027
+ `import "${resolveUrlOfClient("styles/vars.css")}"`,
4028
+ `import "${resolveUrlOfClient("styles/index.css")}"`,
4029
+ `import "${resolveUrlOfClient("styles/code.css")}"`,
4030
+ `import "${resolveUrlOfClient("styles/katex.css")}"`,
4031
+ `import "${resolveUrlOfClient("styles/transitions.css")}"`,
4032
+ `import "${resolveUrlOfClient("styles/monaco.css")}"`
4033
+ ];
4034
+ for (const root of roots) {
4035
+ const styles = [
4036
+ join4(root, "styles", "index.ts"),
4037
+ join4(root, "styles", "index.js"),
4038
+ join4(root, "styles", "index.css"),
4039
+ join4(root, "styles.css"),
4040
+ join4(root, "style.css")
4041
+ ];
4042
+ for (const style of styles) {
4043
+ if (fs5.existsSync(style)) {
4044
+ imports.push(`import "${toAtFS(style)}"`);
4045
+ continue;
3916
4046
  }
3917
4047
  }
3918
- return `${firstLine}
3919
- ${content}
3920
- \`\`\``;
3921
4048
  }
3922
- );
3923
- }
3924
-
3925
- // node/plugins/markdown.ts
3926
- var shiki;
3927
- var shikiOptions;
3928
- async function createMarkdownPlugin(options, { markdown: mdOptions }) {
3929
- const { data: { config }, roots, mode, entry, clientRoot } = options;
3930
- const setups = [];
3931
- const entryPath = slash3(entry);
3932
- if (config.highlighter === "shiki") {
3933
- const [
3934
- options2,
3935
- { getHighlighter, bundledLanguages },
3936
- markdownItShiki,
3937
- transformerTwoslash
3938
- ] = await Promise.all([
3939
- loadShikiSetups(clientRoot, roots),
3940
- import("shiki").then(({ getHighlighter: getHighlighter2, bundledLanguages: bundledLanguages2 }) => ({ bundledLanguages: bundledLanguages2, getHighlighter: getHighlighter2 })),
3941
- import("@shikijs/markdown-it/core").then(({ fromHighlighter }) => fromHighlighter),
3942
- import("@shikijs/vitepress-twoslash").then(({ transformerTwoslash: transformerTwoslash2 }) => transformerTwoslash2)
3943
- ]);
3944
- shikiOptions = options2;
3945
- shiki = await getHighlighter({
3946
- ...options2,
3947
- langs: options2.langs ?? Object.keys(bundledLanguages),
3948
- themes: "themes" in options2 ? Object.values(options2.themes) : [options2.theme]
3949
- });
3950
- const transformers = [
3951
- ...options2.transformers || [],
3952
- transformerTwoslash({
3953
- explicitTrigger: true,
3954
- twoslashOptions: {
3955
- handbookOptions: {
3956
- noErrorValidation: true
3957
- }
3958
- }
3959
- }),
3960
- {
3961
- pre(pre) {
3962
- this.addClassToHast(pre, "slidev-code");
3963
- delete pre.properties.tabindex;
3964
- },
3965
- postprocess(code) {
3966
- return escapeVueInCode(code);
3967
- }
4049
+ if (data.features.katex)
4050
+ imports.push(`import "${await resolveUrl("katex/dist/katex.min.css")}"`);
4051
+ if (data.config.highlighter === "shiki") {
4052
+ imports.push(
4053
+ `import "${await resolveUrl("@shikijs/vitepress-twoslash/style.css")}"`,
4054
+ `import "${resolveUrlOfClient("styles/shiki-twoslash.css")}"`
4055
+ );
4056
+ }
4057
+ if (data.config.css === "unocss") {
4058
+ imports.unshift(
4059
+ `import "${await resolveUrl("@unocss/reset/tailwind.css")}"`,
4060
+ 'import "uno:preflights.css"',
4061
+ 'import "uno:typography.css"',
4062
+ 'import "uno:shortcuts.css"'
4063
+ );
4064
+ imports.push('import "uno.css"');
4065
+ }
4066
+ return imports.join("\n");
4067
+ }
4068
+ async function generateMonacoTypes() {
4069
+ const typesRoot = join4(userRoot, "snippets");
4070
+ const files = await fg2(["**/*.ts", "**/*.mts", "**/*.cts"], { cwd: typesRoot });
4071
+ let result = [
4072
+ 'import * as monaco from "monaco-editor"',
4073
+ "async function addFile(mod, path) {",
4074
+ " const code = (await mod).default",
4075
+ ' monaco.languages.typescript.typescriptDefaults.addExtraLib(code, "file:///" + path)',
4076
+ ' monaco.editor.createModel(code, "javascript", monaco.Uri.file(path))',
4077
+ "}"
4078
+ ].join("\n");
4079
+ for (const file of files) {
4080
+ const url = `${toAtFS(resolve2(typesRoot, file))}?raw`;
4081
+ result += `addFile(import(${JSON.stringify(url)}), ${JSON.stringify(file)})
4082
+ `;
4083
+ }
4084
+ const deps = data.config.monacoTypesAdditionalPackages;
4085
+ if (data.config.monacoTypesSource === "local")
4086
+ deps.push(...scanMonacoModules(data.slides.map((s) => s.source.raw).join()));
4087
+ function mapModuleNameToModule(moduleSpecifier) {
4088
+ if (moduleSpecifier.startsWith("node:"))
4089
+ return "node";
4090
+ if (builtinModules.includes(moduleSpecifier))
4091
+ return "node";
4092
+ const mainPackageName = moduleSpecifier.split("/")[0];
4093
+ if (builtinModules.includes(mainPackageName) && !mainPackageName.startsWith("@"))
4094
+ return "node";
4095
+ const [a = "", b = ""] = moduleSpecifier.split("/");
4096
+ const moduleName = a.startsWith("@") ? `${a}/${b}` : a;
4097
+ return moduleName;
4098
+ }
4099
+ for (const specifier of deps) {
4100
+ if (specifier[0] === ".")
4101
+ continue;
4102
+ const moduleName = mapModuleNameToModule(specifier);
4103
+ result += `import(${JSON.stringify(`/@slidev-monaco-types/resolve/${moduleName}`)})
4104
+ `;
4105
+ }
4106
+ return result;
4107
+ }
4108
+ async function generateLayouts() {
4109
+ const imports = [];
4110
+ const layouts = objectMap(
4111
+ await getLayouts(),
4112
+ (k, v) => {
4113
+ imports.push(`import __layout_${k} from "${toAtFS(v)}"`);
4114
+ return [k, `__layout_${k}`];
3968
4115
  }
3969
- ];
3970
- const plugin = markdownItShiki(shiki, {
3971
- ...options2,
3972
- transformers
4116
+ );
4117
+ return [
4118
+ imports.join("\n"),
4119
+ `export default {
4120
+ ${Object.entries(layouts).map(([k, v]) => `"${k}": ${v}`).join(",\n")}
4121
+ }`
4122
+ ].join("\n\n");
4123
+ }
4124
+ async function generateRoutes() {
4125
+ const imports = [];
4126
+ const redirects = [];
4127
+ const layouts = await getLayouts();
4128
+ imports.push(
4129
+ `import { markRaw } from 'vue'`,
4130
+ `import __layout__end from '${layouts.end}'`
4131
+ );
4132
+ let no = 1;
4133
+ const routes = data.slides.map((i, idx) => {
4134
+ imports.push(`import n${no} from '${slidePrefix}${idx + 1}.md'`);
4135
+ imports.push(`import { meta as f${no} } from '${slidePrefix}${idx + 1}.frontmatter'`);
4136
+ const route = `{ path: '${no}', name: 'page-${no}', component: n${no}, meta: f${no} }`;
4137
+ if (i.frontmatter?.routeAlias)
4138
+ redirects.push(`{ path: '${i.frontmatter?.routeAlias}', redirect: { path: '${no}' } }`);
4139
+ no += 1;
4140
+ return route;
3973
4141
  });
3974
- setups.push((md2) => md2.use(plugin));
3975
- } else {
3976
- setups.push((md2) => md2.use(markdownItPrism));
4142
+ const routesStr = `export const rawRoutes = [
4143
+ ${routes.join(",\n")}
4144
+ ].map(markRaw)`;
4145
+ const redirectsStr = `export const redirects = [
4146
+ ${redirects.join(",\n")}
4147
+ ].map(markRaw)`;
4148
+ return [...imports, routesStr, redirectsStr].join("\n");
3977
4149
  }
3978
- if (config.mdc)
3979
- setups.push((md2) => md2.use(Mdc));
3980
- const KatexOptions = await loadSetups(options.clientRoot, roots, "katex.ts", {}, { strict: false }, false);
3981
- return Markdown2({
3982
- include: [/\.md$/],
3983
- wrapperClasses: "",
3984
- headEnabled: false,
3985
- frontmatter: false,
3986
- escapeCodeTagInterpolation: false,
3987
- markdownItOptions: {
3988
- quotes: `""''`,
3989
- html: true,
3990
- xhtmlOut: true,
3991
- linkify: true,
3992
- ...mdOptions?.markdownItOptions
3993
- },
3994
- ...mdOptions,
3995
- markdownItSetup(md2) {
3996
- md2.use(mila2, {
3997
- attrs: {
3998
- target: "_blank",
3999
- rel: "noopener"
4000
- }
4001
- });
4002
- md2.use(mif);
4003
- md2.use(taskLists, { enabled: true, lineNumber: true, label: true });
4004
- md2.use(math_plugin, KatexOptions);
4005
- setups.forEach((i) => i(md2));
4006
- mdOptions?.markdownItSetup?.(md2);
4007
- },
4008
- transforms: {
4009
- before(code, id) {
4010
- if (id === entryPath)
4011
- return "";
4012
- const monaco = config.monaco === true || config.monaco === mode ? transformMarkdownMonaco : truncateMancoMark;
4013
- if (config.highlighter === "shiki")
4014
- code = transformMagicMove(code, shiki, shikiOptions);
4015
- code = transformSlotSugar(code);
4016
- code = transformSnippet(code, options, id);
4017
- code = transformMermaid(code);
4018
- code = transformPlantUml(code, config.plantUmlServer);
4019
- code = monaco(code);
4020
- code = transformHighlighter(code);
4021
- code = transformPageCSS(code, id);
4022
- code = transformKaTex(code);
4023
- return code;
4024
- }
4150
+ function getTitle() {
4151
+ if (isString(data.config.title)) {
4152
+ const tokens = md.parseInline(data.config.title, {});
4153
+ return stringifyMarkdownTokens(tokens);
4025
4154
  }
4026
- });
4155
+ return data.config.title;
4156
+ }
4157
+ function generateConfigs() {
4158
+ const config = {
4159
+ ...data.config,
4160
+ remote,
4161
+ title: getTitle()
4162
+ };
4163
+ if (isString(config.info))
4164
+ config.info = md.render(config.info);
4165
+ return `export default ${JSON.stringify(config)}`;
4166
+ }
4167
+ async function generateGlobalComponents(layer) {
4168
+ const components = roots.flatMap((root) => {
4169
+ if (layer === "top") {
4170
+ return [
4171
+ join4(root, "global.vue"),
4172
+ join4(root, "global-top.vue"),
4173
+ join4(root, "GlobalTop.vue")
4174
+ ];
4175
+ } else {
4176
+ return [
4177
+ join4(root, "global-bottom.vue"),
4178
+ join4(root, "GlobalBottom.vue")
4179
+ ];
4180
+ }
4181
+ }).filter((i) => fs5.existsSync(i));
4182
+ const imports = components.map((i, idx) => `import __n${idx} from '${toAtFS(i)}'`).join("\n");
4183
+ const render = components.map((i, idx) => `h(__n${idx})`).join(",");
4184
+ return `
4185
+ ${imports}
4186
+ import { h } from 'vue'
4187
+ export default {
4188
+ render() {
4189
+ return [${render}]
4190
+ }
4027
4191
  }
4028
- function transformKaTex(md2) {
4029
- return md2.replace(/^\$\$(?:\s*{([\d\w*,\|-]+)}\s*?({.*?})?\s*?)?\n([\s\S]+?)^\$\$/mg, (full, rangeStr = "", options = "", code) => {
4030
- const ranges = rangeStr.split(/\|/g).map((i) => i.trim());
4031
- code = code.trimEnd();
4032
- options = options.trim() || "{}";
4033
- return `<KaTexBlockWrapper v-bind="${options}" :ranges='${JSON.stringify(ranges)}'>
4034
-
4035
- $$
4036
- ${code}
4037
- $$
4038
- </KaTexBlockWrapper>
4039
4192
  `;
4040
- });
4041
- }
4042
- function transformMarkdownMonaco(md2) {
4043
- md2 = md2.replace(/^```(\w+?)\s*{monaco-diff}\s*?({.*?})?\s*?\n([\s\S]+?)^~~~\s*?\n([\s\S]+?)^```/mg, (full, lang = "ts", options = "{}", code, diff) => {
4044
- lang = lang.trim();
4045
- options = options.trim() || "{}";
4046
- const encoded = lz.compressToBase64(code);
4047
- const encodedDiff = lz.compressToBase64(diff);
4048
- return `<Monaco code-lz="${encoded}" diff-lz="${encodedDiff}" lang="${lang}" v-bind="${options}" />`;
4049
- });
4050
- md2 = md2.replace(/^```(\w+?)\s*{monaco}\s*?({.*?})?\s*?\n([\s\S]+?)^```/mg, (full, lang = "ts", options = "{}", code) => {
4051
- lang = lang.trim();
4052
- options = options.trim() || "{}";
4053
- const encoded = lz.compressToBase64(code);
4054
- return `<Monaco code-lz="${encoded}" lang="${lang}" v-bind="${options}" />`;
4055
- });
4056
- return md2;
4057
- }
4058
- function truncateMancoMark(md2) {
4059
- return md2.replace(/{monaco.*?}/g, "");
4193
+ }
4194
+ async function generateCustomNavControls() {
4195
+ const components = roots.flatMap((root) => {
4196
+ return [
4197
+ join4(root, "custom-nav-controls.vue"),
4198
+ join4(root, "CustomNavControls.vue")
4199
+ ];
4200
+ }).filter((i) => fs5.existsSync(i));
4201
+ const imports = components.map((i, idx) => `import __n${idx} from '${toAtFS(i)}'`).join("\n");
4202
+ const render = components.map((i, idx) => `h(__n${idx})`).join(",");
4203
+ return `
4204
+ ${imports}
4205
+ import { h } from 'vue'
4206
+ export default {
4207
+ render() {
4208
+ return [${render}]
4209
+ }
4060
4210
  }
4061
- function transformSlotSugar(md2) {
4062
- const lines = md2.split(/\r?\n/g);
4063
- let prevSlot = false;
4064
- const { isLineInsideCodeblocks } = getCodeBlocks(md2);
4065
- lines.forEach((line, idx) => {
4066
- if (isLineInsideCodeblocks(idx))
4067
- return;
4068
- const match = line.trimEnd().match(/^::\s*([\w\.\-\:]+)\s*::$/);
4069
- if (match) {
4070
- lines[idx] = `${prevSlot ? "\n\n</template>\n" : "\n"}<template v-slot:${match[1]}="slotProps">
4071
4211
  `;
4072
- prevSlot = true;
4212
+ }
4213
+ async function generteShikiBundle() {
4214
+ const options = await loadShikiSetups(clientRoot, roots);
4215
+ const langs = await resolveLangs(options.langs || ["javascript", "typescript", "html", "css"]);
4216
+ const resolvedThemeOptions = "themes" in options ? {
4217
+ themes: Object.fromEntries(await Promise.all(
4218
+ Object.entries(options.themes).map(async ([name, value]) => [name, await resolveTheme(value)])
4219
+ ))
4220
+ } : {
4221
+ theme: await resolveTheme(options.theme || "vitesse-dark")
4222
+ };
4223
+ const themes = resolvedThemeOptions.themes ? Object.values(resolvedThemeOptions.themes) : [resolvedThemeOptions.theme];
4224
+ const themeOptionsNames = resolvedThemeOptions.themes ? { themes: Object.fromEntries(Object.entries(resolvedThemeOptions.themes).map(([name, value]) => [name, typeof value === "string" ? value : value.name])) } : { theme: typeof resolvedThemeOptions.theme === "string" ? resolvedThemeOptions.theme : resolvedThemeOptions.theme.name };
4225
+ async function normalizeGetter(p) {
4226
+ return Promise.resolve(typeof p === "function" ? p() : p).then((r) => r.default || r);
4073
4227
  }
4074
- });
4075
- if (prevSlot)
4076
- lines[lines.length - 1] += "\n\n</template>";
4077
- return lines.join("\n");
4078
- }
4079
- var reMagicMoveBlock = /^````(?:md|markdown) magic-move(?:[ ]*?({.*?})?([^\n]*?))?\n([\s\S]+?)^````$/mg;
4080
- var reCodeBlock = /^```(\w+?)(?:\s*{([\d\w*,\|-]+)}\s*?({.*?})?(.*?))?\n([\s\S]+?)^```$/mg;
4081
- function transformMagicMove(md2, shiki2, shikiOptions2) {
4082
- return md2.replace(
4083
- reMagicMoveBlock,
4084
- (full, _options = "", _attrs = "", body) => {
4085
- if (!shiki2 || !shikiOptions2)
4086
- throw new Error("Shiki is required for Magic Move. You may need to set `highlighter: shiki` in your Slidev config.");
4087
- const matches = Array.from(body.matchAll(reCodeBlock));
4088
- if (!matches.length)
4089
- throw new Error("Magic Move block must contain at least one code block");
4090
- const langs = new Set(matches.map((i) => i[1]));
4091
- if (langs.size > 1)
4092
- throw new Error(`Magic Move block must contain code blocks with the same language, got ${Array.from(langs).join(", ")}`);
4093
- const lang = Array.from(langs)[0];
4094
- const magicMove = createMagicMoveMachine(
4095
- (code) => codeToKeyedTokens(shiki2, code, {
4096
- ...shikiOptions2,
4097
- lang
4098
- })
4099
- );
4100
- const steps = matches.map((i) => magicMove.commit((i[5] || "").trimEnd()));
4101
- const compressed = lz.compressToBase64(JSON.stringify(steps));
4102
- return `<ShikiMagicMove steps-lz="${compressed}" />`;
4228
+ async function resolveLangs(langs2) {
4229
+ return Array.from(new Set((await Promise.all(
4230
+ langs2.map(async (lang) => await normalizeGetter(lang).then((r) => Array.isArray(r) ? r : [r]))
4231
+ )).flat()));
4103
4232
  }
4104
- );
4105
- }
4106
- function transformHighlighter(md2) {
4107
- return md2.replace(
4108
- reCodeBlock,
4109
- (full, lang = "", rangeStr = "", options = "", attrs = "", code) => {
4110
- const ranges = rangeStr.split(/\|/g).map((i) => i.trim());
4111
- code = code.trimEnd();
4112
- options = options.trim() || "{}";
4113
- return `
4114
- <CodeBlockWrapper v-bind="${options}" :ranges='${JSON.stringify(ranges)}'>
4115
-
4116
- \`\`\`${lang}${attrs}
4117
- ${code}
4118
- \`\`\`
4119
-
4120
- </CodeBlockWrapper>`;
4233
+ async function resolveTheme(theme) {
4234
+ return typeof theme === "string" ? theme : await normalizeGetter(theme);
4121
4235
  }
4122
- );
4236
+ const langsInit = await Promise.all(
4237
+ langs.map(async (lang) => typeof lang === "string" ? `import('${await resolveUrl(`shiki/langs/${lang}.mjs`)}')` : JSON.stringify(lang))
4238
+ );
4239
+ const themesInit = await Promise.all(themes.map(async (theme) => typeof theme === "string" ? `import('${await resolveUrl(`shiki/themes/${theme}.mjs`)}')` : JSON.stringify(theme)));
4240
+ const langNames = langs.flatMap((lang) => typeof lang === "string" ? lang : lang.name);
4241
+ const lines = [];
4242
+ lines.push(
4243
+ `import { getHighlighterCore } from "${await resolveUrl("shiki/core")}"`,
4244
+ `export { shikiToMonaco } from "${await resolveUrl("@shikijs/monaco")}"`,
4245
+ `export const languages = ${JSON.stringify(langNames)}`,
4246
+ `export const themes = ${JSON.stringify(themeOptionsNames.themes || themeOptionsNames.theme)}`,
4247
+ "export const shiki = getHighlighterCore({",
4248
+ ` themes: [${themesInit.join(",")}],`,
4249
+ ` langs: [${langsInit.join(",")}],`,
4250
+ ` loadWasm: import('${await resolveUrl("shiki/wasm")}'),`,
4251
+ "})"
4252
+ );
4253
+ return lines.join("\n");
4254
+ }
4123
4255
  }
4124
- function getCodeBlocks(md2) {
4125
- const codeblocks = Array.from(md2.matchAll(/^```[\s\S]*?^```/mg)).map((m) => {
4126
- const start = m.index;
4127
- const end = m.index + m[0].length;
4128
- const startLine = md2.slice(0, start).match(/\n/g)?.length || 0;
4129
- const endLine = md2.slice(0, end).match(/\n/g)?.length || 0;
4130
- return [start, end, startLine, endLine];
4131
- });
4256
+
4257
+ // node/plugins/setupClient.ts
4258
+ import { existsSync as existsSync2 } from "node:fs";
4259
+ import { join as join5, resolve as resolve3 } from "node:path";
4260
+ import { slash as slash2, uniq as uniq2 } from "@antfu/utils";
4261
+ function createClientSetupPlugin({ themeRoots, addonRoots, userRoot, clientRoot }) {
4262
+ const setupEntry = slash2(resolve3(clientRoot, "setup"));
4132
4263
  return {
4133
- codeblocks,
4134
- isInsideCodeblocks(idx) {
4135
- return codeblocks.some(([s, e]) => s <= idx && idx <= e);
4136
- },
4137
- isLineInsideCodeblocks(line) {
4138
- return codeblocks.some(([, , s, e]) => s <= line && line <= e);
4264
+ name: "slidev:setup",
4265
+ enforce: "pre",
4266
+ async transform(code, id) {
4267
+ if (id.startsWith(setupEntry)) {
4268
+ let getInjections2 = function(isAwait = false, isChained = false) {
4269
+ return injections.join("\n").replace(/:AWAIT:/g, isAwait ? "await " : "").replace(/(,\s*)?:LAST:/g, isChained ? "$1injection_return" : "");
4270
+ };
4271
+ var getInjections = getInjections2;
4272
+ const name = id.slice(setupEntry.length + 1).replace(/\?.*$/, "");
4273
+ const imports = [];
4274
+ const injections = [];
4275
+ const setups = uniq2([
4276
+ ...themeRoots,
4277
+ ...addonRoots,
4278
+ userRoot
4279
+ ]).map((i) => join5(i, "setup", name));
4280
+ setups.forEach((path2, idx) => {
4281
+ if (!existsSync2(path2))
4282
+ return;
4283
+ imports.push(`import __n${idx} from '${toAtFS(path2)}'`);
4284
+ let fn = `:AWAIT:__n${idx}`;
4285
+ if (/\binjection_return\b/g.test(code))
4286
+ fn = `injection_return = ${fn}`;
4287
+ if (/\binjection_arg\b/g.test(code)) {
4288
+ fn += "(";
4289
+ const matches = Array.from(code.matchAll(/\binjection_arg(_\d+)?\b/g));
4290
+ const dedupedMatches = Array.from(new Set(matches.map((m) => m[0])));
4291
+ fn += dedupedMatches.join(", ");
4292
+ fn += ", :LAST:)";
4293
+ } else {
4294
+ fn += "(:LAST:)";
4295
+ }
4296
+ injections.push(
4297
+ `// ${path2}`,
4298
+ fn
4299
+ );
4300
+ });
4301
+ code = code.replace("/* __imports__ */", imports.join("\n"));
4302
+ code = code.replace("/* __injections__ */", getInjections2());
4303
+ code = code.replace("/* __async_injections__ */", getInjections2(true));
4304
+ code = code.replace("/* __chained_injections__ */", getInjections2(false, true));
4305
+ code = code.replace("/* __chained_async_injections__ */", getInjections2(true, true));
4306
+ return code;
4307
+ }
4308
+ return null;
4139
4309
  }
4140
4310
  };
4141
4311
  }
4142
- function transformPageCSS(md2, id) {
4143
- const page = id.match(/(\d+)\.md$/)?.[1];
4144
- if (!page)
4145
- return md2;
4146
- const { isInsideCodeblocks } = getCodeBlocks(md2);
4147
- const result = md2.replace(
4148
- /(\n<style[^>]*?>)([\s\S]+?)(<\/style>)/g,
4149
- (full, start, css, end, index) => {
4150
- if (index < 0 || isInsideCodeblocks(index))
4151
- return full;
4152
- if (!start.includes("scoped"))
4153
- start = start.replace("<style", "<style scoped");
4154
- return `${start}
4155
- ${css}${end}`;
4156
- }
4157
- );
4158
- return result;
4159
- }
4160
- function transformMermaid(md2) {
4161
- return md2.replace(/^```mermaid\s*?({.*?})?\n([\s\S]+?)\n```/mg, (full, options = "", code = "") => {
4162
- code = code.trim();
4163
- options = options.trim() || "{}";
4164
- const encoded = lz.compressToBase64(code);
4165
- return `<Mermaid code-lz="${encoded}" v-bind="${options}" />`;
4166
- });
4167
- }
4168
- function transformPlantUml(md2, server) {
4169
- return md2.replace(/^```plantuml\s*?({.*?})?\n([\s\S]+?)\n```/mg, (full, options = "", content = "") => {
4170
- const code = encodePlantUml(content.trim());
4171
- options = options.trim() || "{}";
4172
- return `<PlantUml :code="'${code}'" :server="'${server}'" v-bind="${options}" />`;
4173
- });
4174
- }
4175
- function escapeVueInCode(md2) {
4176
- return md2.replace(/{{/g, "&lbrace;&lbrace;");
4177
- }
4178
- async function loadShikiSetups(clientRoot, roots) {
4179
- const result = await loadSetups(
4180
- clientRoot,
4181
- roots,
4182
- "shiki.ts",
4183
- {
4184
- /** @deprecated */
4185
- async loadTheme(path2) {
4186
- console.warn("[slidev] `loadTheme` in `setup/shiki.ts` is deprecated. Pass directly the theme name it's supported by Shiki. For custom themes, load it manually via `JSON.parse(fs.readFileSync(path, 'utf-8'))` and pass the raw JSON object instead.");
4187
- return JSON.parse(await fs6.readFile(path2, "utf-8"));
4188
- }
4189
- },
4190
- {},
4191
- false
4192
- );
4193
- if ("theme" in result && "themes" in result)
4194
- delete result.theme;
4195
- if (result.theme && typeof result.theme !== "string" && !result.theme.name && !result.theme.tokenColors) {
4196
- result.themes = result.theme;
4197
- delete result.theme;
4198
- }
4199
- if (!result.theme && !result.themes) {
4200
- result.themes = {
4201
- dark: "vitesse-dark",
4202
- light: "vitesse-light"
4203
- };
4204
- }
4205
- if (result.themes)
4206
- result.defaultColor = false;
4207
- return result;
4208
- }
4209
4312
 
4210
4313
  // node/plugins/patchTransform.ts
4211
4314
  import { objectEntries } from "@antfu/utils";
@@ -4229,6 +4332,72 @@ function createFixPlugins(options) {
4229
4332
  ];
4230
4333
  }
4231
4334
 
4335
+ // node/plugins/monacoTypes.ts
4336
+ import fs6 from "node:fs/promises";
4337
+ import { dirname as dirname2, resolve as resolve4 } from "node:path";
4338
+ import { slash as slash3 } from "@antfu/utils";
4339
+ import fg3 from "fast-glob";
4340
+ import { findDepPkgJsonPath } from "vitefu";
4341
+ function createMonacoTypesLoader({ userRoot }) {
4342
+ const resolvedDepsMap = {};
4343
+ return {
4344
+ name: "slidev:monaco-types-loader",
4345
+ resolveId(id) {
4346
+ if (id.startsWith("/@slidev-monaco-types/"))
4347
+ return id;
4348
+ return null;
4349
+ },
4350
+ async load(id) {
4351
+ const matchResolve = id.match(/^\/\@slidev-monaco-types\/resolve\/(.*?)(?:\?importer=(.*))?$/);
4352
+ if (matchResolve) {
4353
+ const [_, pkg, importer = userRoot] = matchResolve;
4354
+ const resolvedDeps = resolvedDepsMap[importer] ??= /* @__PURE__ */ new Set();
4355
+ if (resolvedDeps.has(pkg))
4356
+ return "";
4357
+ resolvedDeps.add(pkg);
4358
+ const pkgJsonPath = await findDepPkgJsonPath(pkg, importer);
4359
+ if (!pkgJsonPath)
4360
+ throw new Error(`Package "${pkg}" not found in "${importer}"`);
4361
+ const root = dirname2(pkgJsonPath);
4362
+ const pkgJson = JSON.parse(await fs6.readFile(pkgJsonPath, "utf-8"));
4363
+ const deps = pkgJson.dependencies ?? {};
4364
+ return [
4365
+ `import "/@slidev-monaco-types/load/${slash3(root)}&name=${pkgJson.name}"`,
4366
+ ...Object.keys(deps).map((dep) => `import "/@slidev-monaco-types/resolve/${dep}?importer=${slash3(root)}"`)
4367
+ ].join("\n");
4368
+ }
4369
+ const matchLoad = id.match(/^\/\@slidev-monaco-types\/load(\/.*?)&name=(.*)$/);
4370
+ if (matchLoad) {
4371
+ const [_, root, name] = matchLoad;
4372
+ const files = await fg3(
4373
+ [
4374
+ "**/*.d.ts",
4375
+ "**/*.d.mts",
4376
+ "**/*.d.cts",
4377
+ "package.json"
4378
+ ],
4379
+ {
4380
+ cwd: root,
4381
+ followSymbolicLinks: true
4382
+ }
4383
+ );
4384
+ if (!files.length)
4385
+ return "";
4386
+ return [
4387
+ "import * as monaco from 'monaco-editor'",
4388
+ "async function addFile(mod, subPath) {",
4389
+ " const code = (await mod).default",
4390
+ ` const path = ${JSON.stringify(`/node_modules/${name}/`)} + subPath`,
4391
+ ' monaco.languages.typescript.typescriptDefaults.addExtraLib(code, "file://" + path)',
4392
+ ' monaco.editor.createModel(code, "javascript", monaco.Uri.file(path))',
4393
+ "}",
4394
+ ...files.map((file) => `addFile(import(${JSON.stringify(`${toAtFS(resolve4(root, file))}?raw`)}), ${JSON.stringify(file)})`)
4395
+ ].join("\n");
4396
+ }
4397
+ }
4398
+ };
4399
+ }
4400
+
4232
4401
  // node/plugins/preset.ts
4233
4402
  var customElements = /* @__PURE__ */ new Set([
4234
4403
  // katex
@@ -4292,7 +4461,7 @@ async function ViteSlidevPlugin(options, pluginOptions, serverOptions = {}) {
4292
4461
  const VueJsxPlugin = VueJsx(vuejsxOptions);
4293
4462
  const MarkdownPlugin = await createMarkdownPlugin(options, pluginOptions);
4294
4463
  const drawingData = await loadDrawings(options);
4295
- const publicRoots = [...themeRoots, ...addonRoots].map((i) => join7(i, "public")).filter(existsSync3);
4464
+ const publicRoots = [...themeRoots, ...addonRoots].map((i) => join6(i, "public")).filter(existsSync3);
4296
4465
  const plugins = [
4297
4466
  MarkdownPlugin,
4298
4467
  VueJsxPlugin,
@@ -4301,11 +4470,11 @@ async function ViteSlidevPlugin(options, pluginOptions, serverOptions = {}) {
4301
4470
  Components({
4302
4471
  extensions: ["vue", "md", "js", "ts", "jsx", "tsx"],
4303
4472
  dirs: [
4304
- join7(options.clientRoot, "builtin"),
4305
- ...roots.map((i) => join7(i, "components")),
4473
+ join6(options.clientRoot, "builtin"),
4474
+ ...roots.map((i) => join6(i, "components")),
4306
4475
  "src/components",
4307
4476
  "components",
4308
- join7(process3.cwd(), "components")
4477
+ join6(process2.cwd(), "components")
4309
4478
  ],
4310
4479
  include: [/\.vue$/, /\.vue\?vue/, /\.vue\?v=/, /\.md$/, /\.md\?vue/],
4311
4480
  exclude: [],
@@ -4336,7 +4505,7 @@ async function ViteSlidevPlugin(options, pluginOptions, serverOptions = {}) {
4336
4505
  ...remoteAssetsOptions
4337
4506
  })) : null,
4338
4507
  ServerRef({
4339
- debug: process3.env.NODE_ENV === "development",
4508
+ debug: process2.env.NODE_ENV === "development",
4340
4509
  state: {
4341
4510
  sync: false,
4342
4511
  nav: {
@@ -4356,7 +4525,7 @@ async function ViteSlidevPlugin(options, pluginOptions, serverOptions = {}) {
4356
4525
  }),
4357
4526
  createConfigPlugin(options),
4358
4527
  createClientSetupPlugin(options),
4359
- createMonacoTypesLoader(),
4528
+ createMonacoTypesLoader(options),
4360
4529
  createFixPlugins(options),
4361
4530
  publicRoots.length ? import("vite-plugin-static-copy").then((r) => r.viteStaticCopy({
4362
4531
  silent: true,