monaco-yaml
Version:
YAML plugin for the Monaco Editor
229 lines (191 loc) • 6.43 kB
text/typescript
import type {
CodeAction,
CodeActionContext,
CodeLens,
CompletionList,
Diagnostic,
DocumentLink,
DocumentSymbol,
FoldingRange,
FormattingOptions,
Hover,
LocationLink,
Position,
Range,
SelectionRange,
TextEdit,
WorkspaceEdit
} from 'vscode-languageserver-types'
import type { Telemetry } from 'yaml-language-server/lib/esm/languageservice/telemetry.js'
import type { MonacoYamlOptions } from './index.js'
import { initialize } from 'monaco-worker-manager/worker'
import { TextDocument } from 'vscode-languageserver-textdocument'
import { getLanguageService } from 'yaml-language-server/lib/esm/languageservice/yamlLanguageService.js'
/**
* Fetch the given URL and return the response body as text.
*
* @param uri
* The uri to fetch.
* @returns
* The response body as text.
*/
async function schemaRequestService(uri: string): Promise<string> {
const response = await fetch(uri)
if (response.ok) {
return response.text()
}
throw new Error(`Schema request failed for ${uri}`)
}
/**
* @internal
*/
export interface YAMLWorker {
/**
* Validate a document.
*/
doValidation: (uri: string) => Diagnostic[] | undefined
/**
* Get completions in a YAML document.
*/
doComplete: (uri: string, position: Position) => CompletionList | undefined
/**
* Get definitions in a YAML document.
*/
doDefinition: (uri: string, position: Position) => LocationLink[] | undefined
/**
* Get hover information in a YAML document.
*/
doHover: (uri: string, position: Position) => Hover | null | undefined
/**
* Get formatting edits when the user types in a YAML document.
*/
doDocumentOnTypeFormatting: (
uri: string,
position: Position,
ch: string,
options: FormattingOptions
) => TextEdit[] | undefined
/**
* Perform a rename in a YAML document.
*/
doRename: (uri: string, position: Position, newName: string) => null | undefined | WorkspaceEdit
/**
* Format a YAML document.
*/
format: (uri: string) => TextEdit[] | undefined
/**
* Reset the schema state for a YAML document.
*/
resetSchema: (uri: string) => boolean
/**
* Get document symbols in a YAML document.
*/
findDocumentSymbols: (uri: string) => DocumentSymbol[] | undefined
/**
* Get links in a YAML document.
*/
findLinks: (uri: string) => DocumentLink[] | undefined
/**
* Get code actions in a YAML document.
*/
getCodeAction: (uri: string, range: Range, context: CodeActionContext) => CodeAction[] | undefined
/**
* Get the code lens of a YAML document.
*/
getCodeLens: (uri: string) => CodeLens[] | undefined
/**
* Get folding ranges in a YAML document.
*/
getFoldingRanges: (uri: string) => FoldingRange[] | null | undefined
/**
* Get selection ranges in a YAML document
*/
getSelectionRanges: (uri: string, positions: Position[]) => SelectionRange[] | undefined
/**
* Prepare a rename in a YAML document.
*/
prepareRename: (uri: string, position: Position) => null | Range | undefined
}
const telemetry: Telemetry = {
send() {
// Do nothing
},
sendError(name, error) {
// eslint-disable-next-line no-console
console.error('monaco-yaml', name, error)
},
sendTrack() {
// Do nothing
}
}
initialize<YAMLWorker, MonacoYamlOptions>(
(ctx, { enableSchemaRequest, format, ...languageSettings }) => {
const ls = getLanguageService({
// @ts-expect-error Type definitions are wrong. This may be null.
schemaRequestService: enableSchemaRequest ? schemaRequestService : null,
telemetry,
workspaceContext: {
resolveRelativePath(relativePath, resource) {
return String(new URL(relativePath, resource))
}
},
// Copied from https://github.com/microsoft/vscode-json-languageservice/blob/493010da9dc2cd1cc139d403d4709d97064b17e9/src/jsonLanguageTypes.ts#L325-L335
// Usage: https://github.com/microsoft/monaco-editor/blob/f6dc0eb8fce67e57f6036f4769d92c1666cdf546/src/language/json/jsonWorker.ts#L38
clientCapabilities: {
textDocument: {
completion: {
completionItem: {
commitCharactersSupport: true,
documentationFormat: ['markdown', 'plaintext'],
labelDetailsSupport: true
}
}
}
}
})
const withDocument =
<A extends unknown[], R>(fn: (document: TextDocument, ...args: A) => R) =>
(uri: string, ...args: A) => {
const models = ctx.getMirrorModels()
for (const model of models) {
if (String(model.uri) === uri) {
return fn(TextDocument.create(uri, 'yaml', model.version, model.getValue()), ...args)
}
}
}
ls.configure({ ...languageSettings, format: Boolean(format?.enable) })
return {
doValidation: withDocument((document) =>
ls.doValidation(document, Boolean(languageSettings.isKubernetes))
),
doComplete: withDocument((document, position) =>
ls.doComplete(document, position, Boolean(languageSettings.isKubernetes))
),
doDefinition: withDocument((document, position) =>
ls.doDefinition(document, { position, textDocument: document })
),
doDocumentOnTypeFormatting: withDocument((document, position, ch, options) =>
ls.doDocumentOnTypeFormatting(document, { ch, options, position, textDocument: document })
),
doHover: withDocument(ls.doHover),
doRename: withDocument((document, position, newName) =>
ls.doRename(document, { newName, position, textDocument: document })
),
format: withDocument((document) => ls.doFormat(document, format)),
resetSchema: ls.resetSchema,
findDocumentSymbols: withDocument(ls.findDocumentSymbols2),
findLinks: withDocument(ls.findLinks),
getCodeAction: withDocument((document, range, context) =>
ls.getCodeAction(document, { range, textDocument: document, context })
),
getCodeLens: withDocument(ls.getCodeLens),
getFoldingRanges: withDocument((document) =>
ls.getFoldingRanges(document, { lineFoldingOnly: true })
),
getSelectionRanges: withDocument(ls.getSelectionRanges),
prepareRename: withDocument((document, position) =>
ls.prepareRename(document, { position, textDocument: document })
)
}
}
)