From 73f5b4b8f4a72018662b17f0c3088334ed29e9eb Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Sun, 21 Jul 2024 01:57:52 +0800 Subject: [PATCH] feat(vscode): add Slidev language server (#1743) Co-authored-by: _Kerman Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Anthony Fu Co-authored-by: Anthony Fu --- .gitignore | 1 + .npmrc | 1 + .vscode/launch.json | 3 +- .vscode/settings.json | 6 +- eslint.config.js | 1 + package.json | 1 + packages/parser/src/config.ts | 6 +- packages/parser/src/core.ts | 88 ++- packages/types/src/config.ts | 160 ++--- packages/vscode/.vscodeignore | 3 + packages/vscode/language-server/bin.ts | 9 + .../vscode/language-server/import-meta-url.ts | 2 + packages/vscode/language-server/index.ts | 43 ++ .../vscode/language-server/languagePlugin.ts | 90 +++ .../vscode/language-server/prettierService.ts | 11 + packages/vscode/language-server/protocol.ts | 1 + .../language-server/volar-service-yaml.ts | 199 ++++++ packages/vscode/package.json | 108 ++- packages/vscode/schema/headmatter.json | 619 ++++++++++++++++++ packages/vscode/scripts/schema.ts | 12 + packages/vscode/src/index.ts | 6 + packages/vscode/src/languageClient.ts | 68 ++ packages/vscode/src/projects.ts | 1 + .../vscode/syntaxes/.vscode/settings.json | 6 + packages/vscode/syntaxes/codeblock-patch.ts | 52 ++ packages/vscode/syntaxes/codeblock.json | 58 ++ .../syntaxes/language-configuration.json | 57 ++ packages/vscode/syntaxes/markdown.json | 14 + packages/vscode/syntaxes/slidev.example.md | 68 ++ .../vscode/syntaxes/slidev.tmLanguage.json | 112 ++++ packages/vscode/syntaxes/tsconfig.json | 10 + packages/vscode/tsup.config.ts | 34 +- pnpm-lock.yaml | 344 +++++++++- test/__snapshots__/parser.test.ts.snap | 50 +- 34 files changed, 2116 insertions(+), 128 deletions(-) create mode 100644 packages/vscode/language-server/bin.ts create mode 100644 packages/vscode/language-server/import-meta-url.ts create mode 100644 packages/vscode/language-server/index.ts create mode 100644 packages/vscode/language-server/languagePlugin.ts create mode 100644 packages/vscode/language-server/prettierService.ts create mode 100644 packages/vscode/language-server/protocol.ts create mode 100644 packages/vscode/language-server/volar-service-yaml.ts create mode 100644 packages/vscode/schema/headmatter.json create mode 100644 packages/vscode/scripts/schema.ts create mode 100644 packages/vscode/src/languageClient.ts create mode 100644 packages/vscode/syntaxes/.vscode/settings.json create mode 100644 packages/vscode/syntaxes/codeblock-patch.ts create mode 100644 packages/vscode/syntaxes/codeblock.json create mode 100644 packages/vscode/syntaxes/language-configuration.json create mode 100644 packages/vscode/syntaxes/markdown.json create mode 100644 packages/vscode/syntaxes/slidev.example.md create mode 100644 packages/vscode/syntaxes/slidev.tmLanguage.json create mode 100644 packages/vscode/syntaxes/tsconfig.json diff --git a/.gitignore b/.gitignore index 3e84df1943..a1e7a1492d 100644 --- a/.gitignore +++ b/.gitignore @@ -20,5 +20,6 @@ packages/create-app/template/pages packages/create-app/template/slides.md packages/create-app/template/snippets packages/slidev/README.md +packages/vscode/syntaxes/codeblock-patch.json slides-export.md *slides-export.pptx diff --git a/.npmrc b/.npmrc index 84342cc2de..b6a607cf6c 100644 --- a/.npmrc +++ b/.npmrc @@ -1,3 +1,4 @@ shamefully-hoist=true ignore-workspace-root-check=true strict-peer-dependencies=false +link-workspace-packages=true diff --git a/.vscode/launch.json b/.vscode/launch.json index d8aac753e2..cb05a7f180 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -6,7 +6,8 @@ "type": "extensionHost", "request": "launch", "args": [ - "--extensionDevelopmentPath=${workspaceFolder}/packages/vscode" + "--extensionDevelopmentPath=${workspaceFolder}/packages/vscode", + "--folder-uri=${workspaceRoot}/packages/vscode/syntaxes" ], "outFiles": [ "${workspaceFolder}/out/**/*.js" diff --git a/.vscode/settings.json b/.vscode/settings.json index b75f8166c1..79309d59d9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -46,5 +46,9 @@ "jsonc", "yaml" ], - "vitest.disableWorkspaceWarning": true + "vitest.disableWorkspaceWarning": true, + "slidev.include": [ + "**/slides.md", + "packages/vscode/syntax/slidev.example.md" + ] } diff --git a/eslint.config.js b/eslint.config.js index 3892ce8bd2..bd4fcbe640 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -17,6 +17,7 @@ export default antfu( '**/template.md', '**/example.md', 'test/fixtures/markdown/**/*.md', + 'packages/vscode/syntaxes/slidev.example.md', ], }, }, diff --git a/package.json b/package.json index df010e4f32..64d99b5861 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "shiki": "^1.10.2", "simple-git-hooks": "^2.11.1", "taze": "^0.14.2", + "ts-json-schema-generator": "^2.3.0", "tsup": "^8.1.0", "typescript": "^5.5.3", "vite": "^5.3.3", diff --git a/packages/parser/src/config.ts b/packages/parser/src/config.ts index 2a68b749d0..9db7f59c8d 100644 --- a/packages/parser/src/config.ts +++ b/packages/parser/src/config.ts @@ -36,10 +36,12 @@ export function getDefaultConfig(): SlidevConfig { css: 'unocss', presenter: true, htmlAttrs: {}, - transition: undefined, + transition: null, editor: true, - contextMenu: undefined, + contextMenu: null, wakeLock: true, + remote: false, + mdc: false, } } diff --git a/packages/parser/src/core.ts b/packages/parser/src/core.ts index 395e37bbe3..aa6fbcb9a3 100644 --- a/packages/parser/src/core.ts +++ b/packages/parser/src/core.ts @@ -2,6 +2,11 @@ import YAML from 'yaml' import { ensurePrefix } from '@antfu/utils' import type { FrontmatterStyle, SlidevDetectedFeatures, SlidevMarkdown, SlidevPreparserExtension, SourceSlideInfo } from '@slidev/types' +export interface SlidevParserOptions { + noParseYAML?: boolean + preserveCR?: boolean +} + export function stringify(data: SlidevMarkdown) { return `${data.slides.map(stringifySlide).join('\n').trim()}\n` } @@ -30,7 +35,7 @@ export function prettify(data: SlidevMarkdown) { return data } -function matter(code: string) { +function matter(code: string, options: SlidevParserOptions) { let type: FrontmatterStyle | undefined let raw: string | undefined @@ -50,13 +55,13 @@ function matter(code: string) { }) } - const doc = YAML.parseDocument(raw || '') + const doc = raw && !options.noParseYAML ? YAML.parseDocument(raw) : undefined return { type, raw, doc, - data: doc.toJSON(), + data: doc?.toJSON(), content, } } @@ -70,8 +75,8 @@ export function detectFeatures(code: string): SlidevDetectedFeatures { } } -export function parseSlide(raw: string): Omit { - const matterResult = matter(raw) +export function parseSlide(raw: string, options: SlidevParserOptions = {}): Omit { + const matterResult = matter(raw, options) let note: string | undefined const frontmatter = matterResult.data || {} let content = matterResult.content.trim() @@ -115,8 +120,9 @@ export async function parse( markdown: string, filepath: string, extensions?: SlidevPreparserExtension[], + options: SlidevParserOptions = {}, ): Promise { - const lines = markdown.split(/\r?\n/g) + const lines = markdown.split(options.preserveCR ? '\n' : /\r?\n/g) const slides: SourceSlideInfo[] = [] let start = 0 @@ -127,7 +133,7 @@ export async function parse( return const raw = lines.slice(start, end).join('\n') const slide: SourceSlideInfo = { - ...parseSlide(raw), + ...parseSlide(raw, options), filepath, index: slides.length, start, @@ -195,6 +201,74 @@ export async function parse( } } +export function parseSync( + markdown: string, + filepath: string, + options: SlidevParserOptions = {}, +): SlidevMarkdown { + const lines = markdown.split(options.preserveCR ? '\n' : /\r?\n/g) + const slides: SourceSlideInfo[] = [] + + let start = 0 + let contentStart = 0 + + function slice(end: number) { + if (start === end) + return + const raw = lines.slice(start, end).join('\n') + const slide: SourceSlideInfo = { + ...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] + // found frontmatter, skip next dash + if (line[3] !== '-' && next?.trim()) { + start = i + for (i += 1; i < lines.length; i++) { + if (lines[i].trimEnd() === '---') + break + } + contentStart = i + 1 + } + } + // skip code block + 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 + } + // Update i only when code block ends + if (j !== lines.length) + i = j + } + } + + if (start <= lines.length - 1) + slice(lines.length) + + return { + filepath, + raw: markdown, + slides, + } +} + function scanMonacoReferencedMods(md: string) { const types = new Set() const deps = new Set() diff --git a/packages/types/src/config.ts b/packages/types/src/config.ts index c7bc4223cc..de4dbd4fa1 100644 --- a/packages/types/src/config.ts +++ b/packages/types/src/config.ts @@ -2,152 +2,108 @@ import type { TransitionGroupProps } from 'vue' import type { ExportArgs } from './cli' import type { SlidevThemeConfig } from './types' -export interface SlidevConfig { - title: string +export interface Headmatter { + /** + * Title of the slides + */ + title?: string /** * String template to compose title * * @example "%s - Slidev" - to suffix " - Slidev" to all pages * @default '%s - Slidev' */ - titleTemplate: string + titleTemplate?: string /** * Theme to use for the slides * * @see https://sli.dev/themes/use.html * @default 'default' */ - theme: string + theme?: string /** * List of Slidev addons * * @default [] */ - addons: string[] + addons?: string[] /** * Download remote assets in local using vite-plugin-remote-assets * * @default false */ - remoteAssets: boolean | 'dev' | 'build' - /** - * Enable Monaco - * - * @see https://sli.dev/custom/config-monaco.html - * @default true - */ - monaco: boolean | 'dev' | 'build' - /** - * Where to load monaco types from - * - * - `cdn` - load from CDN with `@typescript/ata` - * - `local` - load from local node_modules - * - * @default 'local' - */ - monacoTypesSource: 'cdn' | 'local' | 'none' - /** - * Additional node packages to load as monaco types - * - * @default [] - */ - monacoTypesAdditionalPackages: string[] - /** - * Packages to ignore when loading monaco types - * - * @default [] - */ - monacoTypesIgnorePackages: string[] - /** - * Additional local modules to load as dependencies of monaco runnable - * - * @default [] - */ - monacoRunAdditionalDeps: string[] + remoteAssets?: boolean | 'dev' | 'build' /** * Show a download button in the SPA build, * could also be a link to custom pdf * * @default false */ - download: boolean | string - /** - * Options for export - * - * @default {} - */ - export: ResolvedExportOptions + download?: boolean | string /** * Show a copy button in code blocks * * @default true */ - codeCopy: boolean + codeCopy?: boolean /** * Information shows on the built SPA * Can be a markdown string * * @default false */ - info: string | boolean + info?: string | boolean /** * Prefer highlighter * * @see https://sli.dev/custom/config-highlighter.html * @default shiki */ - highlighter: 'shiki' | 'prism' + highlighter?: 'shiki' | 'prism' /** * Enable Twoslash * * @default true */ - twoslash: boolean | 'dev' | 'build' + twoslash?: boolean | 'dev' | 'build' /** * Show line numbers in code blocks * * @default false */ - lineNumbers: boolean + lineNumbers?: boolean /** * Force slides color schema * * @default 'auto' */ - colorSchema: 'dark' | 'light' | 'all' | 'auto' + colorSchema?: 'dark' | 'light' | 'all' | 'auto' /** * Router mode for vue-router * * @default 'history' */ - routerMode: 'hash' | 'history' + routerMode?: 'hash' | 'history' /** * Aspect ratio for slides * should be like `16/9` or `1:1` * * @default '16/9' */ - aspectRatio: number + aspectRatio?: number /** * The actual width for slides canvas. * unit in px. * * @default '980' */ - canvasWidth: number - /** - * Force the filename used when exporting the presentation. - * The extension, e.g. .pdf, gets automatically added. - * - * @default '' - */ - exportFilename: string | null + canvasWidth?: number /** * Controls whether texts in slides are selectable * * @default true */ - selectable: boolean + selectable?: boolean /** * Configure for themes, will inject intro root styles as * `--slidev-theme-x` for attribute `x` @@ -157,37 +113,37 @@ export interface SlidevConfig { * * @default {} */ - themeConfig: SlidevThemeConfig + themeConfig?: SlidevThemeConfig /** * Configure fonts for the slides and app * * @default {} */ - fonts: ResolvedFontOptions + fonts?: ResolvedFontOptions /** * Configure the icon for app * * @default 'https://cdn.jsdelivr.net/gh/slidevjs/slidev/assets/favicon.png' */ - favicon: string + favicon?: string /** * Options for drawings * * @default {} */ - drawings: ResolvedDrawingsOptions + drawings?: ResolvedDrawingsOptions /** * URL of PlantUML server used to render diagrams * * @default https://www.plantuml.com/plantuml */ - plantUmlServer: string + plantUmlServer?: string /** * Enable slides recording * * @default 'dev' */ - record: boolean | 'dev' | 'build' + record?: boolean | 'dev' | 'build' /** * Expose the server to inbound requests (listen to `0.0.0.0`) * @@ -203,19 +159,19 @@ export interface SlidevConfig { * @deprecated * @default 'unocss' */ - css: 'unocss' + css?: 'unocss' /** * Enable presenter mode * * @default true */ - presenter: boolean | 'dev' | 'build' + presenter?: boolean | 'dev' | 'build' /** * Attributes to apply to the HTML element * * @default {} */ - htmlAttrs: Record + htmlAttrs?: Record /** * Page transition, powered by Vue's * @@ -230,7 +186,7 @@ export interface SlidevConfig { * @see https://sli.dev/guide/animations.html#pages-transitions * @see https://vuejs.org/guide/built-ins/transition.html */ - transition?: BuiltinSlideTransition | string | TransitionGroupProps + transition?: BuiltinSlideTransition | string | TransitionGroupProps | null /** * Suppport MDC syntax * @@ -245,17 +201,67 @@ export interface SlidevConfig { * * @default true */ - editor: boolean + editor?: boolean /** * Enable context menu * * @default true */ - contextMenu: boolean | 'dev' | 'build' | undefined + contextMenu?: boolean | 'dev' | 'build' | null /** * Enable wake lock */ - wakeLock: boolean | 'dev' | 'build' + wakeLock?: boolean | 'dev' | 'build' + /** + * Options for export + * + * @default {} + */ + export?: ResolvedExportOptions + /** + * Force the filename used when exporting the presentation. + * The extension, e.g. .pdf, gets automatically added. + * + * @default '' + */ + exportFilename?: string | null + /** + * Enable Monaco + * + * @see https://sli.dev/custom/config-monaco.html + * @default true + */ + monaco?: boolean | 'dev' | 'build' + /** + * Where to load monaco types from + * + * - `cdn` - load from CDN with `@typescript/ata` + * - `local` - load from local node_modules + * + * @default 'local' + */ + monacoTypesSource?: 'cdn' | 'local' | 'none' + /** + * Additional node packages to load as monaco types + * + * @default [] + */ + monacoTypesAdditionalPackages?: string[] + /** + * Packages to ignore when loading monaco types + * + * @default [] + */ + monacoTypesIgnorePackages?: string[] + /** + * Additional local modules to load as dependencies of monaco runnable + * + * @default [] + */ + monacoRunAdditionalDeps?: string[] +} + +export interface SlidevConfig extends Required { } export interface FontOptions { diff --git a/packages/vscode/.vscodeignore b/packages/vscode/.vscodeignore index 920ba9f8b0..ce5aeb012e 100644 --- a/packages/vscode/.vscodeignore +++ b/packages/vscode/.vscodeignore @@ -1,5 +1,8 @@ .vscode/** .vscode-test/** +node_modules/** +language-server/** +scripts/** src/** tsup.config.ts *.map diff --git a/packages/vscode/language-server/bin.ts b/packages/vscode/language-server/bin.ts new file mode 100644 index 0000000000..8370da9fc4 --- /dev/null +++ b/packages/vscode/language-server/bin.ts @@ -0,0 +1,9 @@ +#!/usr/bin/env node +/* eslint-disable no-console */ +import process from 'node:process' +import { version } from '../package.json' + +if (process.argv.includes('--version')) + console.log(version) +else + import('./index.js') diff --git a/packages/vscode/language-server/import-meta-url.ts b/packages/vscode/language-server/import-meta-url.ts new file mode 100644 index 0000000000..18d9319126 --- /dev/null +++ b/packages/vscode/language-server/import-meta-url.ts @@ -0,0 +1,2 @@ +// eslint-disable-next-line no-var, ts/no-require-imports, import/no-mutable-exports +export var import_meta_url = require('node:url').pathToFileURL(__filename) diff --git a/packages/vscode/language-server/index.ts b/packages/vscode/language-server/index.ts new file mode 100644 index 0000000000..c55bea1300 --- /dev/null +++ b/packages/vscode/language-server/index.ts @@ -0,0 +1,43 @@ +import { fileURLToPath } from 'node:url' +import { createConnection, createServer, createSimpleProject } from '@volar/language-server/node' +import { create as createYamlService } from './volar-service-yaml' +import { slidevLanguagePlugin } from './languagePlugin' +import { create as createPrettierService } from './prettierService' + +const connection = createConnection() +const server = createServer(connection) + +connection.onInitialize((params) => { + return server.initialize( + params, + createSimpleProject([slidevLanguagePlugin]), + [ + createYamlService({ + getLanguageSettings() { + return { + completion: true, + customTags: [], + format: true, + hover: true, + isKubernetes: false, + validate: true, + yamlVersion: '1.2', + schemas: [ + { + fileMatch: ['volar-embedded-content://frontmatter_0/**/*.md'], + uri: fileURLToPath(new URL('../schema/headmatter.json', import.meta.url)), + }, + ], + } + }, + }), + createPrettierService(), + ], + ) +}) + +connection.onInitialized(server.initialized) + +connection.onShutdown(server.shutdown) + +connection.listen() diff --git a/packages/vscode/language-server/languagePlugin.ts b/packages/vscode/language-server/languagePlugin.ts new file mode 100644 index 0000000000..d92384d86e --- /dev/null +++ b/packages/vscode/language-server/languagePlugin.ts @@ -0,0 +1,90 @@ +import type { LanguagePlugin, VirtualCode } from '@volar/language-core' +import { parseSync } from '@slidev/parser' +import type { URI } from 'vscode-uri' +import type { SlidevMarkdown } from '@slidev/types' + +export const slidevLanguagePlugin: LanguagePlugin = { + getLanguageId() { + return undefined + }, + createVirtualCode(uri, languageId, snapshot) { + if (languageId === 'markdown') { + const source = snapshot.getText(0, snapshot.getLength()) + const parsed = parseSync(source, uri.fsPath, { + noParseYAML: true, + preserveCR: true, + }) + + return { + id: 'root', + languageId: 'markdown', + mappings: [], + embeddedCodes: [...getEmbeddedCodes(parsed)], + snapshot, + } + } + }, +} + +function* getEmbeddedCodes(parsed: SlidevMarkdown): Generator { + const lines = parsed.raw.split('\n') + function lineToPos(line: number) { + let pos = 0 + for (let i = 0; i <= line; i++) { + pos += lines[i].length + 1 + } + return pos + } + for (const { frontmatterRaw, start, contentStart, content, index } of parsed.slides) { + if (frontmatterRaw != null) { + yield { + id: `frontmatter_${index}`, + languageId: 'yaml', + snapshot: { + getText: (start, end) => frontmatterRaw.substring(start, end), + getLength: () => frontmatterRaw.length, + getChangeRange: () => undefined, + }, + mappings: [{ + sourceOffsets: [lineToPos(start)], + generatedOffsets: [0], + lengths: [frontmatterRaw.length], + data: { + verification: true, + completion: true, + semantic: true, + navigation: true, + structure: true, + format: true, + }, + }], + embeddedCodes: [], + } + } + if (content) { + yield { + id: `content_${index}`, + languageId: 'markdown', + snapshot: { + getText: (start, end) => content.substring(start, end), + getLength: () => content.length, + getChangeRange: () => undefined, + }, + mappings: [{ + sourceOffsets: [lineToPos(contentStart)], + generatedOffsets: [0], + lengths: [content.length], + data: { + verification: true, + completion: true, + semantic: true, + navigation: true, + structure: true, + format: true, + }, + }], + embeddedCodes: [], + } + } + } +} diff --git a/packages/vscode/language-server/prettierService.ts b/packages/vscode/language-server/prettierService.ts new file mode 100644 index 0000000000..3c6cadc170 --- /dev/null +++ b/packages/vscode/language-server/prettierService.ts @@ -0,0 +1,11 @@ +import { create as createPrettierPlugin } from 'volar-service-prettier' +import prettier from 'prettier' + +export function create() { + return createPrettierPlugin( + prettier, + { + documentSelector: ['yaml'], + }, + ) +} diff --git a/packages/vscode/language-server/protocol.ts b/packages/vscode/language-server/protocol.ts new file mode 100644 index 0000000000..3cd434e888 --- /dev/null +++ b/packages/vscode/language-server/protocol.ts @@ -0,0 +1 @@ +export * from '@volar/language-server/protocol' diff --git a/packages/vscode/language-server/volar-service-yaml.ts b/packages/vscode/language-server/volar-service-yaml.ts new file mode 100644 index 0000000000..da1ee31534 --- /dev/null +++ b/packages/vscode/language-server/volar-service-yaml.ts @@ -0,0 +1,199 @@ +// Vendored from https://github.com/volarjs/services/tree/master/packages/yaml +// Await https://github.com/volarjs/services/pull/103 + +import type { Disposable, DocumentSelector, LanguageServiceContext, LanguageServicePlugin, LanguageServicePluginInstance, ProviderResult } from '@volar/language-service' +import type { TextDocument } from 'vscode-languageserver-textdocument' +import { URI, Utils } from 'vscode-uri' +import * as yaml from 'yaml-language-server' + +export interface Provide { + 'yaml/languageService': () => yaml.LanguageService +} + +function noop(): undefined { } + +/** + * Create a Volar language service for YAML documents. + */ +export function create({ + documentSelector = ['yaml'], + getWorkspaceContextService = (context) => { + return { + resolveRelativePath(relativePath, resource) { + const base = resource.substring(0, resource.lastIndexOf('/') + 1) + let baseUri = URI.parse(base) + const decoded = context.decodeEmbeddedDocumentUri(baseUri) + if (decoded) { + baseUri = decoded[0] + } + return Utils.resolvePath(baseUri, relativePath).toString() + }, + } + }, + getLanguageSettings = () => { + return { + completion: true, + customTags: [], + format: true, + hover: true, + isKubernetes: false, + validate: true, + yamlVersion: '1.2', + } + }, + onDidChangeLanguageSettings = () => { + return { dispose() { } } + }, +}: { + documentSelector?: DocumentSelector + getWorkspaceContextService?: (context: LanguageServiceContext) => yaml.WorkspaceContextService + getLanguageSettings?: (context: LanguageServiceContext) => ProviderResult + onDidChangeLanguageSettings?: (listener: () => void, context: LanguageServiceContext) => Disposable +} = {}): LanguageServicePlugin { + return { + name: 'yaml', + capabilities: { + codeActionProvider: {}, + codeLensProvider: { + resolveProvider: false, + }, + completionProvider: { + triggerCharacters: [' ', ':'], + }, + definitionProvider: true, + diagnosticProvider: {}, + documentOnTypeFormattingProvider: { + triggerCharacters: ['\n'], + }, + documentSymbolProvider: true, + hoverProvider: true, + documentLinkProvider: {}, + foldingRangeProvider: true, + selectionRangeProvider: true, + }, + create(context): LanguageServicePluginInstance { + const ls = yaml.getLanguageService({ + schemaRequestService: async uri => await context.env.fs?.readFile(URI.parse(uri)) ?? '', + telemetry: { + send: noop, + sendError: noop, + sendTrack: noop, + }, + // @ts-expect-error https://github.com/redhat-developer/yaml-language-server/pull/910 + clientCapabilities: context.env?.clientCapabilities, + workspaceContext: getWorkspaceContextService(context), + }) + let initializing: Promise | undefined + + const disposable = onDidChangeLanguageSettings(() => initializing = undefined, context) + + return { + dispose() { + disposable.dispose() + }, + + provide: { + 'yaml/languageService': () => ls, + }, + + provideCodeActions(document, range, context) { + return worker(document, () => { + return ls.getCodeAction(document, { + context, + range, + textDocument: document, + }) + }) + }, + + // provideCodeLenses(document) { + // return worker(document, () => { + // return ls.getCodeLens(document) + // }) + // }, + + provideCompletionItems(document, position) { + return worker(document, () => { + return ls.doComplete(document, position, false) + }) + }, + + provideDefinition(document, position) { + return worker(document, () => { + return ls.doDefinition(document, { position, textDocument: document }) + }) + }, + + provideDiagnostics(document) { + return worker(document, () => { + return ls.doValidation(document, false) + }) + }, + + provideDocumentSymbols(document) { + return worker(document, () => { + return ls.findDocumentSymbols2(document, {}) + }) + }, + + provideHover(document, position) { + return worker(document, () => { + return ls.doHover(document, position) + }) + }, + + provideDocumentLinks(document) { + return worker(document, () => { + return ls.findLinks(document) + }) + }, + + provideFoldingRanges(document) { + return worker(document, () => { + return ls.getFoldingRanges(document, context.env.clientCapabilities?.textDocument?.foldingRange ?? {}) + }) + }, + + provideOnTypeFormattingEdits(document, position, key, options) { + return worker(document, () => { + return ls.doDocumentOnTypeFormatting(document, { ch: key, options, position, textDocument: document }) + }) + }, + + provideSelectionRanges(document, positions) { + return worker(document, () => { + return ls.getSelectionRanges(document, positions) + }) + }, + + // resolveCodeLens(codeLens) { + // return ls.resolveCodeLens(codeLens) + // }, + } + + async function worker(document: TextDocument, callback: () => T): Promise | undefined> { + if (!matchDocument(documentSelector, document)) { + return + } + + await (initializing ??= initialize()) + + return await callback() + } + + async function initialize() { + const settings = await getLanguageSettings(context) + ls.configure(settings) + } + }, + } +} + +function matchDocument(selector: DocumentSelector, document: TextDocument) { + for (const sel of selector) { + if (sel === document.languageId || (typeof sel === 'object' && sel.language === document.languageId)) { + return true + } + } + return false +} diff --git a/packages/vscode/package.json b/packages/vscode/package.json index 6e5066c851..2efbde87b2 100644 --- a/packages/vscode/package.json +++ b/packages/vscode/package.json @@ -24,6 +24,102 @@ "onStartupFinished" ], "contributes": { + "languages": [ + { + "id": "markdown", + "configuration": "./language/language-configuration.json" + }, + { + "id": "slidev" + } + ], + "grammars": [ + { + "language": "slidev", + "scopeName": "source.slidev", + "path": "./syntaxes/slidev.tmLanguage.json", + "embeddedLanguages": { + "source.ts": "typescript", + "source.yaml": "yaml" + } + }, + { + "path": "./syntaxes/markdown.json", + "scopeName": "inject-to-markdown.main.slidev", + "injectTo": [ + "text.html.markdown" + ], + "embeddedLanguages": { + "source.slidev": "slidev" + } + }, + { + "path": "./syntaxes/codeblock.json", + "scopeName": "inject-to-markdown.codeblock.slidev", + "injectTo": [ + "text.html.markdown" + ], + "embeddedLanguages": { + "source.slidev": "slidev", + "source.ts": "typescript" + } + }, + { + "path": "./syntaxes/codeblock-patch.json", + "scopeName": "inject-to-markdown.codeblock.patch.slidev", + "injectTo": [ + "text.html.markdown" + ], + "embeddedLanguages": { + "source.slidev": "slidev", + "meta.embedded.block.html": "html", + "source.js": "javascript", + "source.css": "css", + "meta.embedded.block.frontmatter": "yaml", + "meta.embedded.block.css": "css", + "meta.embedded.block.ini": "ini", + "meta.embedded.block.java": "java", + "meta.embedded.block.lua": "lua", + "meta.embedded.block.makefile": "makefile", + "meta.embedded.block.perl": "perl", + "meta.embedded.block.r": "r", + "meta.embedded.block.ruby": "ruby", + "meta.embedded.block.php": "php", + "meta.embedded.block.sql": "sql", + "meta.embedded.block.vs_net": "vs_net", + "meta.embedded.block.xml": "xml", + "meta.embedded.block.xsl": "xsl", + "meta.embedded.block.yaml": "yaml", + "meta.embedded.block.dosbatch": "dosbatch", + "meta.embedded.block.clojure": "clojure", + "meta.embedded.block.coffee": "coffee", + "meta.embedded.block.c": "c", + "meta.embedded.block.cpp": "cpp", + "meta.embedded.block.diff": "diff", + "meta.embedded.block.dockerfile": "dockerfile", + "meta.embedded.block.go": "go", + "meta.embedded.block.groovy": "groovy", + "meta.embedded.block.pug": "jade", + "meta.embedded.block.javascript": "javascript", + "meta.embedded.block.json": "json", + "meta.embedded.block.jsonc": "jsonc", + "meta.embedded.block.latex": "latex", + "meta.embedded.block.less": "less", + "meta.embedded.block.objc": "objc", + "meta.embedded.block.scss": "scss", + "meta.embedded.block.perl6": "perl6", + "meta.embedded.block.powershell": "powershell", + "meta.embedded.block.python": "python", + "meta.embedded.block.rust": "rust", + "meta.embedded.block.scala": "scala", + "meta.embedded.block.shellscript": "shellscript", + "meta.embedded.block.typescript": "typescript", + "meta.embedded.block.typescriptreact": "typescriptreact", + "meta.embedded.block.csharp": "csharp", + "meta.embedded.block.fsharp": "fsharp" + } + } + ], "commands": [ { "command": "slidev.enable-extension", @@ -349,8 +445,9 @@ "scripts": { "publish": "esno scripts/publish.ts", "pack": "vsce package --no-dependencies", + "prepare": "esno scripts/schema.ts", "build": "tsup --env.NODE_ENV production --treeshake", - "dev": "tsup --watch ./src --env.NODE_ENV development", + "dev": "nr prepare && tsup --watch ./src --watch ./language-server --env.NODE_ENV development", "vscode:prepublish": "nr build" }, "devDependencies": { @@ -359,8 +456,15 @@ "@slidev/types": "workspace:*", "@types/node": "^20.14.10", "@types/vscode": "~1.89.0", + "@volar/language-server": "~2.4.0-alpha.15", + "@volar/vscode": "^2.4.0-alpha.15", "get-port-please": "^3.1.2", + "mlly": "^1.7.1", "ovsx": "^0.9.1", - "reactive-vscode": "0.2.0-beta.4" + "prettier": "^3.3.2", + "reactive-vscode": "0.2.0-beta.5", + "tm-grammars": "^1.13.11", + "volar-service-prettier": "^0.0.54", + "volar-service-yaml": "^0.0.59" } } diff --git a/packages/vscode/schema/headmatter.json b/packages/vscode/schema/headmatter.json new file mode 100644 index 0000000000..6fa425e06d --- /dev/null +++ b/packages/vscode/schema/headmatter.json @@ -0,0 +1,619 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Headmatter", + "definitions": { + "Headmatter": { + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "Title of the slides" + }, + "titleTemplate": { + "type": "string", + "description": "String template to compose title", + "default": "%s - Slidev" + }, + "theme": { + "type": "string", + "description": "Theme to use for the slides", + "default": "default" + }, + "addons": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of Slidev addons", + "default": [] + }, + "remoteAssets": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "string", + "const": "dev" + }, + { + "type": "string", + "const": "build" + } + ], + "description": "Download remote assets in local using vite-plugin-remote-assets", + "default": false + }, + "download": { + "type": [ + "boolean", + "string" + ], + "description": "Show a download button in the SPA build, could also be a link to custom pdf", + "default": false + }, + "codeCopy": { + "type": "boolean", + "description": "Show a copy button in code blocks", + "default": true + }, + "info": { + "type": [ + "string", + "boolean" + ], + "description": "Information shows on the built SPA Can be a markdown string", + "default": false + }, + "highlighter": { + "type": "string", + "enum": [ + "shiki", + "prism" + ], + "description": "Prefer highlighter", + "default": "shiki" + }, + "twoslash": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "string", + "const": "dev" + }, + { + "type": "string", + "const": "build" + } + ], + "description": "Enable Twoslash", + "default": true + }, + "lineNumbers": { + "type": "boolean", + "description": "Show line numbers in code blocks", + "default": false + }, + "colorSchema": { + "type": "string", + "enum": [ + "dark", + "light", + "all", + "auto" + ], + "description": "Force slides color schema", + "default": "auto" + }, + "routerMode": { + "type": "string", + "enum": [ + "hash", + "history" + ], + "description": "Router mode for vue-router", + "default": "history" + }, + "aspectRatio": { + "type": "number", + "description": "Aspect ratio for slides should be like `16/9` or `1:1`", + "default": "16/9" + }, + "canvasWidth": { + "type": "number", + "description": "The actual width for slides canvas. unit in px.", + "default": "980" + }, + "selectable": { + "type": "boolean", + "description": "Controls whether texts in slides are selectable", + "default": true + }, + "themeConfig": { + "$ref": "#/definitions/SlidevThemeConfig", + "description": "Configure for themes, will inject intro root styles as `--slidev-theme-x` for attribute `x`\n\nThis allows themes to have customization options in frontmatter Refer to themes' document for options avaliable", + "default": {} + }, + "fonts": { + "$ref": "#/definitions/ResolvedFontOptions", + "description": "Configure fonts for the slides and app", + "default": {} + }, + "favicon": { + "type": "string", + "description": "Configure the icon for app", + "default": "https://cdn.jsdelivr.net/gh/slidevjs/slidev/assets/favicon.png" + }, + "drawings": { + "$ref": "#/definitions/ResolvedDrawingsOptions", + "description": "Options for drawings", + "default": {} + }, + "plantUmlServer": { + "type": "string", + "description": "URL of PlantUML server used to render diagrams", + "default": "https://www.plantuml.com/plantuml" + }, + "record": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "string", + "const": "dev" + }, + { + "type": "string", + "const": "build" + } + ], + "description": "Enable slides recording", + "default": "dev" + }, + "remote": { + "type": [ + "string", + "boolean" + ], + "description": "Expose the server to inbound requests (listen to `0.0.0.0`)\n\nPass a string to set the password for accessing presenter mode.", + "default": false + }, + "css": { + "type": "string", + "const": "unocss", + "description": "Engine for Atomic CSS", + "deprecated": true, + "default": "unocss" + }, + "presenter": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "string", + "const": "dev" + }, + { + "type": "string", + "const": "build" + } + ], + "description": "Enable presenter mode", + "default": true + }, + "htmlAttrs": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Attributes to apply to the HTML element", + "default": {} + }, + "transition": { + "anyOf": [ + { + "$ref": "#/definitions/BuiltinSlideTransition" + }, + { + "type": "string" + }, + { + "$ref": "#/definitions/TransitionGroupProps" + }, + { + "type": "null" + } + ], + "description": "Page transition, powered by Vue's \n\nBuilt-in transitions:\n- fade\n- fade-out\n- slide-left\n- slide-right\n- slide-up\n- slide-down" + }, + "mdc": { + "type": "boolean", + "description": "Suppport MDC syntax", + "default": false + }, + "editor": { + "type": "boolean", + "description": "Enable built-in editor", + "default": true + }, + "contextMenu": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "string", + "const": "dev" + }, + { + "type": "string", + "const": "build" + }, + { + "type": "null" + } + ], + "description": "Enable context menu", + "default": true + }, + "wakeLock": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "string", + "const": "dev" + }, + { + "type": "string", + "const": "build" + } + ], + "description": "Enable wake lock" + }, + "export": { + "$ref": "#/definitions/ResolvedExportOptions", + "description": "Options for export", + "default": {} + }, + "exportFilename": { + "type": [ + "string", + "null" + ], + "description": "Force the filename used when exporting the presentation. The extension, e.g. .pdf, gets automatically added.", + "default": "" + }, + "monaco": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "string", + "const": "dev" + }, + { + "type": "string", + "const": "build" + } + ], + "description": "Enable Monaco", + "default": true + }, + "monacoTypesSource": { + "type": "string", + "enum": [ + "cdn", + "local", + "none" + ], + "description": "Where to load monaco types from\n\n- `cdn` - load from CDN with `@typescript/ata`\n- `local` - load from local node_modules", + "default": "local" + }, + "monacoTypesAdditionalPackages": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Additional node packages to load as monaco types", + "default": [] + }, + "monacoTypesIgnorePackages": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Packages to ignore when loading monaco types", + "default": [] + }, + "monacoRunAdditionalDeps": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Additional local modules to load as dependencies of monaco runnable", + "default": [] + } + } + }, + "SlidevThemeConfig": { + "type": "object", + "additionalProperties": { + "type": [ + "string", + "number" + ] + } + }, + "ResolvedFontOptions": { + "type": "object", + "properties": { + "sans": { + "type": "array", + "items": { + "type": "string" + } + }, + "mono": { + "type": "array", + "items": { + "type": "string" + } + }, + "serif": { + "type": "array", + "items": { + "type": "string" + } + }, + "weights": { + "type": "array", + "items": { + "type": "string" + } + }, + "italic": { + "type": "boolean" + }, + "provider": { + "type": "string", + "enum": [ + "none", + "google" + ] + }, + "webfonts": { + "type": "array", + "items": { + "type": "string" + } + }, + "local": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "sans", + "mono", + "serif", + "weights", + "italic", + "provider", + "webfonts", + "local" + ] + }, + "ResolvedDrawingsOptions": { + "type": "object", + "properties": { + "persist": { + "type": "boolean", + "enum": [ + false + ] + }, + "enabled": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "string", + "const": "dev" + }, + { + "type": "string", + "const": "build" + } + ] + }, + "presenterOnly": { + "type": "boolean" + }, + "syncAll": { + "type": "boolean" + } + }, + "required": [ + "persist", + "enabled", + "presenterOnly", + "syncAll" + ] + }, + "BuiltinSlideTransition": { + "type": "string", + "enum": [ + "slide-up", + "slide-down", + "slide-left", + "slide-right", + "fade", + "zoom", + "none" + ] + }, + "TransitionGroupProps": { + "type": "object", + "properties": { + "tag": { + "type": "string" + }, + "moveClass": { + "type": "string" + }, + "name": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "transition", + "animation" + ] + }, + "css": { + "type": "boolean" + }, + "duration": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "object", + "properties": { + "enter": { + "type": "number" + }, + "leave": { + "type": "number" + } + }, + "required": [ + "enter", + "leave" + ] + } + ] + }, + "enterFromClass": { + "type": "string" + }, + "enterActiveClass": { + "type": "string" + }, + "enterToClass": { + "type": "string" + }, + "appearFromClass": { + "type": "string" + }, + "appearActiveClass": { + "type": "string" + }, + "appearToClass": { + "type": "string" + }, + "leaveFromClass": { + "type": "string" + }, + "leaveActiveClass": { + "type": "string" + }, + "leaveToClass": { + "type": "string" + }, + "appear": {}, + "persisted": {}, + "onBeforeEnter": {}, + "onEnter": {}, + "onAfterEnter": {}, + "onEnterCancelled": {}, + "onBeforeLeave": {}, + "onLeave": {}, + "onAfterLeave": {}, + "onLeaveCancelled": {}, + "onBeforeAppear": {}, + "onAppear": {}, + "onAfterAppear": {}, + "onAppearCancelled": {} + }, + "required": [ + "appear", + "onAfterAppear", + "onAfterEnter", + "onAfterLeave", + "onAppear", + "onAppearCancelled", + "onBeforeAppear", + "onBeforeEnter", + "onBeforeLeave", + "onEnter", + "onEnterCancelled", + "onLeave", + "onLeaveCancelled", + "persisted" + ] + }, + "ResolvedExportOptions": { + "type": "object", + "properties": { + "output": { + "type": "string" + }, + "format": { + "type": "string" + }, + "timeout": { + "type": "number" + }, + "wait": { + "type": "number" + }, + "wait-until": { + "type": "string" + }, + "range": { + "type": "string" + }, + "dark": { + "type": "boolean" + }, + "with-clicks": { + "type": "boolean" + }, + "executable-path": { + "type": "string" + }, + "with-toc": { + "type": "boolean" + }, + "per-slide": { + "type": "boolean" + }, + "scale": { + "type": "number" + }, + "withClicks": { + "type": "boolean" + }, + "executablePath": { + "type": "string" + }, + "withToc": { + "type": "boolean" + } + } + } + } +} diff --git a/packages/vscode/scripts/schema.ts b/packages/vscode/scripts/schema.ts new file mode 100644 index 0000000000..c192800720 --- /dev/null +++ b/packages/vscode/scripts/schema.ts @@ -0,0 +1,12 @@ +import fs from 'node:fs/promises' +import tsj from 'ts-json-schema-generator' + +const program = tsj + .createGenerator({ + path: '../../packages/types/src/config.ts', + tsconfig: '../../tsconfig.json', + additionalProperties: true, + }) + .createSchema('Headmatter') + +await fs.writeFile('./schema/headmatter.json', JSON.stringify(program, null, 2)) diff --git a/packages/vscode/src/index.ts b/packages/vscode/src/index.ts index 40e0aba42f..3ee8e48cd9 100644 --- a/packages/vscode/src/index.ts +++ b/packages/vscode/src/index.ts @@ -7,6 +7,7 @@ import { logger } from './views/logger' import { usePreviewWebview } from './views/previewWebview' import { useSlidesTree } from './views/slidesTree' import { useProjectsTree } from './views/projectsTree' +import { useLanguageClient } from './languageClient' // eslint-disable-next-line no-restricted-syntax export = defineExtension(() => { @@ -23,6 +24,11 @@ export = defineExtension(() => { useAnnotations() useFoldings() + // language server + const labsInfo = useLanguageClient() + logger.info('Slidev activated.') logger.info(`Entry: ${activeEntry.value}`) + + return labsInfo }) diff --git a/packages/vscode/src/languageClient.ts b/packages/vscode/src/languageClient.ts new file mode 100644 index 0000000000..ab6d32a56d --- /dev/null +++ b/packages/vscode/src/languageClient.ts @@ -0,0 +1,68 @@ +import { createLabsInfo } from '@volar/vscode' +import type { ServerOptions } from '@volar/vscode/node' +import { LanguageClient, TransportKind } from '@volar/vscode/node' +import { computed, extensionContext, watch } from 'reactive-vscode' +import { Uri, window } from 'vscode' +import * as serverProtocol from '../language-server/protocol' +import { slidevFiles } from './projects' +import { logger } from './views/logger' + +export function useLanguageClient() { + const serverModule = Uri.joinPath(extensionContext.value!.extensionUri, 'dist', 'language-server.cjs') + const runOptions = { execArgv: [] } + const debugOptions = { execArgv: ['--nolazy', `--inspect=${6009}`] } + const serverOptions: ServerOptions = { + run: { + module: serverModule.fsPath, + transport: TransportKind.ipc, + options: runOptions, + }, + debug: { + module: serverModule.fsPath, + transport: TransportKind.ipc, + options: debugOptions, + }, + } + + const documentSelector = computed(() => slidevFiles.value.map(path => ({ language: 'markdown', pattern: path }))) + + logger.info('Starting Slidev language server...') + const client = new LanguageClient( + 'slidev-language-server', + 'Slidev Language Server', + serverOptions, + { documentSelector: documentSelector.value }, + ) + + async function doStart(shouldStop: boolean) { + if (shouldStop) + await client.stop() + client.clientOptions.documentSelector = documentSelector.value + await client.start() + } + + let restartPromise: Promise | undefined + async function start(shouldStop: boolean) { + await restartPromise + restartPromise = doStart(shouldStop) + await restartPromise + } + + let shouldStop = false + watch( + () => slidevFiles.value.join('\n'), + (files) => { + if (files.length === 0 && !shouldStop) + return + if (shouldStop) + window.setStatusBarMessage(`Restarting Slidev language server...`, start(true)) + else + start(false) + shouldStop = true + }, + ) + + const labsInfo = createLabsInfo(serverProtocol) + labsInfo.addLanguageClient(client) + return labsInfo.extensionExports +} diff --git a/packages/vscode/src/projects.ts b/packages/vscode/src/projects.ts index d4170c5eb9..31b36c59d5 100644 --- a/packages/vscode/src/projects.ts +++ b/packages/vscode/src/projects.ts @@ -17,6 +17,7 @@ export interface SlidevProject { } export const projects = reactive(new Map()) +export const slidevFiles = computed(() => [...projects.values()].flatMap(p => Object.keys(p.data.markdownFiles))) export const activeEntry = ref(null) export const activeProject = computed(() => activeEntry.value ? projects.get(activeEntry.value) : undefined) export const activeSlidevData = computed(() => activeProject.value?.data) diff --git a/packages/vscode/syntaxes/.vscode/settings.json b/packages/vscode/syntaxes/.vscode/settings.json new file mode 100644 index 0000000000..a11c29c24e --- /dev/null +++ b/packages/vscode/syntaxes/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "slidev.include": [ + "**/slides.md", + "slidev.example.md" + ] +} diff --git a/packages/vscode/syntaxes/codeblock-patch.ts b/packages/vscode/syntaxes/codeblock-patch.ts new file mode 100644 index 0000000000..e94196ac27 --- /dev/null +++ b/packages/vscode/syntaxes/codeblock-patch.ts @@ -0,0 +1,52 @@ +import { readFileSync } from 'node:fs' +import { join } from 'node:path' + +const Markdown = JSON.parse( + readFileSync(join(__dirname, '../node_modules/tm-grammars/grammars/markdown.json'), 'utf8'), +) + +const base = { + $schema: 'https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json', + fileTypes: [], + injectionSelector: 'L:text.html.markdown -markup.frontmatter.slidev -markup.fenced_code.block.markdown', + patterns: [ + ], + repository: { + fenced_code_block_unknown: { + begin: '(^|\\G)(\\s*)(`{3,}|~{3,})\\s*(?=([^`]*)?$)', + beginCaptures: { + 3: { + name: 'punctuation.definition.markdown', + }, + 4: { + name: 'fenced_code.block.language.attributes.markdown', + patterns: [], + }, + }, + end: '(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$', + endCaptures: { + 3: { + name: 'punctuation.definition.markdown', + }, + }, + name: 'markup.fenced_code.block.markdown', + }, + }, + scopeName: 'inject-to-markdown.codeblock.patch.slidev', +} as any + +export function generateCodeblockPatch() { + for (const [k, v] of Object.entries(Markdown.repository) as any) { + if (!k.startsWith('fenced_code_block_') || k === 'fenced_code_block_unknown') + continue + v.beginCaptures[5].patterns = [] + base.patterns.push(v) + } + + base.patterns.push( + { + include: '#fenced_code_block_unknown', + }, + ) + return base +} diff --git a/packages/vscode/syntaxes/codeblock.json b/packages/vscode/syntaxes/codeblock.json new file mode 100644 index 0000000000..c467c061f8 --- /dev/null +++ b/packages/vscode/syntaxes/codeblock.json @@ -0,0 +1,58 @@ +{ + "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", + "fileTypes": [], + "injectionSelector": "L:fenced_code.block.language.attributes.markdown -meta.code_block_attrs.slidev", + "patterns": [ + { + "match": "twoslash", + "name": "keyword.twoslash.slidev" + }, + { + "match": "\\s*(\\{)([^}]*)(\\})\\s*(.*)$", + "name": "meta.code_block_attrs.slidev", + "captures": { + "1": { + "name": "punctuation.definition.range_or_monaco.slidev" + }, + "2": { + "name": "meta.range_or_monaco.slidev", + "patterns": [ + { + "include": "source.slidev#monaco-type" + }, + { + "include": "source.slidev#range-with-steps" + } + ] + }, + "3": { + "name": "punctuation.definition.range_or_monaco.slidev" + }, + "4": { + "patterns": [ + { + "match": "twoslash", + "name": "keyword.twoslash.slidev" + }, + { + "begin": "(?=\\{)", + "end": "(?<=\\})(\\s*twoslash)?$", + "endCaptures": { + "1": { + "name": "keyword.twoslash.slidev" + } + }, + "contentName": "meta.embedded.block.code_block_options.ts", + "patterns": [ + { + "include": "source.ts#object-literal" + } + ] + } + ] + } + } + } + ], + "scopeName": "inject-to-markdown.codeblock.slidev" +} diff --git a/packages/vscode/syntaxes/language-configuration.json b/packages/vscode/syntaxes/language-configuration.json new file mode 100644 index 0000000000..200592d184 --- /dev/null +++ b/packages/vscode/syntaxes/language-configuration.json @@ -0,0 +1,57 @@ +// Ported from https://github.com/vuejs/language-tools/blob/master/extensions/vscode/languages/markdown-language-configuration.json +{ + "autoClosingPairs": [ + // html + { + "open": "{", + "close": "}" + }, + { + "open": "[", + "close": "]" + }, + { + "open": "(", + "close": ")" + }, + { + "open": "'", + "close": "'" + }, + { + "open": "\"", + "close": "\"" + }, + { + "open": "", + "notIn": [ + "comment", + "string" + ] + }, + // javascript + // commented to fix https://github.com/vuejs/language-tools/issues/1428 + // { + // "open": "`", + // "close": "`", + // "notIn": [ + // "string", + // "comment" + // ] + // }, + { + "open": "/**", + "close": " */", + "notIn": [ + "string" + ] + } + ], + "colorizedBracketPairs": [ + [ + "{{", + "}}" + ] + ] +} diff --git a/packages/vscode/syntaxes/markdown.json b/packages/vscode/syntaxes/markdown.json new file mode 100644 index 0000000000..b55a6f0970 --- /dev/null +++ b/packages/vscode/syntaxes/markdown.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", + "fileTypes": [], + "injectionSelector": "L:text.html.markdown -markup.frontmatter.slidev", + "patterns": [ + { + "include": "source.slidev#import-snippet" + }, + { + "include": "source.slidev#slide-frontmatter" + } + ], + "scopeName": "inject-to-markdown.main.slidev" +} diff --git a/packages/vscode/syntaxes/slidev.example.md b/packages/vscode/syntaxes/slidev.example.md new file mode 100644 index 0000000000..021c9c2a97 --- /dev/null +++ b/packages/vscode/syntaxes/slidev.example.md @@ -0,0 +1,68 @@ +--- +foo: a +bar: 1 +--- + +# Title + +**Hello** World + +[](./a) + +```ts {a} +console.log('Hello World') +``` + +--- +src: ../../../demo/starter/slides.md +s: 1 +--- + +--- + +# Import Snippets + +<<< @/snippets/snippet.js {2,3|5} +<<< @/snippets/snippet.js {2,3|5}{lines:true} +<<< @/snippets/snippet.js ts {monaco-run}{lines: true} + +--- + +# Vue Component + +
+ + + + +--- +layout: center +text: 1 +--- + +# Code block + +```ts {1,2|3} +const a = 1 +``` + +```ts twoslash +const a = 1 +``` + +```vue {monaco-run}{showOutputAt: '+1'} + +``` + +```ts {monaco-run}{showOutputAt: '+1'} twoslash +const a = 1 +``` + +$$ +\lambda = 1 +$$ diff --git a/packages/vscode/syntaxes/slidev.tmLanguage.json b/packages/vscode/syntaxes/slidev.tmLanguage.json new file mode 100644 index 0000000000..ef8c34e0c1 --- /dev/null +++ b/packages/vscode/syntaxes/slidev.tmLanguage.json @@ -0,0 +1,112 @@ +{ + "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", + "name": "Slidev", + "scopeName": "source.slidev", + "patterns": [], + "repository": { + "import-snippet": { + "match": "^(<<<)\\s*(\\S+)(\\s+[\\w-]+)?(?:\\s*(\\{)([^}]*)(\\}))?(?:\\s*(\\{.*\\}))?", + "name": "meta.import_snippet.block.slidev", + "captures": { + "1": { + "name": "punctuation.definition.slidev" + }, + "2": { + "name": "string.path.snippet.slidev" + }, + "3": { + "name": "import_snippet.block.language.slidev" + }, + "4": { + "name": "punctuation.separator.range.slidev" + }, + "5": { + "name": "meta.range_or_monaco.slidev", + "patterns": [ + { + "include": "#monaco-type" + }, + { + "include": "#monaco-write" + }, + { + "include": "#range-with-steps" + } + ] + }, + "6": { + "name": "punctuation.separator.range.slidev" + }, + "7": { + "patterns": [ + { + "include": "source.ts#object-literal" + } + ] + } + } + }, + "range-with-steps": { + "match": "([^|]*)(\\|)?", + "captures": { + "1": { + "patterns": [ + { + "include": "#range" + } + ] + }, + "2": { + "name": "punctuation.separator.steps.slidev" + } + } + }, + "range": { + "match": "(\\d+|\\*)([,-])?", + "captures": { + "1": { + "name": "constant.numeric.range.slidev" + }, + "2": { + "name": "punctuation.separator.range.slidev" + } + } + }, + "monaco-type": { + "match": "monaco(-(run|diff))?", + "name": "keyword.monaco.slidev" + }, + "monaco-write": { + "match": "monaco-write", + "name": "keyword.monaco.slidev" + }, + "slide-frontmatter": { + "begin": "(^|\\G)(---).*$", + "beginCaptures": { + "2": { + "name": "punctuation.definition.frontmatter.slidev" + } + }, + "end": "(?=^\\s*$)", + "name": "markup.frontmatter.slidev", + "patterns": [ + { + "begin": "(?=^(?!\\s*$))", + "end": "(?=^\\s*$)", + "patterns": [ + { + "begin": "\\G", + "end": "(?=(^|\\G)(---).*$)", + "contentName": "meta.embedded.block.yaml", + "patterns": [ + { + "include": "source.yaml" + } + ] + } + ] + } + ] + } + } +} diff --git a/packages/vscode/syntaxes/tsconfig.json b/packages/vscode/syntaxes/tsconfig.json new file mode 100644 index 0000000000..88d9c9d549 --- /dev/null +++ b/packages/vscode/syntaxes/tsconfig.json @@ -0,0 +1,10 @@ +{ + "include": [ + "*.ts", + "*.vue", + "*.md" + ], + "vueCompilerOptions": { + "vitePressExtensions": [".md"] + } +} diff --git a/packages/vscode/tsup.config.ts b/packages/vscode/tsup.config.ts index 2b90e8e064..7d8440cae6 100644 --- a/packages/vscode/tsup.config.ts +++ b/packages/vscode/tsup.config.ts @@ -1,16 +1,37 @@ -import { copyFileSync, existsSync, mkdirSync } from 'node:fs' -import { join, resolve } from 'node:path' +import { copyFileSync, existsSync, mkdirSync, writeFileSync } from 'node:fs' +import { join } from 'node:path' import { defineConfig } from 'tsup' +import { resolvePath } from 'mlly' +import { generateCodeblockPatch } from './syntaxes/codeblock-patch' export default defineConfig({ - entry: ['src/index.ts'], + entry: { + 'index': 'src/index.ts', + 'language-server': 'language-server/bin.ts', + }, format: ['cjs'], target: 'node18', clean: true, minify: true, + sourcemap: true, external: [ 'vscode', ], + inject: ['./language-server/import-meta-url.ts'], + define: { + 'import.meta.url': 'import_meta_url', + }, + esbuildPlugins: [{ + name: 'umd2esm', + setup(build) { + build.onResolve({ filter: /^(vscode-.*-languageservice|jsonc-parser)/ }, async (args) => { + const pathUmdMay = await resolvePath(args.path, { url: args.resolveDir }) + // Call twice the replace is to solve the problem of the path in Windows + const pathEsm = pathUmdMay.replace('/umd/', '/esm/').replace('\\umd\\', '\\esm\\') + return { path: pathEsm } + }) + }, + }], async onSuccess() { const assetsDir = join(__dirname, '../../assets') const resDir = join(__dirname, './dist/res') @@ -19,6 +40,11 @@ export default defineConfig({ mkdirSync(resDir, { recursive: true }) for (const file of ['logo-mono.svg', 'logo-mono-dark.svg', 'logo.png', 'logo.svg']) - copyFileSync(resolve(assetsDir, file), resolve(resDir, file)) + copyFileSync(join(assetsDir, file), join(resDir, file)) + + writeFileSync( + join(__dirname, 'syntaxes/codeblock-patch.json'), + JSON.stringify(generateCodeblockPatch(), null, 2), + ) }, }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 921189c187..0591bb24b1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -130,6 +130,9 @@ importers: taze: specifier: ^0.14.2 version: 0.14.2 + ts-json-schema-generator: + specifier: ^2.3.0 + version: 2.3.0 tsup: specifier: ^8.1.0 version: 8.1.0(postcss@8.4.39)(typescript@5.5.3) @@ -736,15 +739,36 @@ importers: '@types/vscode': specifier: ~1.89.0 version: 1.89.0 + '@volar/language-server': + specifier: ~2.4.0-alpha.15 + version: 2.4.0-alpha.15 + '@volar/vscode': + specifier: ^2.4.0-alpha.15 + version: 2.4.0-alpha.15 get-port-please: specifier: ^3.1.2 version: 3.1.2 + mlly: + specifier: ^1.7.1 + version: 1.7.1 ovsx: specifier: ^0.9.1 version: 0.9.1 + prettier: + specifier: ^3.3.2 + version: 3.3.2 reactive-vscode: - specifier: 0.2.0-beta.4 - version: 0.2.0-beta.4(@types/vscode@1.89.0) + specifier: 0.2.0-beta.5 + version: 0.2.0-beta.5(@types/vscode@1.89.0) + tm-grammars: + specifier: ^1.13.11 + version: 1.13.11 + volar-service-prettier: + specifier: ^0.0.54 + version: 0.0.54(prettier@3.3.2) + volar-service-yaml: + specifier: ^0.0.59 + version: 0.0.59 packages: @@ -1598,8 +1622,8 @@ packages: '@polka/url@1.0.0-next.24': resolution: {integrity: sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==} - '@reactive-vscode/reactivity@0.2.0-beta.4': - resolution: {integrity: sha512-g7z9tYRxUAqE5u/r9nLP6hkubUjY6/lp2S6Pr9vqnmxe+1LCXBoOjc97YHVd/BlGNiDsQrt9UbECvVohEoumuw==} + '@reactive-vscode/reactivity@0.2.0-beta.5': + resolution: {integrity: sha512-Cqp+CDFA+bYTV/U8o7e8WqTGs9PyOXNkz2x1cKd8nvn7y96p7rNgd0BqE/9L7qbwINCdqxGEoJx6E4Hk0MJJxw==} '@rollup/pluginutils@4.2.1': resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} @@ -2215,12 +2239,24 @@ packages: '@volar/language-core@2.4.0-alpha.15': resolution: {integrity: sha512-mt8z4Fm2WxfQYoQHPcKVjLQV6PgPqyKLbkCVY2cr5RSaamqCHjhKEpsFX66aL4D/7oYguuaUw9Bx03Vt0TpIIA==} + '@volar/language-server@2.4.0-alpha.15': + resolution: {integrity: sha512-epaF7Rllb29nr25F8hX5bq7ivgStNZzXGkhuPlHCUM+Ij/aQnsBeYQsfm7EttPqqO3abCctpRWyd+icklFEBoQ==} + + '@volar/language-service@2.4.0-alpha.15': + resolution: {integrity: sha512-H5T5JvvqvWhG0PvvKPTM0nczTbTKQ+U87a8r0eahlH/ySi2HvIHO/7PiNKLxKqLNsiT8SX4U3QcGC8ZaNcC07g==} + + '@volar/snapshot-document@2.4.0-alpha.15': + resolution: {integrity: sha512-8lnX0eZ7/lM+hakO5kspWABi4nijppxTy9XU0f9ns2lZ/JCE0t9EurNNiOaw4MWFO9USr0H72Ut0LCB9o4rpqA==} + '@volar/source-map@2.4.0-alpha.15': resolution: {integrity: sha512-8Htngw5TmBY4L3ClDqBGyfLhsB8EmoEXUH1xydyEtEoK0O6NX5ur4Jw8jgvscTlwzizyl/wsN1vn0cQXVbbXYg==} '@volar/typescript@2.4.0-alpha.15': resolution: {integrity: sha512-U3StRBbDuxV6Woa4hvGS4kz3XcOzrWUKgFdEFN+ba1x3eaYg7+ytau8ul05xgA+UNGLXXsKur7fTUhDFyISk0w==} + '@volar/vscode@2.4.0-alpha.15': + resolution: {integrity: sha512-apzZqZrCKO9tDWRzsy4EWUgywMzlVhIqDWP3HrXIjDuRKCFG7x8tgfqoDHOSs5M8aIo2BHk1akzCinobLkpFbw==} + '@vscode/vsce@2.26.1': resolution: {integrity: sha512-QOG6Ht7V93nhwcBxPWcG33UK0qDGEoJdg0xtVeaTN27W6PGdMJUJGTPhB/sNHUIFKwvwzv/zMAHvDgMNXbcwlA==} engines: {node: '>= 16'} @@ -2437,6 +2473,9 @@ packages: ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@8.16.0: + resolution: {integrity: sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==} + algoliasearch@4.22.1: resolution: {integrity: sha512-jwydKFQJKIx9kIZ8Jm44SdpigFwRGPESaxZBaHSV0XWN2yBJAOT4mT7ppvlrpA4UGzz92pqFnVKr/kaZXrcreg==} @@ -3800,6 +3839,10 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported @@ -4176,6 +4219,10 @@ packages: resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} engines: {node: '>=14'} + jackspeak@3.4.2: + resolution: {integrity: sha512-qH3nOSj8q/8+Eg8LUPOq3C+6HWkpUioIjDsq1+D4zY91oZvpPttw8GwtF1nReRYKXl+1AORyFqtm2f5Q1SB6/Q==} + engines: {node: 14 >=14.21 || 16 >=16.20 || >=18} + jiti@1.21.6: resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==} hasBin: true @@ -4231,6 +4278,9 @@ packages: json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-schema@0.4.0: resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} @@ -4731,6 +4781,10 @@ packages: minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} @@ -4750,6 +4804,10 @@ packages: resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} engines: {node: '>=16 || 14 >=14.17'} + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + minisearch@6.3.0: resolution: {integrity: sha512-ihFnidEeU8iXzcVHy74dhkxh/dn8Dc08ERl0xwoMMGqp4+LvRSCgicb+zGqWthVokQKvCSxITlh3P08OzdTYCQ==} @@ -4969,6 +5027,9 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + package-json-from-dist@1.0.0: + resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==} + pako@1.0.11: resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} @@ -5041,6 +5102,10 @@ packages: resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} engines: {node: '>=16 || 14 >=14.17'} + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -5176,6 +5241,11 @@ packages: peerDependencies: prettier: ^3.2.4 + prettier@2.8.7: + resolution: {integrity: sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==} + engines: {node: '>=10.13.0'} + hasBin: true + prettier@2.8.8: resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} engines: {node: '>=10.13.0'} @@ -5270,8 +5340,8 @@ packages: react-is@18.2.0: resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} - reactive-vscode@0.2.0-beta.4: - resolution: {integrity: sha512-o7AdxVQj0QFbpC95Zz4ZcxmxbvA0fSRgMgoTSk8o1sqVun6VVctK+Nigt87aMFjR7StLpJ+rFpmzASR2s/Ryxw==} + reactive-vscode@0.2.0-beta.5: + resolution: {integrity: sha512-A0UTr+TVy8VjWaCUNGvgyKxlK4YuS8uXmjc8qGIvPNk6HJqk3TU/dzjoDQ4aRWBW0nmlKAhyAY/nFDsKaXMv8A==} peerDependencies: '@types/vscode': ^1.89.0 @@ -5317,6 +5387,12 @@ packages: resolution: {integrity: sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==} hasBin: true + request-light@0.5.8: + resolution: {integrity: sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg==} + + request-light@0.7.0: + resolution: {integrity: sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q==} + request-progress@3.0.0: resolution: {integrity: sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==} @@ -5324,6 +5400,10 @@ packages: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + requires-port@1.0.0: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} @@ -5410,6 +5490,10 @@ packages: safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safe-stable-stringify@2.4.3: + resolution: {integrity: sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==} + engines: {node: '>=10'} + safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -5754,6 +5838,9 @@ packages: resolution: {integrity: sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==} engines: {node: '>=14.0.0'} + tm-grammars@1.13.11: + resolution: {integrity: sha512-qZysArHMEbWF27pI914n8RpkFj8t1zNwXoEzJfzE6eknxOrPeRea+z6N9rZvhqIO0vrS7qBjoE/u8zibO+gYBA==} + tmp@0.2.3: resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} engines: {node: '>=14.14'} @@ -5805,6 +5892,11 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + ts-json-schema-generator@2.3.0: + resolution: {integrity: sha512-t4lBQAwZc0sOJq9LJt3NgbznIcslVnm0JeEMFq8qIRklpMRY8jlYD0YmnRWbqBKANxkby91P1XanSSlSOFpUmg==} + engines: {node: '>=18.0.0'} + hasBin: true + tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} @@ -6213,6 +6305,67 @@ packages: jsdom: optional: true + volar-service-prettier@0.0.54: + resolution: {integrity: sha512-DGE16JEeCEECiyt7TXcVpDEhJN0N96sRw9N7Fhk+WyhAztju8F5jO2qIJV9CGyN1AfkUdB+1mwuy+RTho7RHxg==} + peerDependencies: + '@volar/language-service': ~2.3.1 + prettier: ^2.2 || ^3.0 + peerDependenciesMeta: + '@volar/language-service': + optional: true + prettier: + optional: true + + volar-service-yaml@0.0.59: + resolution: {integrity: sha512-7Pi7XWnmgcWmdW7essscHn2+CcG1BEgnNjEE/31GaycwvLu4rPF+Xztzc0ErZLSFW3F2EBPzaecWfrGL2l4NGQ==} + peerDependencies: + '@volar/language-service': ~2.4.0-alpha.12 + peerDependenciesMeta: + '@volar/language-service': + optional: true + + vscode-json-languageservice@4.1.8: + resolution: {integrity: sha512-0vSpg6Xd9hfV+eZAaYN63xVVMOTmJ4GgHxXnkLCh+9RsQBkWKIghzLhW2B9ebfG+LQQg8uLtsQ2aUKjTgE+QOg==} + engines: {npm: '>=7.0.0'} + + vscode-jsonrpc@6.0.0: + resolution: {integrity: sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg==} + engines: {node: '>=8.0.0 || >=10.0.0'} + + vscode-jsonrpc@8.2.0: + resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} + engines: {node: '>=14.0.0'} + + vscode-languageclient@9.0.1: + resolution: {integrity: sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA==} + engines: {vscode: ^1.82.0} + + vscode-languageserver-protocol@3.16.0: + resolution: {integrity: sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A==} + + vscode-languageserver-protocol@3.17.5: + resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} + + vscode-languageserver-textdocument@1.0.11: + resolution: {integrity: sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==} + + vscode-languageserver-types@3.16.0: + resolution: {integrity: sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA==} + + vscode-languageserver-types@3.17.5: + resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} + + vscode-languageserver@7.0.0: + resolution: {integrity: sha512-60HTx5ID+fLRcgdHfmz0LDZAXYEV68fzwG0JWwEPBode9NuMYTIxuYXPg4ngO8i8+Ou0lM7y6GzaYWbiDL0drw==} + hasBin: true + + vscode-languageserver@9.0.1: + resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} + hasBin: true + + vscode-nls@5.2.0: + resolution: {integrity: sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==} + vscode-uri@3.0.8: resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} @@ -6339,6 +6492,14 @@ packages: resolution: {integrity: sha512-4wZWvE398hCP7O8n3nXKu/vdq1HcH01ixYlCREaJL5NUMwQ0g3MaGFUBNSlmBtKmhbtVG/Cm6lyYmSVTEVil8A==} engines: {node: ^14.17.0 || >=16.0.0} + yaml-language-server@1.15.0: + resolution: {integrity: sha512-N47AqBDCMQmh6mBLmI6oqxryHRzi33aPFPsJhYy3VTUGCdLHYjGh4FZzpUjRlphaADBBkDmnkM/++KNIOHi5Rw==} + hasBin: true + + yaml@2.2.2: + resolution: {integrity: sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==} + engines: {node: '>= 14'} + yaml@2.4.5: resolution: {integrity: sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==} engines: {node: '>= 14'} @@ -7321,7 +7482,7 @@ snapshots: '@polka/url@1.0.0-next.24': {} - '@reactive-vscode/reactivity@0.2.0-beta.4': {} + '@reactive-vscode/reactivity@0.2.0-beta.5': {} '@rollup/pluginutils@4.2.1': dependencies: @@ -8136,6 +8297,31 @@ snapshots: dependencies: '@volar/source-map': 2.4.0-alpha.15 + '@volar/language-server@2.4.0-alpha.15': + dependencies: + '@volar/language-core': 2.4.0-alpha.15 + '@volar/language-service': 2.4.0-alpha.15 + '@volar/snapshot-document': 2.4.0-alpha.15 + '@volar/typescript': 2.4.0-alpha.15 + path-browserify: 1.0.1 + request-light: 0.7.0 + vscode-languageserver: 9.0.1 + vscode-languageserver-protocol: 3.17.5 + vscode-languageserver-textdocument: 1.0.11 + vscode-uri: 3.0.8 + + '@volar/language-service@2.4.0-alpha.15': + dependencies: + '@volar/language-core': 2.4.0-alpha.15 + vscode-languageserver-protocol: 3.17.5 + vscode-languageserver-textdocument: 1.0.11 + vscode-uri: 3.0.8 + + '@volar/snapshot-document@2.4.0-alpha.15': + dependencies: + vscode-languageserver-protocol: 3.17.5 + vscode-languageserver-textdocument: 1.0.11 + '@volar/source-map@2.4.0-alpha.15': {} '@volar/typescript@2.4.0-alpha.15': @@ -8144,6 +8330,13 @@ snapshots: path-browserify: 1.0.1 vscode-uri: 3.0.8 + '@volar/vscode@2.4.0-alpha.15': + dependencies: + '@volar/language-server': 2.4.0-alpha.15 + path-browserify: 1.0.1 + vscode-languageclient: 9.0.1 + vscode-nls: 5.2.0 + '@vscode/vsce@2.26.1': dependencies: '@azure/identity': 4.2.0 @@ -8455,6 +8648,13 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ajv@8.16.0: + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + algoliasearch@4.22.1: dependencies: '@algolia/cache-browser-local-storage': 4.22.1 @@ -10044,6 +10244,15 @@ snapshots: minipass: 7.0.4 path-scurry: 1.10.1 + glob@10.4.5: + dependencies: + foreground-child: 3.1.1 + jackspeak: 3.4.2 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.0 + path-scurry: 1.11.1 + glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -10385,6 +10594,12 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + jackspeak@3.4.2: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + jiti@1.21.6: {} joycon@3.1.1: {} @@ -10420,6 +10635,8 @@ snapshots: json-schema-traverse@0.4.1: {} + json-schema-traverse@1.0.0: {} + json-schema@0.4.0: {} json-stable-stringify-without-jsonify@1.0.1: {} @@ -11212,6 +11429,10 @@ snapshots: dependencies: brace-expansion: 1.1.11 + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.1 + minimatch@9.0.5: dependencies: brace-expansion: 2.0.1 @@ -11226,6 +11447,8 @@ snapshots: minipass@7.0.4: {} + minipass@7.1.2: {} + minisearch@6.3.0: {} minizlib@2.1.2: @@ -11453,6 +11676,8 @@ snapshots: p-try@2.2.0: {} + package-json-from-dist@1.0.0: {} + pako@1.0.11: {} parent-module@1.0.1: @@ -11520,6 +11745,11 @@ snapshots: lru-cache: 10.2.0 minipass: 7.0.4 + path-scurry@1.11.1: + dependencies: + lru-cache: 10.2.0 + minipass: 7.1.2 + path-type@4.0.0: {} path-type@5.0.0: @@ -11647,6 +11877,9 @@ snapshots: '@slidev/parser': 0.47.5 prettier: 3.3.2 + prettier@2.8.7: + optional: true + prettier@2.8.8: {} prettier@3.3.2: {} @@ -11730,9 +11963,9 @@ snapshots: react-is@18.2.0: {} - reactive-vscode@0.2.0-beta.4(@types/vscode@1.89.0): + reactive-vscode@0.2.0-beta.5(@types/vscode@1.89.0): dependencies: - '@reactive-vscode/reactivity': 0.2.0-beta.4 + '@reactive-vscode/reactivity': 0.2.0-beta.5 '@types/vscode': 1.89.0 read-pkg-up@7.0.1: @@ -11790,12 +12023,18 @@ snapshots: dependencies: jsesc: 0.5.0 + request-light@0.5.8: {} + + request-light@0.7.0: {} + request-progress@3.0.0: dependencies: throttleit: 1.0.1 require-directory@2.1.1: {} + require-from-string@2.0.2: {} + requires-port@1.0.0: {} resolve-alpn@1.2.1: {} @@ -11890,6 +12129,8 @@ snapshots: safe-buffer@5.2.1: {} + safe-stable-stringify@2.4.3: {} + safer-buffer@2.1.2: {} sax@1.3.0: {} @@ -12234,6 +12475,8 @@ snapshots: tinyspy@2.2.0: {} + tm-grammars@1.13.11: {} + tmp@0.2.3: {} to-fast-properties@2.0.0: {} @@ -12275,6 +12518,17 @@ snapshots: ts-interface-checker@0.1.13: {} + ts-json-schema-generator@2.3.0: + dependencies: + '@types/json-schema': 7.0.15 + commander: 12.1.0 + glob: 10.4.5 + json5: 2.2.3 + normalize-path: 3.0.0 + safe-stable-stringify: 2.4.3 + tslib: 2.6.2 + typescript: 5.5.3 + tslib@1.14.1: {} tslib@2.4.0: {} @@ -12821,6 +13075,61 @@ snapshots: - supports-color - terser + volar-service-prettier@0.0.54(prettier@3.3.2): + dependencies: + vscode-uri: 3.0.8 + optionalDependencies: + prettier: 3.3.2 + + volar-service-yaml@0.0.59: + dependencies: + vscode-uri: 3.0.8 + yaml-language-server: 1.15.0 + + vscode-json-languageservice@4.1.8: + dependencies: + jsonc-parser: 3.2.1 + vscode-languageserver-textdocument: 1.0.11 + vscode-languageserver-types: 3.17.5 + vscode-nls: 5.2.0 + vscode-uri: 3.0.8 + + vscode-jsonrpc@6.0.0: {} + + vscode-jsonrpc@8.2.0: {} + + vscode-languageclient@9.0.1: + dependencies: + minimatch: 5.1.6 + semver: 7.6.2 + vscode-languageserver-protocol: 3.17.5 + + vscode-languageserver-protocol@3.16.0: + dependencies: + vscode-jsonrpc: 6.0.0 + vscode-languageserver-types: 3.16.0 + + vscode-languageserver-protocol@3.17.5: + dependencies: + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 + + vscode-languageserver-textdocument@1.0.11: {} + + vscode-languageserver-types@3.16.0: {} + + vscode-languageserver-types@3.17.5: {} + + vscode-languageserver@7.0.0: + dependencies: + vscode-languageserver-protocol: 3.16.0 + + vscode-languageserver@9.0.1: + dependencies: + vscode-languageserver-protocol: 3.17.5 + + vscode-nls@5.2.0: {} + vscode-uri@3.0.8: {} vue-demi@0.14.8(vue@3.4.32(typescript@5.5.3)): @@ -12951,6 +13260,23 @@ snapshots: lodash: 4.17.21 yaml: 2.4.5 + yaml-language-server@1.15.0: + dependencies: + ajv: 8.16.0 + lodash: 4.17.21 + request-light: 0.5.8 + vscode-json-languageservice: 4.1.8 + vscode-languageserver: 7.0.0 + vscode-languageserver-textdocument: 1.0.11 + vscode-languageserver-types: 3.17.5 + vscode-nls: 5.2.0 + vscode-uri: 3.0.8 + yaml: 2.2.2 + optionalDependencies: + prettier: 2.8.7 + + yaml@2.2.2: {} + yaml@2.4.5: {} yargs-parser@21.1.1: {} diff --git a/test/__snapshots__/parser.test.ts.snap b/test/__snapshots__/parser.test.ts.snap index 5676ad4ac9..bf1f01fcdb 100644 --- a/test/__snapshots__/parser.test.ts.snap +++ b/test/__snapshots__/parser.test.ts.snap @@ -216,7 +216,7 @@ This is note "end": 27, "filepath": "frontmatter.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 2, @@ -307,7 +307,7 @@ Also part of the code block "end": 50, "filepath": "frontmatter.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 4, @@ -454,7 +454,7 @@ Content 3 "end": 81, "filepath": "frontmatter.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 7, @@ -694,7 +694,7 @@ console.log('Hello World') "end": 10, "filepath": "minimal.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 0, @@ -741,7 +741,7 @@ console.log('Hello World') "end": 19, "filepath": "minimal.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 1, @@ -775,7 +775,7 @@ Nice to meet you "end": 23, "filepath": "minimal.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 2, @@ -886,7 +886,7 @@ exports[`md parser > multi-entries.md > slides 1`] = ` "end": 2, "filepath": "sub/page1.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 0, @@ -918,7 +918,7 @@ src: sub/page1.md "end": 2, "filepath": "sub/page1.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 0, @@ -1066,7 +1066,7 @@ background: https://sli.dev/demo-cover.png#34 "end": 2, "filepath": "sub/pages3-4.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 0, @@ -1129,7 +1129,7 @@ background: https://sli.dev/demo-cover.png#34 "end": 2, "filepath": "sub/pages3-4.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 0, @@ -1175,7 +1175,7 @@ background: https://sli.dev/demo-cover.png#34 "end": 2, "filepath": "sub/pages3-4.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 0, @@ -1309,7 +1309,7 @@ background: https://sli.dev/demo-cover.png#14 "end": 2, "filepath": "sub/page1.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 0, @@ -1408,7 +1408,7 @@ src: page2.md "end": 2, "filepath": "sub/pages3-4.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 0, @@ -1493,7 +1493,7 @@ background: https://sli.dev/demo-cover.png#14 "end": 2, "filepath": "sub/page1.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 0, @@ -1525,7 +1525,7 @@ src: /sub/page1.md "end": 2, "filepath": "sub/page1.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 0, @@ -1586,7 +1586,7 @@ background: https://sli.dev/demo-cover.png#14 "end": 2, "filepath": "sub/page1.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 0, @@ -1685,7 +1685,7 @@ src: page2.md "end": 2, "filepath": "sub/pages3-4.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 0, @@ -1886,7 +1886,7 @@ background: https://sli.dev/demo-cover.png#14 "end": 2, "filepath": "sub/page1.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 0, @@ -1985,7 +1985,7 @@ src: page2.md "end": 2, "filepath": "sub/pages3-4.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 0, @@ -2070,7 +2070,7 @@ background: https://sli.dev/demo-cover.png#14 "end": 2, "filepath": "sub/pages3-4.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 0, @@ -2132,7 +2132,7 @@ src: ../sub/pages3-4.md "end": 2, "filepath": "sub/pages3-4.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 0, @@ -2193,7 +2193,7 @@ background: https://sli.dev/demo-cover.png#14 "end": 2, "filepath": "sub/page1.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 0, @@ -2292,7 +2292,7 @@ src: page2.md "end": 2, "filepath": "sub/pages3-4.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 0, @@ -2377,7 +2377,7 @@ background: https://sli.dev/demo-cover.png#14 "end": 2, "filepath": "sub/pages3-4.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 0, @@ -2484,7 +2484,7 @@ $x+2$ "end": 25, "filepath": "multi-entries.md", "frontmatter": {}, - "frontmatterDoc": null, + "frontmatterDoc": undefined, "frontmatterRaw": undefined, "frontmatterStyle": undefined, "index": 4,