diff --git a/docs/tutorialkit.dev/src/content/docs/reference/configuration.mdx b/docs/tutorialkit.dev/src/content/docs/reference/configuration.mdx index b97a6e928..893a8ac50 100644 --- a/docs/tutorialkit.dev/src/content/docs/reference/configuration.mdx +++ b/docs/tutorialkit.dev/src/content/docs/reference/configuration.mdx @@ -174,7 +174,7 @@ Navigating to a lesson that specifies `autoReload` will always reload the previe ##### `template` -Specified which folder from the `src/templates/` directory should be used as the basis for the code. See the "[Code templates](/guides/creating-content/#code-templates)" guide for a detailed explainer. +Specifies which folder from the `src/templates/` directory should be used as the basis for the code. See the "[Code templates](/guides/creating-content/#code-templates)" guide for a detailed explainer. #### `editPageLink` diff --git a/extensions/vscode/build.mjs b/extensions/vscode/build.mjs deleted file mode 100644 index ca57d51e0..000000000 --- a/extensions/vscode/build.mjs +++ /dev/null @@ -1,70 +0,0 @@ -import * as esbuild from 'esbuild'; -import { execa } from 'execa'; -import fs from 'node:fs'; - -const production = process.argv.includes('--production'); -const watch = process.argv.includes('--watch'); - -async function main() { - const ctx = await esbuild.context({ - entryPoints: ['src/extension.ts'], - bundle: true, - format: 'cjs', - minify: production, - sourcemap: !production, - sourcesContent: false, - platform: 'node', - outfile: 'dist/extension.js', - external: ['vscode'], - logLevel: 'silent', - plugins: [ - // add to the end of plugins array - esbuildProblemMatcherPlugin, - ], - }); - - if (watch) { - await Promise.all([ - ctx.watch(), - execa('tsc', ['--noEmit', '--watch', '--project', 'tsconfig.json'], { stdio: 'inherit', preferLocal: true }), - ]); - } else { - await ctx.rebuild(); - await ctx.dispose(); - - if (production) { - // rename name in package json to match extension name on store - const pkgJSON = JSON.parse(fs.readFileSync('./package.json', { encoding: 'utf8' })); - - pkgJSON.name = 'tutorialkit'; - - fs.writeFileSync('./package.json', JSON.stringify(pkgJSON, undefined, 2), 'utf8'); - } - } -} - -/** - * @type {import('esbuild').Plugin} - */ -const esbuildProblemMatcherPlugin = { - name: 'esbuild-problem-matcher', - setup(build) { - build.onStart(() => { - console.log('[watch] Build started'); - }); - - build.onEnd((result) => { - result.errors.forEach(({ text, location }) => { - console.error(`✘ [ERROR] ${text}`); - console.error(` ${location.file}:${location.line}:${location.column}:`); - }); - - console.log('[watch] Build finished'); - }); - }, -}; - -main().catch((error) => { - console.error(error); - process.exit(1); -}); diff --git a/extensions/vscode/package.json b/extensions/vscode/package.json index 5d1a544ca..f66030df8 100644 --- a/extensions/vscode/package.json +++ b/extensions/vscode/package.json @@ -102,29 +102,53 @@ "when": "view == tutorialkit-lessons-tree && viewItem == part" } ] - } + }, + "languages": [ + { + "id": "markdown", + "extensions": [ + ".md" + ] + }, + { + "id": "mdx", + "extensions": [ + ".mdx" + ] + } + ] }, "scripts": { "__esbuild-base": "esbuild ./src/extension.ts --bundle --outfile=dist/extension.js --external:vscode --format=cjs --platform=node", "__dev": "pnpm run esbuild-base -- --sourcemap --watch", "__vscode:prepublish": "pnpm run esbuild-base -- --minify", "__build": "vsce package", - "dev": "node build.mjs --watch", - "build": "pnpm run check-types && node build.mjs", + "dev": "node scripts/build.mjs --watch", + "build": "pnpm run check-types && node scripts/build.mjs", "check-types": "tsc --noEmit", "vscode:prepublish": "pnpm run package", - "package": "pnpm run check-types && node build.mjs --production" + "package": "pnpm run check-types && node scripts/build.mjs --production" }, "dependencies": { + "@volar/language-core": "2.3.4", + "@volar/language-server": "2.3.4", + "@volar/language-service": "2.3.4", + "@volar/vscode": "2.3.4", "case-anything": "^3.1.0", - "gray-matter": "^4.0.3" + "gray-matter": "^4.0.3", + "volar-service-yaml": "volar-2.3", + "vscode-languageclient": "^9.0.1", + "vscode-uri": "^3.0.8", + "yaml-language-server": "1.15.0" }, "devDependencies": { - "@types/mocha": "^10.0.6", + "@tutorialkit/types": "workspace:*", "@types/node": "20.14.11", "@types/vscode": "^1.80.0", + "chokidar": "3.6.0", "esbuild": "^0.21.5", "execa": "^9.2.0", - "typescript": "^5.4.5" + "typescript": "^5.4.5", + "zod-to-json-schema": "3.23.1" } } diff --git a/extensions/vscode/scripts/build.mjs b/extensions/vscode/scripts/build.mjs new file mode 100644 index 000000000..48d1c8b45 --- /dev/null +++ b/extensions/vscode/scripts/build.mjs @@ -0,0 +1,117 @@ +import { watch } from 'chokidar'; +import * as esbuild from 'esbuild'; +import { execa } from 'execa'; +import fs from 'node:fs'; +import { createRequire } from 'node:module'; +import { join, dirname } from 'path'; +import { Worker } from 'node:worker_threads'; +import { fileURLToPath } from 'node:url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const require = createRequire(import.meta.url); +const production = process.argv.includes('--production'); +const isWatch = process.argv.includes('--watch'); + +async function main() { + const ctx = await esbuild.context({ + entryPoints: { + extension: 'src/extension.ts', + server: './src/language-server/index.ts', + }, + bundle: true, + format: 'cjs', + minify: production, + sourcemap: !production, + sourcesContent: false, + tsconfig: './tsconfig.json', + platform: 'node', + outdir: 'dist', + define: { 'process.env.NODE_ENV': production ? '"production"' : '"development"' }, + external: ['vscode'], + plugins: [esbuildUMD2ESMPlugin], + }); + + if (isWatch) { + const buildMetadataSchemaDebounced = debounce(buildMetadataSchema, 100); + const dependencyPath = dirname(require.resolve('@tutorialkit/types')); + + watch(dependencyPath).on('all', (eventName, path) => { + if (eventName !== 'change' && eventName !== 'add' && eventName !== 'unlink') { + return; + } + + buildMetadataSchemaDebounced(); + }); + + await Promise.all([ + ctx.watch(), + execa('tsc', ['--noEmit', '--watch', '--preserveWatchOutput', '--project', 'tsconfig.json'], { + stdio: 'inherit', + preferLocal: true, + }), + ]); + } else { + await ctx.rebuild(); + await ctx.dispose(); + + await buildMetadataSchema(); + + if (production) { + // rename name in `package.json` to match extension name on store + const pkgJSON = JSON.parse(fs.readFileSync('./package.json', { encoding: 'utf8' })); + + pkgJSON.name = 'tutorialkit'; + + fs.writeFileSync('./package.json', JSON.stringify(pkgJSON, undefined, 2), 'utf8'); + } + } +} + +async function buildMetadataSchema() { + const schema = await new Promise((resolve) => { + const worker = new Worker(join(__dirname, './load-schema-worker.mjs')); + worker.on('message', (value) => resolve(value)); + }); + + fs.mkdirSync('./dist', { recursive: true }); + fs.writeFileSync('./dist/schema.json', JSON.stringify(schema, undefined, 2), 'utf-8'); + + console.log('Updated schema.json'); +} + +/** + * @type {import('esbuild').Plugin} + */ +const esbuildUMD2ESMPlugin = { + name: 'umd2esm', + setup(build) { + build.onResolve({ filter: /^(vscode-.*-languageservice|jsonc-parser)/ }, (args) => { + const pathUmdMay = require.resolve(args.path, { paths: [args.resolveDir] }); + const pathEsm = pathUmdMay.replace('/umd/', '/esm/').replace('\\umd\\', '\\esm\\'); + + return { path: pathEsm }; + }); + }, +}; + +main().catch((error) => { + console.error(error); + process.exit(1); +}); + +/** + * Debounce the provided function. + * + * @param {Function} fn Function to debounce + * @param {number} duration Duration of the debounce + * @returns {Function} Debounced function + */ +function debounce(fn, duration) { + let timeoutId = 0; + + return function () { + clearTimeout(timeoutId); + + timeoutId = setTimeout(fn.bind(this), duration, ...arguments); + }; +} diff --git a/extensions/vscode/scripts/load-schema-worker.mjs b/extensions/vscode/scripts/load-schema-worker.mjs new file mode 100644 index 000000000..35036568d --- /dev/null +++ b/extensions/vscode/scripts/load-schema-worker.mjs @@ -0,0 +1,5 @@ +import { parentPort } from 'node:worker_threads'; +import { zodToJsonSchema } from 'zod-to-json-schema'; +import { contentSchema } from '@tutorialkit/types'; + +parentPort.postMessage(zodToJsonSchema(contentSchema)); diff --git a/extensions/vscode/src/extension.ts b/extensions/vscode/src/extension.ts index 37958594b..2a12a2065 100644 --- a/extensions/vscode/src/extension.ts +++ b/extensions/vscode/src/extension.ts @@ -1,16 +1,52 @@ +import * as serverProtocol from '@volar/language-server/protocol'; +import { createLabsInfo } from '@volar/vscode'; import * as vscode from 'vscode'; import { useCommands } from './commands'; import { useLessonTree } from './views/lessonsTree'; +import * as lsp from 'vscode-languageclient/node'; export let extContext: vscode.ExtensionContext; -export function activate(context: vscode.ExtensionContext) { +let client: lsp.BaseLanguageClient; + +export async function activate(context: vscode.ExtensionContext) { extContext = context; useCommands(); useLessonTree(); + + const serverModule = vscode.Uri.joinPath(context.extensionUri, 'dist', 'server.js'); + const runOptions = { execArgv: [] }; + const debugOptions = { execArgv: ['--nolazy', '--inspect=' + 6009] }; + + const serverOptions: lsp.ServerOptions = { + run: { + module: serverModule.fsPath, + transport: lsp.TransportKind.ipc, + options: runOptions, + }, + debug: { + module: serverModule.fsPath, + transport: lsp.TransportKind.ipc, + options: debugOptions, + }, + }; + + const clientOptions: lsp.LanguageClientOptions = { + documentSelector: [{ language: 'markdown' }, { language: 'mdx' }], + initializationOptions: {}, + }; + + client = new lsp.LanguageClient('tutorialkit-language-server', 'TutorialKit', serverOptions, clientOptions); + + await client.start(); + + const labsInfo = createLabsInfo(serverProtocol); + labsInfo.addLanguageClient(client); + + return labsInfo.extensionExports; } export function deactivate() { - // do nothing + return client?.stop(); } diff --git a/extensions/vscode/src/language-server/index.ts b/extensions/vscode/src/language-server/index.ts new file mode 100644 index 000000000..5d43b7615 --- /dev/null +++ b/extensions/vscode/src/language-server/index.ts @@ -0,0 +1,54 @@ +import { createConnection, createServer, createSimpleProject } from '@volar/language-server/node'; +import { create as createYamlService } from 'volar-service-yaml'; +import { SchemaPriority } from 'yaml-language-server'; +import { frontmatterPlugin } from './languagePlugin'; +import { readSchema } from './schema'; + +const connection = createConnection(); +const server = createServer(connection); + +connection.listen(); + +connection.onInitialize((params) => { + const yamlService = createYamlService({ + getLanguageSettings(_context) { + const schema = readSchema(); + + return { + completion: true, + validate: true, + hover: true, + format: true, + yamlVersion: '1.2', + isKubernetes: false, + schemas: [ + { + uri: 'https://tutorialkit.dev/reference/configuration', + schema, + fileMatch: [ + '**/*', + + // TODO: these don't work + 'src/content/*.md', + 'src/content/**/*.md', + 'src/content/**/*.mdx', + ], + priority: SchemaPriority.Settings, + }, + ], + }; + }, + }); + + delete yamlService.capabilities.codeLensProvider; + + return server.initialize( + params, + createSimpleProject([frontmatterPlugin(connection.console.debug.bind(connection.console.debug))]), + [yamlService], + ); +}); + +connection.onInitialized(server.initialized); + +connection.onShutdown(server.shutdown); diff --git a/extensions/vscode/src/language-server/languagePlugin.ts b/extensions/vscode/src/language-server/languagePlugin.ts new file mode 100644 index 000000000..9b1996509 --- /dev/null +++ b/extensions/vscode/src/language-server/languagePlugin.ts @@ -0,0 +1,101 @@ +import { CodeMapping, type LanguagePlugin, type VirtualCode } from '@volar/language-core'; +import type * as ts from 'typescript'; +import type { URI } from 'vscode-uri'; + +export function frontmatterPlugin(debug: (message: string) => void): LanguagePlugin { + return { + getLanguageId(uri) { + debug('URI: ' + uri.path); + + if (uri.path.endsWith('.md')) { + return 'markdown'; + } + + if (uri.path.endsWith('.mdx')) { + return 'mdx'; + } + + return undefined; + }, + createVirtualCode(_uri, languageId, snapshot) { + if (languageId === 'markdown' || languageId === 'mdx') { + return new FrontMatterVirtualCode(snapshot); + } + + return undefined; + }, + }; +} + +export class FrontMatterVirtualCode implements VirtualCode { + id = 'root'; + languageId = 'markdown'; + mappings: CodeMapping[]; + embeddedCodes: VirtualCode[] = []; + + constructor(public snapshot: ts.IScriptSnapshot) { + this.mappings = [ + { + sourceOffsets: [0], + generatedOffsets: [0], + lengths: [snapshot.getLength()], + data: { + completion: true, + format: true, + navigation: true, + semantic: true, + structure: true, + verification: true, + }, + }, + ]; + + this.embeddedCodes = [...frontMatterCode(snapshot)]; + } +} + +function* frontMatterCode(snapshot: ts.IScriptSnapshot): Generator { + const content = snapshot.getText(0, snapshot.getLength()); + + let frontMatterStartIndex = content.indexOf('---'); + + if (frontMatterStartIndex === -1) { + return; + } + + frontMatterStartIndex += 3; + + let frontMatterEndIndex = content.indexOf('---', frontMatterStartIndex); + + if (frontMatterEndIndex === -1) { + frontMatterEndIndex = snapshot.getLength(); + } + + const frontMatterText = content.substring(frontMatterStartIndex, frontMatterEndIndex); + + yield { + id: 'frontmatter_1', + languageId: 'yaml', + snapshot: { + getText: (start, end) => frontMatterText.slice(start, end), + getLength: () => frontMatterText.length, + getChangeRange: () => undefined, + }, + mappings: [ + { + sourceOffsets: [frontMatterStartIndex], + generatedOffsets: [0], + lengths: [frontMatterText.length], + data: { + completion: true, + format: true, + navigation: true, + semantic: true, + structure: true, + verification: true, + }, + }, + ], + embeddedCodes: [], + }; +} diff --git a/extensions/vscode/src/language-server/schema.ts b/extensions/vscode/src/language-server/schema.ts new file mode 100644 index 000000000..4e3f5db20 --- /dev/null +++ b/extensions/vscode/src/language-server/schema.ts @@ -0,0 +1,11 @@ +import fs from 'node:fs'; +import path from 'node:path'; + +export function readSchema() { + try { + const fileContent = fs.readFileSync(path.join(__dirname, './schema.json'), 'utf-8'); + return JSON.parse(fileContent); + } catch { + return {}; + } +} diff --git a/extensions/vscode/tsconfig.json b/extensions/vscode/tsconfig.json index 69df86d3d..e029bdc09 100644 --- a/extensions/vscode/tsconfig.json +++ b/extensions/vscode/tsconfig.json @@ -1,12 +1,15 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "allowJs": true, "module": "Node16", "target": "ES2022", "outDir": "dist", "lib": ["ES2022"], "verbatimModuleSyntax": false, "sourceMap": true, - "rootDir": "src" - } + "rootDir": "." + }, + "include": ["src", "scripts"], + "references": [{ "path": "../../packages/types" }] } diff --git a/package.json b/package.json index 5669d9b9c..2ca59d40c 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "changelog": "./scripts/changelog.mjs", "clean": "./scripts/clean.sh", "prepare": "is-ci || husky install", - "extension:dev": "pnpm run --filter=tutorialkit-vscode dev", + "extension:dev": "pnpm --parallel --stream --filter=@tutorialkit/types --filter=tutorialkit-vscode run dev", "extension:build": "pnpm run --filter=tutorialkit-vscode build", "template:dev": "TUTORIALKIT_DEV=true pnpm run build && pnpm run --filter=tutorialkit-starter dev", "template:build": "pnpm run build && pnpm run --filter=tutorialkit-starter build", diff --git a/packages/types/src/schemas/chapter.ts b/packages/types/src/schemas/chapter.ts index 7b0cff182..24d29c371 100644 --- a/packages/types/src/schemas/chapter.ts +++ b/packages/types/src/schemas/chapter.ts @@ -3,7 +3,12 @@ import { baseSchema } from './common.js'; export const chapterSchema = baseSchema.extend({ type: z.literal('chapter'), - lessons: z.array(z.string()).optional(), + lessons: z + .array(z.string()) + .optional() + .describe( + 'The list of lessons in this chapter. The order of the array defines the order of the lessons. If not specified a folder-based numbering system is used instead.', + ), }); export type ChapterSchema = z.infer; diff --git a/packages/types/src/schemas/common.ts b/packages/types/src/schemas/common.ts index 3c4bb9e01..e071489be 100644 --- a/packages/types/src/schemas/common.ts +++ b/packages/types/src/schemas/common.ts @@ -9,16 +9,21 @@ export const commandSchema = z.union([ z.tuple([z.string(), z.string()]), z.strictObject({ - command: z.string(), - title: z.string(), + command: z.string().describe('Command to execute in WebContainer.'), + title: z.string().describe('Title to show for this step in the Prepare Environment section.'), }), ]); export type CommandSchema = z.infer; export const commandsSchema = z.object({ - mainCommand: commandSchema.optional(), - prepareCommands: commandSchema.array().optional(), + mainCommand: commandSchema.optional().describe('The last command to be executed. Typically a dev server.'), + prepareCommands: commandSchema + .array() + .optional() + .describe( + 'List of commands to be executed to prepare the environment in WebContainer. Each command executed and its status will be shown in the Prepare Environment section.', + ), }); export type CommandsSchema = z.infer; @@ -36,8 +41,8 @@ export const previewSchema = z.union([ z.tuple([z.number(), z.string()]), z.strictObject({ - port: z.number(), - title: z.string(), + port: z.number().describe('Port number of the preview.'), + title: z.string().describe('Title of the preview.'), }), ]) .array(), @@ -45,7 +50,19 @@ export const previewSchema = z.union([ export type PreviewSchema = z.infer; -const panelType = z.union([z.literal('output'), z.literal('terminal')]); +const panelTypeSchema = z + .union([z.literal('output'), z.literal('terminal')]) + .describe(`The type of the terminal which can either be 'output' or 'terminal'.`); + +const allowRedirectsSchema = z + .boolean() + .optional() + .describe("Set to `true` if you want to enable output redirects in the terminal. It's disabled by default."); + +const allowCommandsSchema = z + .array(z.string()) + .optional() + .describe('List of command that are allowed in the terminal, if not provided, all commands are allowed.'); export const terminalSchema = z.union([ // `false` if you want to disable the terminal entirely @@ -67,12 +84,12 @@ export const terminalSchema = z.union([ .array( z.union([ // the type of the panel - panelType, + panelTypeSchema, // or a tuple with the type and the title of the panel z.tuple([ // the type of the panel - panelType, + panelTypeSchema, // the title of the panel which is shown in the tab z.string(), @@ -81,19 +98,24 @@ export const terminalSchema = z.union([ // or an object defining the panel z.strictObject({ // the type of the panel - type: panelType, + type: panelTypeSchema, // an id linking the terminal of multiple lessons together - id: z.string().optional(), + id: z + .string() + .optional() + .describe( + 'An id linking the terminal of multiple lessons together so that its state is preserved between lessons.', + ), // the title of the panel which is shown in the tab - title: z.string().optional(), + title: z.string().optional().describe('The title of the panel which is shown in the tab.'), // `true` if you want to enable output redirects in the terminal, disabled by default - allowRedirects: z.boolean().optional(), + allowRedirects: allowRedirectsSchema, // list of command that are allowed in the terminal, if not provided, all commands are allowed - allowCommands: z.array(z.string()).optional(), + allowCommands: allowCommandsSchema, }), ]), ) @@ -122,35 +144,62 @@ export const terminalSchema = z.union([ }, ), ]), - activePanel: z.number().gte(0).optional(), + activePanel: z.number().gte(0).optional().describe('Defines which panel should be visible by default.'), // `true` if you want to enable output redirects in the terminal, disabled by default - allowRedirects: z.boolean().optional(), + allowRedirects: allowRedirectsSchema, // list of command that are allowed in the terminal, if not provided, all commands are allowed - allowCommands: z.array(z.string()).optional(), + allowCommands: allowCommandsSchema, }), ]); -export type TerminalPanelType = z.infer; +export type TerminalPanelType = z.infer; export type TerminalSchema = z.infer; export const webcontainerSchema = commandsSchema.extend({ - previews: previewSchema.optional(), - autoReload: z.boolean().optional(), - template: z.string().optional(), - terminal: terminalSchema.optional(), - focus: z.string().optional(), - editor: z.union([ - // can either be completely removed by setting it to `false` - z.boolean().optional(), - - // or you can only remove the file tree - z.strictObject({ - fileTree: z.boolean().optional(), - }), - ]), - i18n: i18nSchema.optional(), + previews: previewSchema + .optional() + .describe( + 'Configure which ports should be used for the previews allowing you to align the behavior with your demo application’s dev server setup. If not specified, the lowest port will be used.', + ), + autoReload: z + .boolean() + .optional() + .describe( + 'Navigating to a lesson that specifies autoReload will always reload the preview. This is typically only needed if your server does not support HMR.', + ), + template: z + .string() + .optional() + .describe( + 'Specifies which folder from the `src/templates/` directory should be used as the basis for the code. See the "Code templates" guide for a detailed explainer.', + ), + terminal: terminalSchema + .optional() + .describe( + 'Configures one or more terminals. TutorialKit provides two types of terminals: read-only, called output, and interactive, called terminal.', + ), + focus: z + .string() + .optional() + .describe('Defines which file should be opened in the code editor by default when lesson loads.'), + editor: z + .union([ + // can either be completely removed by setting it to `false` + z.boolean().optional(), + + // or you can only remove the file tree + z.strictObject({ + fileTree: z.boolean().optional(), + }), + ]) + .describe( + 'Configure whether or not the editor should be rendered. If an object is provided with fileTree: false, only the file tree is hidden.', + ), + i18n: i18nSchema + .optional() + .describe('Lets you define alternative texts used in the UI. This is useful for localization.'), editPageLink: z .union([ // pattern for creating the URL @@ -159,12 +208,20 @@ export const webcontainerSchema = commandsSchema.extend({ // `false` for disabling the edit link z.boolean(), ]) - .optional(), + .optional() + .describe( + 'Display a link in lesson for editing the page content. The value is a URL pattern where `${path}` is replaced with the lesson’s location relative to `src/content/tutorial`.', + ), }); export const baseSchema = webcontainerSchema.extend({ - title: z.string(), - slug: z.string().optional(), + title: z.string().describe('The title of the part, chapter, or lesson.'), + slug: z + .string() + .optional() + .describe( + 'Customize the URL segment of this part, chapter or lesson. The full URL path is `/:partSlug/:chapterSlug/:lessonSlug`.', + ), }); export type BaseSchema = z.infer; diff --git a/packages/types/src/schemas/i18n.ts b/packages/types/src/schemas/i18n.ts index d9881bfdc..cdd49e50c 100644 --- a/packages/types/src/schemas/i18n.ts +++ b/packages/types/src/schemas/i18n.ts @@ -6,64 +6,69 @@ export const i18nSchema = z.object({ * * @default 'Part ${index}: ${title}' */ - partTemplate: z.string().optional(), + partTemplate: z.string().optional().describe('Template on how to format a part. Variables: ${index} and ${title}.'), /** * Text of the edit page link. * * @default 'Edit this page' */ - editPageText: z.string().optional(), + editPageText: z.string().optional().describe('Text of the edit page link.'), /** * Text shown when there are no previews or steps to show in the prepare environment section. * * @default 'Start WebContainer' */ - startWebContainerText: z.string().optional(), + startWebContainerText: z + .string() + .optional() + .describe('Text shown when there are no previews or steps to show in the prepare environment section.'), /** - * Text shown on the call to action button to start webcontainer when boot was blocked - * due to memory restrictions. + * Text shown in the preview section when there are no steps to run and no preview to show. * * @default 'No preview to run nor steps to show' */ - noPreviewNorStepsText: z.string().optional(), + noPreviewNorStepsText: z + .string() + .optional() + .describe('Text shown in the preview section when there are no steps to run and no preview to show.'), /** * Text shown on top of the file tree. * * @default 'Files' */ - filesTitleText: z.string().optional(), + filesTitleText: z.string().optional().describe('Text shown on top of the file tree.'), /** * Text shown on top of the steps section. * * @default 'Preparing Environment' */ - prepareEnvironmentTitleText: z.string().optional(), + prepareEnvironmentTitleText: z.string().optional().describe('Text shown on top of the steps section.'), /** - * Text shown for the toggle terminal button. + * Text for the toggle terminal button. * * @default 'Toggle Terminal' */ - toggleTerminalButtonText: z.string().optional(), + toggleTerminalButtonText: z.string().optional().describe('Text for the toggle terminal button.'), /** - * Text shown for the solve button. + * Text for the solve button. * * @default 'Solve' */ - solveButtonText: z.string().optional(), + solveButtonText: z.string().optional().describe('Text for the solve button.'), /** - * Text shown for the reset button. + * Text for the reset button. * * @default 'Reset' */ - resetButtonText: z.string().optional(), + resetButtonText: z.string().optional().describe('Text for the reset button.'), }); export type I18nSchema = z.infer; diff --git a/packages/types/src/schemas/lesson.ts b/packages/types/src/schemas/lesson.ts index 7b501d7c5..73e3d8bb2 100644 --- a/packages/types/src/schemas/lesson.ts +++ b/packages/types/src/schemas/lesson.ts @@ -3,8 +3,11 @@ import { baseSchema } from './common.js'; export const lessonSchema = baseSchema.extend({ type: z.literal('lesson'), - scope: z.string().optional(), - hideRoot: z.boolean().optional(), + scope: z.string().optional().describe('A prefix that all file paths must match to be visible in the file tree.'), + hideRoot: z + .boolean() + .optional() + .describe('If set to false, `/` is shown at the top of the file tree. Defaults to true.'), }); export type LessonSchema = z.infer; diff --git a/packages/types/src/schemas/part.ts b/packages/types/src/schemas/part.ts index cce512857..ce3682e1b 100644 --- a/packages/types/src/schemas/part.ts +++ b/packages/types/src/schemas/part.ts @@ -3,7 +3,12 @@ import { baseSchema } from './common.js'; export const partSchema = baseSchema.extend({ type: z.literal('part'), - chapters: z.array(z.string()).optional(), + chapters: z + .array(z.string()) + .optional() + .describe( + 'The list of chapters in this part. The order of this array defines the order of the chapters. If not specified a folder-based numbering system is used instead.', + ), }); export type PartSchema = z.infer; diff --git a/packages/types/src/schemas/tutorial.ts b/packages/types/src/schemas/tutorial.ts index 0f86c1339..6ae8bf4fc 100644 --- a/packages/types/src/schemas/tutorial.ts +++ b/packages/types/src/schemas/tutorial.ts @@ -4,7 +4,12 @@ import { webcontainerSchema } from './common.js'; export const tutorialSchema = webcontainerSchema.extend({ type: z.literal('tutorial'), logoLink: z.string().optional(), - parts: z.array(z.string()).optional(), + parts: z + .array(z.string()) + .optional() + .describe( + 'The list of parts in this tutorial. The order of this array defines the order of the parts. If not specified a folder-based numbering system is used instead.', + ), }); export type TutorialSchema = z.infer; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 08c4b5203..f71e3dcbb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -166,22 +166,49 @@ importers: extensions/vscode: dependencies: + '@volar/language-core': + specifier: 2.3.4 + version: 2.3.4 + '@volar/language-server': + specifier: 2.3.4 + version: 2.3.4 + '@volar/language-service': + specifier: 2.3.4 + version: 2.3.4 + '@volar/vscode': + specifier: 2.3.4 + version: 2.3.4 case-anything: specifier: ^3.1.0 version: 3.1.0 gray-matter: specifier: ^4.0.3 version: 4.0.3 + volar-service-yaml: + specifier: volar-2.3 + version: 0.0.54(@volar/language-service@2.3.4) + vscode-languageclient: + specifier: ^9.0.1 + version: 9.0.1 + vscode-uri: + specifier: ^3.0.8 + version: 3.0.8 + yaml-language-server: + specifier: 1.15.0 + version: 1.15.0 devDependencies: - '@types/mocha': - specifier: ^10.0.6 - version: 10.0.7 + '@tutorialkit/types': + specifier: workspace:* + version: link:../../packages/types '@types/node': specifier: 20.14.11 version: 20.14.11 '@types/vscode': specifier: ^1.80.0 version: 1.91.0 + chokidar: + specifier: 3.6.0 + version: 3.6.0 esbuild: specifier: ^0.21.5 version: 0.21.5 @@ -191,6 +218,9 @@ importers: typescript: specifier: ^5.4.5 version: 5.5.3 + zod-to-json-schema: + specifier: 3.23.1 + version: 3.23.1(zod@3.23.8) integration: dependencies: @@ -3130,10 +3160,6 @@ packages: /@types/mdx@2.0.13: resolution: {integrity: sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==} - /@types/mocha@10.0.7: - resolution: {integrity: sha512-GN8yJ1mNTcFcah/wKEFIJckJx9iJLoMSzWcfRRuxz/Jk+U6KQNnml+etbtxFK8lPjzOw3zp4Ha/kjSst9fsHYw==} - dev: true - /@types/ms@0.7.34: resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} @@ -3622,12 +3648,33 @@ packages: vscode-uri: 3.0.8 dev: true + /@volar/language-core@2.3.4: + resolution: {integrity: sha512-wXBhY11qG6pCDAqDnbBRFIDSIwbqkWI7no+lj5+L7IlA7HRIjRP7YQLGzT0LF4lS6eHkMSsclXqy9DwYJasZTQ==} + dependencies: + '@volar/source-map': 2.3.4 + dev: false + /@volar/language-core@2.4.0-alpha.16: resolution: {integrity: sha512-oOTnIZlx0P/idFwVw+W0NbzKDtZAQMzXSdIFfTePCKcXlb4Ys12GaGkx8NF9dsvPYV3nbv3ZsSxnkZWBmNKd7A==} dependencies: '@volar/source-map': 2.4.0-alpha.16 dev: true + /@volar/language-server@2.3.4: + resolution: {integrity: sha512-I0usa8dI0nTVTqbNyVTQNMDMOHeOaBs84Onmr6oJH3K0EiqLb+Py/Zd5hP/mX22P6MQLhPI2cMVmk0DrSyZFaw==} + dependencies: + '@volar/language-core': 2.3.4 + '@volar/language-service': 2.3.4 + '@volar/snapshot-document': 2.3.4 + '@volar/typescript': 2.3.4 + 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 + dev: false + /@volar/language-server@2.4.0-alpha.16: resolution: {integrity: sha512-DswMBlmmXPo9fb1Dmb2qrCtxRDgQPej5jUjAoUm+1wO5k02Tk+jIvbbd/R3EzyHFTARmiRH5/bSOfRefHyuMsg==} dependencies: @@ -3643,6 +3690,15 @@ packages: vscode-uri: 3.0.8 dev: true + /@volar/language-service@2.3.4: + resolution: {integrity: sha512-mtzvYb33l17VVRwmX7C39EjVHBU9LbBJeo1rLXFKoXOzbZCanm0XtPZEENsm05VUvse929y4ParujW7k4G5H0w==} + dependencies: + '@volar/language-core': 2.3.4 + vscode-languageserver-protocol: 3.17.5 + vscode-languageserver-textdocument: 1.0.11 + vscode-uri: 3.0.8 + dev: false + /@volar/language-service@2.4.0-alpha.16: resolution: {integrity: sha512-iIRUY0EL9jp8Od7Py/GlYpCu469GFDYl7ai716pQgwipjpjEjRQiuGAD2+cSFjOVXDsMPFpJ+Dpei7aSvE/8pQ==} dependencies: @@ -3652,6 +3708,13 @@ packages: vscode-uri: 3.0.8 dev: true + /@volar/snapshot-document@2.3.4: + resolution: {integrity: sha512-mSyxrKWa181r5Hv7CRjwrYXEnzqBLJ3M2Nse9+0KPRff2pAGIx0yl03O7e3Z7IyvMAkXxv3MIVYvP14zY3gVEQ==} + dependencies: + vscode-languageserver-protocol: 3.17.5 + vscode-languageserver-textdocument: 1.0.11 + dev: false + /@volar/snapshot-document@2.4.0-alpha.16: resolution: {integrity: sha512-X9xZeLvkmhjkrz27J6nq9JhYWV8AUT1KS9fi4s+Mo1FOh5HHUIx/QzhrwsUN/pY1z3kO+vtrl2DE6NVJRYwwbw==} dependencies: @@ -3659,10 +3722,22 @@ packages: vscode-languageserver-textdocument: 1.0.11 dev: true + /@volar/source-map@2.3.4: + resolution: {integrity: sha512-C+t63nwcblqLIVTYXaVi/+gC8NukDaDIQI72J3R7aXGvtgaVB16c+J8Iz7/VfOy7kjYv7lf5GhBny6ACw9fTGQ==} + dev: false + /@volar/source-map@2.4.0-alpha.16: resolution: {integrity: sha512-sL9vNG7iR2hiKZor7UkD5Sufu3QCia4cbp2gX/nGRNSdaPbhOpdAoavwlBm0PrVkpiA19NZuavZoobD8krviFg==} dev: true + /@volar/typescript@2.3.4: + resolution: {integrity: sha512-acCvt7dZECyKcvO5geNybmrqOsu9u8n5XP1rfiYsOLYGPxvHRav9BVmEdRyZ3vvY6mNyQ1wLL5Hday4IShe17w==} + dependencies: + '@volar/language-core': 2.3.4 + path-browserify: 1.0.1 + vscode-uri: 3.0.8 + dev: false + /@volar/typescript@2.4.0-alpha.16: resolution: {integrity: sha512-WCx7z5O81McCQp2cC0c8081y+MgTiAR2WAiJjVL4tr4Qh4GgqK0lgn3CqAjcKizaK1R5y3wfrUqgIYr+QeFYcw==} dependencies: @@ -3671,6 +3746,15 @@ packages: vscode-uri: 3.0.8 dev: true + /@volar/vscode@2.3.4: + resolution: {integrity: sha512-rdsFjEvRiQbh16a/vhp64aQ/7nxpbWGIC8NmTkaXRCH1YBCMs/06akhXy7lriw3XDDtv9/ntu2eMZgIGnyohIw==} + dependencies: + '@volar/language-server': 2.3.4 + path-browserify: 1.0.1 + vscode-languageclient: 9.0.1 + vscode-nls: 5.2.0 + dev: false + /@vscode/emmet-helper@2.9.3: resolution: {integrity: sha512-rB39LHWWPQYYlYfpv9qCoZOVioPCftKXXqrsyqN1mTWZM6dTnONT63Db+03vgrBbHzJN45IrgS/AGxw9iiqfEw==} dependencies: @@ -3759,7 +3843,6 @@ packages: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 uri-js: 4.4.1 - dev: true /ansi-align@3.0.1: resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} @@ -3971,7 +4054,6 @@ packages: /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true /bare-events@2.4.2: resolution: {integrity: sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==} @@ -4068,7 +4150,6 @@ packages: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} dependencies: balanced-match: 1.0.2 - dev: true /braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} @@ -5106,7 +5187,6 @@ packages: /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true /fast-diff@1.3.0: resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} @@ -5907,7 +5987,6 @@ packages: /json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - dev: true /json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -5932,6 +6011,10 @@ packages: resolution: {integrity: sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg==} dev: true + /jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + dev: false + /jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} dependencies: @@ -6049,6 +6132,10 @@ packages: resolution: {integrity: sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==} dev: true + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: false + /log-symbols@6.0.0: resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} engines: {node: '>=18'} @@ -6654,6 +6741,13 @@ packages: brace-expansion: 1.1.11 dev: true + /minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: false + /minimatch@9.0.4: resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} engines: {node: '>=16 || 14 >=14.17'} @@ -6975,7 +7069,6 @@ packages: /path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} - dev: true /path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} @@ -7119,6 +7212,14 @@ packages: sass-formatter: 0.7.9 dev: true + /prettier@2.8.7: + resolution: {integrity: sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==} + engines: {node: '>=10.13.0'} + hasBin: true + requiresBuild: true + dev: false + optional: true + /prettier@3.3.2: resolution: {integrity: sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==} engines: {node: '>=14'} @@ -7163,7 +7264,6 @@ packages: /punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - dev: true /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -7388,9 +7488,12 @@ packages: mdast-util-to-markdown: 2.1.0 unified: 11.0.5 + /request-light@0.5.8: + resolution: {integrity: sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg==} + dev: false + /request-light@0.7.0: resolution: {integrity: sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q==} - dev: true /require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} @@ -7400,7 +7503,6 @@ packages: /require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - dev: true /resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} @@ -8329,7 +8431,6 @@ packages: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: punycode: 2.3.1 - dev: true /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -8632,6 +8733,19 @@ packages: vscode-uri: 3.0.8 dev: true + /volar-service-yaml@0.0.54(@volar/language-service@2.3.4): + resolution: {integrity: sha512-gT+RbDviF3XfavtzlLCI3ai7c12do5dricXIEJ5Gg1t2Cy+6n6x4bLaqQgyOwcPVRh35Hti6hvUJ5LQUuuzpkw==} + peerDependencies: + '@volar/language-service': ~2.3.1 + peerDependenciesMeta: + '@volar/language-service': + optional: true + dependencies: + '@volar/language-service': 2.3.4 + vscode-uri: 3.0.8 + yaml-language-server: 1.15.0 + dev: false + /vscode-css-languageservice@6.3.0: resolution: {integrity: sha512-nU92imtkgzpCL0xikrIb8WvedV553F2BENzgz23wFuok/HLN5BeQmroMy26pUwFxV2eV8oNRmYCUv8iO7kSMhw==} dependencies: @@ -8650,36 +8764,73 @@ packages: vscode-uri: 3.0.8 dev: true + /vscode-json-languageservice@4.1.8: + resolution: {integrity: sha512-0vSpg6Xd9hfV+eZAaYN63xVVMOTmJ4GgHxXnkLCh+9RsQBkWKIghzLhW2B9ebfG+LQQg8uLtsQ2aUKjTgE+QOg==} + engines: {npm: '>=7.0.0'} + dependencies: + jsonc-parser: 3.3.1 + vscode-languageserver-textdocument: 1.0.11 + vscode-languageserver-types: 3.17.5 + vscode-nls: 5.2.0 + vscode-uri: 3.0.8 + dev: false + + /vscode-jsonrpc@6.0.0: + resolution: {integrity: sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg==} + engines: {node: '>=8.0.0 || >=10.0.0'} + dev: false + /vscode-jsonrpc@8.2.0: resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==} engines: {node: '>=14.0.0'} - dev: true + + /vscode-languageclient@9.0.1: + resolution: {integrity: sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA==} + engines: {vscode: ^1.82.0} + dependencies: + minimatch: 5.1.6 + semver: 7.6.2 + vscode-languageserver-protocol: 3.17.5 + dev: false + + /vscode-languageserver-protocol@3.16.0: + resolution: {integrity: sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A==} + dependencies: + vscode-jsonrpc: 6.0.0 + vscode-languageserver-types: 3.16.0 + dev: false /vscode-languageserver-protocol@3.17.5: resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==} dependencies: vscode-jsonrpc: 8.2.0 vscode-languageserver-types: 3.17.5 - dev: true /vscode-languageserver-textdocument@1.0.11: resolution: {integrity: sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA==} - dev: true + + /vscode-languageserver-types@3.16.0: + resolution: {integrity: sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA==} + dev: false /vscode-languageserver-types@3.17.5: resolution: {integrity: sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==} - dev: true + + /vscode-languageserver@7.0.0: + resolution: {integrity: sha512-60HTx5ID+fLRcgdHfmz0LDZAXYEV68fzwG0JWwEPBode9NuMYTIxuYXPg4ngO8i8+Ou0lM7y6GzaYWbiDL0drw==} + hasBin: true + dependencies: + vscode-languageserver-protocol: 3.16.0 + dev: false /vscode-languageserver@9.0.1: resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} hasBin: true dependencies: vscode-languageserver-protocol: 3.17.5 - dev: true /vscode-nls@5.2.0: resolution: {integrity: sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng==} - dev: true /vscode-uri@2.1.2: resolution: {integrity: sha512-8TEXQxlldWAuIODdukIb+TR5s+9Ds40eSJrw+1iDDA9IFORPjMELarNQE3myz5XIkWWpdprmJjm1/SxMlWOC8A==} @@ -8687,7 +8838,6 @@ packages: /vscode-uri@3.0.8: resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} - dev: true /w3c-keyname@2.2.8: resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} @@ -8772,6 +8922,29 @@ packages: /yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + /yaml-language-server@1.15.0: + resolution: {integrity: sha512-N47AqBDCMQmh6mBLmI6oqxryHRzi33aPFPsJhYy3VTUGCdLHYjGh4FZzpUjRlphaADBBkDmnkM/++KNIOHi5Rw==} + hasBin: true + 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 + dev: false + + /yaml@2.2.2: + resolution: {integrity: sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==} + engines: {node: '>= 14'} + dev: false + /yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'}