import { parseAspectRatio } from "./chunk-47YLTX76.mjs"; // src/core.ts import { ensurePrefix } from "@antfu/utils"; import YAML from "yaml"; // src/config.ts import { toArray, uniq } from "@antfu/utils"; function getDefaultConfig() { return { theme: "default", title: "Slidev", titleTemplate: "%s - Slidev", addons: [], remoteAssets: false, monaco: true, monacoTypesSource: "local", monacoTypesAdditionalPackages: [], monacoTypesIgnorePackages: [], monacoRunAdditionalDeps: [], download: false, export: {}, info: false, highlighter: "shiki", twoslash: true, lineNumbers: false, colorSchema: "auto", routerMode: "history", aspectRatio: 16 / 9, canvasWidth: 980, exportFilename: "", selectable: false, themeConfig: {}, fonts: {}, favicon: "https://cdn.jsdelivr.net/gh/slidevjs/slidev/assets/favicon.png", drawings: {}, plantUmlServer: "https://www.plantuml.com/plantuml", codeCopy: true, author: "", record: "dev", css: "unocss", presenter: true, browserExporter: "dev", htmlAttrs: {}, transition: null, editor: true, contextMenu: null, overviewSnapshots: false, wakeLock: true, remote: false, mdc: false }; } function resolveConfig(headmatter, themeMeta = {}, filepath, verify = false) { const themeHightlighter = ["prism", "shiki", "shikiji"].includes(themeMeta.highlighter || "") ? themeMeta.highlighter : void 0; const themeColorSchema = ["light", "dark"].includes(themeMeta.colorSchema || "") ? themeMeta.colorSchema : void 0; const defaultConfig = getDefaultConfig(); const config = { ...defaultConfig, highlighter: themeHightlighter || defaultConfig.highlighter, colorSchema: themeColorSchema || defaultConfig.colorSchema, ...themeMeta.defaults, ...headmatter.config, ...headmatter, fonts: resolveFonts({ ...themeMeta.defaults?.fonts, ...headmatter.config?.fonts, ...headmatter?.fonts }), drawings: resolveDrawings(headmatter.drawings, filepath), htmlAttrs: { ...themeMeta.defaults?.htmlAttrs, ...headmatter.config?.htmlAttrs, ...headmatter?.htmlAttrs } }; if (config.highlighter === "shikiji") { console.warn(`[slidev] "shikiji" is merged back to "shiki", you can safely change it "highlighter: shiki"`); config.highlighter = "shiki"; } if (config.highlighter === "prism") throw new Error(`[slidev] "prism" support has been dropped. Please use "highlighter: shiki" instead`); if (config.colorSchema !== "dark" && config.colorSchema !== "light") config.colorSchema = "auto"; if (themeColorSchema && config.colorSchema === "auto") config.colorSchema = themeColorSchema; config.aspectRatio = parseAspectRatio(config.aspectRatio); if (verify) verifyConfig(config, themeMeta); return config; } function verifyConfig(config, themeMeta = {}, warn = (v) => console.warn(`[slidev] ${v}`)) { const themeHightlighter = themeMeta.highlighter === "shiki" ? themeMeta.highlighter : void 0; const themeColorSchema = ["light", "dark"].includes(themeMeta.colorSchema || "") ? themeMeta.colorSchema : void 0; if (themeColorSchema && config.colorSchema !== themeColorSchema) warn(`Color schema "${config.colorSchema}" does not supported by the theme`); if (themeHightlighter && config.highlighter !== themeHightlighter) warn(`Syntax highlighter "${config.highlighter}" does not supported by the theme`); if (config.css !== "unocss") { warn(`Unsupported Atomic CSS engine "${config.css}", fallback to UnoCSS`); config.css = "unocss"; } } function resolveFonts(fonts = {}) { const { fallbacks = true, italic = false, provider = "google" } = fonts; let sans = toArray(fonts.sans).flatMap((i) => i.split(/,\s*/g)).map((i) => i.trim()); let serif = toArray(fonts.serif).flatMap((i) => i.split(/,\s*/g)).map((i) => i.trim()); let mono = toArray(fonts.mono).flatMap((i) => i.split(/,\s*/g)).map((i) => i.trim()); const weights = toArray(fonts.weights || "200,400,600").flatMap((i) => i.toString().split(/,\s*/g)).map((i) => i.trim()); const custom = toArray(fonts.custom).flatMap((i) => i.split(/,\s*/g)).map((i) => i.trim()); const local = toArray(fonts.local).flatMap((i) => i.split(/,\s*/g)).map((i) => i.trim()); const webfonts = fonts.webfonts ? fonts.webfonts : fallbacks ? uniq([...sans, ...serif, ...mono, ...custom]) : []; webfonts.filter((i) => local.includes(i)); function toQuoted(font) { if (/^(['"]).*\1$/.test(font)) return font; return `"${font}"`; } if (fallbacks) { sans = uniq([ ...sans.map(toQuoted), "ui-sans-serif", "system-ui", "-apple-system", "BlinkMacSystemFont", '"Segoe UI"', "Roboto", '"Helvetica Neue"', "Arial", '"Noto Sans"', "sans-serif", '"Apple Color Emoji"', '"Segoe UI Emoji"', '"Segoe UI Symbol"', '"Noto Color Emoji"' ]); serif = uniq([ ...serif.map(toQuoted), "ui-serif", "Georgia", "Cambria", '"Times New Roman"', "Times", "serif" ]); mono = uniq([ ...mono.map(toQuoted), "ui-monospace", "SFMono-Regular", "Menlo", "Monaco", "Consolas", '"Liberation Mono"', '"Courier New"', "monospace" ]); } return { sans, serif, mono, webfonts, provider, local, italic, weights }; } function resolveDrawings(options = {}, filepath) { const { enabled = true, persist = false, presenterOnly = false, syncAll = true } = options; const persistPath = typeof persist === "string" ? persist : persist ? `.slidev/drawings${filepath ? `/${filepath.match(/([^\\/]+?)(\.\w+)?$/)?.[1]}` : ""}` : false; return { enabled, persist: persistPath, presenterOnly, syncAll }; } // src/core.ts function stringify(data) { return `${data.slides.map(stringifySlide).join("\n").trim()} `; } function stringifySlide(data, idx = 0) { return data.raw.startsWith("---") || idx === 0 ? data.raw : `--- ${ensurePrefix("\n", data.raw)}`; } function prettifySlide(data) { const trimed = data.content.trim(); data.content = trimed ? ` ${data.content.trim()} ` : ""; data.raw = data.frontmatterDoc?.contents ? data.frontmatterStyle === "yaml" ? `\`\`\`yaml ${data.frontmatterDoc.toString().trim()} \`\`\` ${data.content}` : `--- ${data.frontmatterDoc.toString().trim()} --- ${data.content}` : data.content; if (data.note) data.raw += ` `; return data; } function prettify(data) { data.slides.forEach(prettifySlide); return data; } function matter(code, options) { let type; let raw; let content = code.replace(/^---.*\r?\n([\s\S]*?)---/, (_, f) => { type = "frontmatter"; raw = f; return ""; }); if (type !== "frontmatter") { content = content.replace(/^\s*```ya?ml([\s\S]*?)```/, (_, f) => { type = "yaml"; raw = f; return ""; }); } const doc = raw && !options.noParseYAML ? YAML.parseDocument(raw) : void 0; return { type, raw, doc, data: doc?.toJSON(), content }; } function detectFeatures(code) { return { katex: !!code.match(/\$.*?\$/) || !!code.match(/\$\$/), monaco: code.match(/\{monaco.*\}/) ? scanMonacoReferencedMods(code) : false, tweet: !!code.match(//g)); if (comments.length) { const last = comments[comments.length - 1]; if (last.index !== void 0 && last.index + last[0].length >= content.length) { note = last[1].trim(); content = content.slice(0, last.index).trim(); } } let title; let level; if (frontmatter.title || frontmatter.name) { title = frontmatter.title || frontmatter.name; } else { const match = content.match(/^(#+) (.*)$/m); title = match?.[2]?.trim(); level = match?.[1]?.length; } if (frontmatter.level) level = frontmatter.level || 1; return { raw, title, level, revision, content, frontmatter, frontmatterStyle: matterResult.type, frontmatterDoc: matterResult.doc, frontmatterRaw: matterResult.raw, note }; } async function parse(markdown, filepath, extensions, options = {}) { const lines = markdown.split(options.preserveCR ? "\n" : /\r?\n/g); const slides = []; let start = 0; let contentStart = 0; async function slice(end) { if (start === end) return; const raw = lines.slice(start, end).join("\n"); const slide = { ...parseSlide(raw, options), filepath, index: slides.length, start, contentStart, end }; if (extensions) { for (const e of extensions) { if (e.transformSlide) { const newContent = await e.transformSlide(slide.content, slide.frontmatter); if (newContent !== void 0) slide.content = newContent; } } } slides.push(slide); start = end + 1; contentStart = end + 1; } if (extensions) { for (const e of extensions) { if (e.transformRawLines) await e.transformRawLines(lines); } } for (let i = 0; i < lines.length; i++) { const line = lines[i].trimEnd(); if (line.startsWith("---")) { await slice(i); const next = lines[i + 1]; if (line[3] !== "-" && next?.trim()) { start = i; for (i += 1; i < lines.length; i++) { if (lines[i].trimEnd() === "---") break; } contentStart = i + 1; } } else if (line.trimStart().startsWith("```")) { const codeBlockLevel = line.match(/^\s*`+/)[0]; let j = i + 1; for (; j < lines.length; j++) { if (lines[j].startsWith(codeBlockLevel)) break; } if (j !== lines.length) i = j; } } if (start <= lines.length - 1) await slice(lines.length); return { filepath, raw: markdown, slides }; } function parseSync(markdown, filepath, options = {}) { const lines = markdown.split(options.preserveCR ? "\n" : /\r?\n/g); const slides = []; let start = 0; let contentStart = 0; function slice(end) { if (start === end) return; const raw = lines.slice(start, end).join("\n"); const slide = { ...parseSlide(raw, options), filepath, index: slides.length, start, contentStart, end }; slides.push(slide); start = end + 1; contentStart = end + 1; } for (let i = 0; i < lines.length; i++) { const line = lines[i].trimEnd(); if (line.startsWith("---")) { slice(i); const next = lines[i + 1]; if (line[3] !== "-" && next?.trim()) { start = i; for (i += 1; i < lines.length; i++) { if (lines[i].trimEnd() === "---") break; } contentStart = i + 1; } } else if (line.trimStart().startsWith("```")) { const codeBlockLevel = line.match(/^\s*`+/)[0]; let j = i + 1; for (; j < lines.length; j++) { if (lines[j].startsWith(codeBlockLevel)) break; } if (j !== lines.length) i = j; } } if (start <= lines.length - 1) slice(lines.length); return { filepath, raw: markdown, slides }; } function scanMonacoReferencedMods(md) { const types = /* @__PURE__ */ new Set(); const deps = /* @__PURE__ */ new Set(); md.replace( /^```(\w+)\s*\{monaco([^}]*)\}\s*(\S[\s\S]*?)^```/gm, (full, lang = "ts", kind, code) => { lang = lang.trim(); const isDep = kind === "-run"; if (["js", "javascript", "ts", "typescript"].includes(lang)) { for (const [, , specifier] of code.matchAll(/\s+from\s+(["'])([/.\w@-]+)\1/g)) { if (specifier) { if (!"./".includes(specifier)) types.add(specifier); if (isDep) deps.add(specifier); } } } return ""; } ); return { types: Array.from(types), deps: Array.from(deps) }; } function hash(str) { let hash2 = 0; for (let i = 0; i < str.length; i++) { hash2 = (hash2 << 5) - hash2 + str.charCodeAt(i); hash2 |= 0; } return hash2.toString(36).slice(0, 12); } export { getDefaultConfig, resolveConfig, verifyConfig, resolveFonts, stringify, stringifySlide, prettifySlide, prettify, detectFeatures, parseSlide, parse, parseSync };