Convert classes to factory functions

TypeScript is better at inferring types when using simple functions and
objects instead of classes. As a result many type annotations have now
been removed without impacting type safety.

Some other benefits are this can be minified better and private fields
are now truly private variables.
This commit is contained in:
Remco Haszing 2021-08-18 21:40:44 +02:00
parent bdfa1ef4e7
commit 8fa3ca4252
No known key found for this signature in database
GPG key ID: 40D9F5FE9155FD3C
7 changed files with 355 additions and 345 deletions

1
index.d.ts vendored
View file

@ -57,6 +57,7 @@ declare module 'monaco-editor/esm/vs/editor/editor.api' {
export interface LanguageServiceDefaults { export interface LanguageServiceDefaults {
readonly onDidChange: IEvent<LanguageServiceDefaults>; readonly onDidChange: IEvent<LanguageServiceDefaults>;
readonly languageId: string;
readonly diagnosticsOptions: DiagnosticsOptions; readonly diagnosticsOptions: DiagnosticsOptions;
setDiagnosticsOptions: (options: DiagnosticsOptions) => void; setDiagnosticsOptions: (options: DiagnosticsOptions) => void;
} }

View file

@ -11,7 +11,6 @@ import {
import * as ls from 'vscode-languageserver-types'; import * as ls from 'vscode-languageserver-types';
import { CustomFormatterOptions } from 'yaml-language-server/lib/esm/languageservice/yamlLanguageService'; import { CustomFormatterOptions } from 'yaml-language-server/lib/esm/languageservice/yamlLanguageService';
import { LanguageServiceDefaultsImpl } from './monaco.contribution';
import { YAMLWorker } from './yamlWorker'; import { YAMLWorker } from './yamlWorker';
export type WorkerAccessor = (...more: Uri[]) => PromiseLike<YAMLWorker>; export type WorkerAccessor = (...more: Uri[]) => PromiseLike<YAMLWorker>;
@ -48,85 +47,22 @@ function toDiagnostics(resource: Uri, diag: ls.Diagnostic): editor.IMarkerData {
}; };
} }
export class DiagnosticsAdapter { export function createDiagnosticsAdapter(
private _disposables: IDisposable[] = []; languageId: string,
private _listener: Record<string, IDisposable> = Object.create(null); getWorker: WorkerAccessor,
defaults: languages.yaml.LanguageServiceDefaults,
): IDisposable {
let disposables: IDisposable[] = [];
const listeners: Record<string, IDisposable> = Object.create(null);
constructor( const resetSchema = (resource: Uri): void => {
private _languageId: string, getWorker().then((worker) => {
private _worker: WorkerAccessor,
defaults: LanguageServiceDefaultsImpl,
) {
const onModelAdd = (model: editor.IModel): void => {
const modeId = model.getModeId();
if (modeId !== this._languageId) {
return;
}
let handle: number;
this._listener[String(toString)] = model.onDidChangeContent(() => {
clearTimeout(handle);
handle = setTimeout(() => this._doValidate(model.uri, modeId), 500);
});
this._doValidate(model.uri, modeId);
};
const onModelRemoved = (model: editor.IModel): void => {
editor.setModelMarkers(model, this._languageId, []);
const uriStr = String(model.uri);
const listener = this._listener[uriStr];
if (listener) {
listener.dispose();
delete this._listener[uriStr];
}
};
this._disposables.push(
editor.onDidCreateModel(onModelAdd),
editor.onWillDisposeModel((model) => {
onModelRemoved(model);
this._resetSchema(model.uri);
}),
editor.onDidChangeModelLanguage((event) => {
onModelRemoved(event.model);
onModelAdd(event.model);
this._resetSchema(event.model.uri);
}),
defaults.onDidChange(() => {
editor.getModels().forEach((model) => {
if (model.getModeId() === this._languageId) {
onModelRemoved(model);
onModelAdd(model);
}
});
}),
{
dispose: () => {
editor.getModels().forEach(onModelRemoved);
for (const disposable of Object.values(this._listener)) {
disposable.dispose();
}
},
},
);
editor.getModels().forEach(onModelAdd);
}
dispose(): void {
this._disposables.forEach((d) => d && d.dispose());
this._disposables = [];
}
private _resetSchema(resource: Uri): void {
this._worker().then((worker) => {
worker.resetSchema(String(resource)); worker.resetSchema(String(resource));
}); });
} };
private _doValidate(resource: Uri, languageId: string): void { const doValidate = (resource: Uri, languageId: string): void => {
this._worker(resource) getWorker(resource)
.then((worker) => .then((worker) =>
worker.doValidation(String(resource)).then((diagnostics) => { worker.doValidation(String(resource)).then((diagnostics) => {
const markers = diagnostics.map((d) => toDiagnostics(resource, d)); const markers = diagnostics.map((d) => toDiagnostics(resource, d));
@ -139,7 +75,70 @@ export class DiagnosticsAdapter {
.then(undefined, (err) => { .then(undefined, (err) => {
console.error(err); console.error(err);
}); });
} };
const onModelAdd = (model: editor.IModel): void => {
const modeId = model.getModeId();
if (modeId !== languageId) {
return;
}
let handle: number;
listeners[String(toString)] = model.onDidChangeContent(() => {
clearTimeout(handle);
handle = setTimeout(() => doValidate(model.uri, modeId), 500);
});
doValidate(model.uri, modeId);
};
const onModelRemoved = (model: editor.IModel): void => {
editor.setModelMarkers(model, languageId, []);
const uriStr = String(model.uri);
const listener = listeners[uriStr];
if (listener) {
listener.dispose();
delete listeners[uriStr];
}
};
disposables.push(
editor.onDidCreateModel(onModelAdd),
editor.onWillDisposeModel((model) => {
onModelRemoved(model);
resetSchema(model.uri);
}),
editor.onDidChangeModelLanguage((event) => {
onModelRemoved(event.model);
onModelAdd(event.model);
resetSchema(event.model.uri);
}),
defaults.onDidChange(() => {
editor.getModels().forEach((model) => {
if (model.getModeId() === languageId) {
onModelRemoved(model);
onModelAdd(model);
}
});
}),
{
dispose: () => {
editor.getModels().forEach(onModelRemoved);
for (const disposable of Object.values(listeners)) {
disposable.dispose();
}
},
},
);
editor.getModels().forEach(onModelAdd);
return {
dispose() {
disposables.forEach((d) => d && d.dispose());
disposables = [];
},
};
} }
// --- completion ------ // --- completion ------
@ -218,64 +217,66 @@ function toTextEdit(textEdit: ls.TextEdit): editor.ISingleEditOperation {
}; };
} }
export class CompletionAdapter implements languages.CompletionItemProvider { export function createCompletionItemProvider(
triggetCharacters = [' ', ':']; getWorker: WorkerAccessor,
): languages.CompletionItemProvider {
return {
triggerCharacters: [' ', ':'],
constructor(private _worker: WorkerAccessor) {} provideCompletionItems(
model: editor.IReadOnlyModel,
position: Position,
): PromiseLike<languages.CompletionList> {
const resource = model.uri;
provideCompletionItems( return getWorker(resource)
model: editor.IReadOnlyModel, .then((worker) => worker.doComplete(String(resource), fromPosition(position)))
position: Position, .then((info) => {
): PromiseLike<languages.CompletionList> { if (!info) {
const resource = model.uri; return;
}
return this._worker(resource) const wordInfo = model.getWordUntilPosition(position);
.then((worker) => worker.doComplete(String(resource), fromPosition(position))) const wordRange = new Range(
.then((info) => { position.lineNumber,
if (!info) { wordInfo.startColumn,
return; position.lineNumber,
} wordInfo.endColumn,
);
const wordInfo = model.getWordUntilPosition(position); const items = info.items.map((entry) => {
const wordRange = new Range( const item: languages.CompletionItem = {
position.lineNumber, label: entry.label,
wordInfo.startColumn, insertText: entry.insertText || entry.label,
position.lineNumber, sortText: entry.sortText,
wordInfo.endColumn, filterText: entry.filterText,
); documentation: entry.documentation,
detail: entry.detail,
kind: toCompletionItemKind(entry.kind),
range: wordRange,
};
if (entry.textEdit) {
item.range = toRange(
'range' in entry.textEdit ? entry.textEdit.range : entry.textEdit.replace,
);
item.insertText = entry.textEdit.newText;
}
if (entry.additionalTextEdits) {
item.additionalTextEdits = entry.additionalTextEdits.map(toTextEdit);
}
if (entry.insertTextFormat === ls.InsertTextFormat.Snippet) {
item.insertTextRules = languages.CompletionItemInsertTextRule.InsertAsSnippet;
}
return item;
});
const items: languages.CompletionItem[] = info.items.map((entry) => { return {
const item: languages.CompletionItem = { isIncomplete: info.isIncomplete,
label: entry.label, suggestions: items,
insertText: entry.insertText || entry.label,
sortText: entry.sortText,
filterText: entry.filterText,
documentation: entry.documentation,
detail: entry.detail,
kind: toCompletionItemKind(entry.kind),
range: wordRange,
}; };
if (entry.textEdit) {
item.range = toRange(
'range' in entry.textEdit ? entry.textEdit.range : entry.textEdit.replace,
);
item.insertText = entry.textEdit.newText;
}
if (entry.additionalTextEdits) {
item.additionalTextEdits = entry.additionalTextEdits.map(toTextEdit);
}
if (entry.insertTextFormat === ls.InsertTextFormat.Snippet) {
item.insertTextRules = languages.CompletionItemInsertTextRule.InsertAsSnippet;
}
return item;
}); });
},
return { };
isIncomplete: info.isIncomplete,
suggestions: items,
};
});
}
} }
function isMarkupContent(thing: unknown): thing is ls.MarkupContent { function isMarkupContent(thing: unknown): thing is ls.MarkupContent {
@ -316,24 +317,24 @@ function toMarkedStringArray(
// --- hover ------ // --- hover ------
export class HoverAdapter implements languages.HoverProvider { export function createHoverProvider(getWorker: WorkerAccessor): languages.HoverProvider {
constructor(private _worker: WorkerAccessor) {} return {
provideHover(model, position) {
const resource = model.uri;
provideHover(model: editor.IReadOnlyModel, position: Position): PromiseLike<languages.Hover> { return getWorker(resource)
const resource = model.uri; .then((worker) => worker.doHover(String(resource), fromPosition(position)))
.then((info) => {
return this._worker(resource) if (!info) {
.then((worker) => worker.doHover(String(resource), fromPosition(position))) return;
.then((info) => { }
if (!info) { return {
return; range: toRange(info.range),
} contents: toMarkedStringArray(info.contents),
return { } as languages.Hover;
range: toRange(info.range), });
contents: toMarkedStringArray(info.contents), },
} as languages.Hover; };
});
}
} }
// --- document symbols ------ // --- document symbols ------
@ -395,21 +396,23 @@ function toDocumentSymbol(item: ls.DocumentSymbol): languages.DocumentSymbol {
}; };
} }
export class DocumentSymbolAdapter implements languages.DocumentSymbolProvider { export function createDocumentSymbolProvider(
constructor(private _worker: WorkerAccessor) {} getWorker: WorkerAccessor,
): languages.DocumentSymbolProvider {
return {
provideDocumentSymbols(model) {
const resource = model.uri;
provideDocumentSymbols(model: editor.IReadOnlyModel): PromiseLike<languages.DocumentSymbol[]> { return getWorker(resource)
const resource = model.uri; .then((worker) => worker.findDocumentSymbols(String(resource)))
.then((items) => {
return this._worker(resource) if (!items) {
.then((worker) => worker.findDocumentSymbols(String(resource))) return;
.then((items) => { }
if (!items) { return items.map((item) => toDocumentSymbol(item));
return; });
} },
return items.map((item) => toDocumentSymbol(item)); };
});
}
} }
function fromFormattingOptions( function fromFormattingOptions(
@ -422,22 +425,21 @@ function fromFormattingOptions(
}; };
} }
export class DocumentFormattingEditProvider implements languages.DocumentFormattingEditProvider { export function createDocumentFormattingEditProvider(
constructor(private _worker: WorkerAccessor) {} getWorker: WorkerAccessor,
): languages.DocumentFormattingEditProvider {
return {
provideDocumentFormattingEdits(model, options) {
const resource = model.uri;
provideDocumentFormattingEdits( return getWorker(resource).then((worker) =>
model: editor.IReadOnlyModel, worker.format(String(resource), fromFormattingOptions(options)).then((edits) => {
options: languages.FormattingOptions, if (!edits || edits.length === 0) {
): PromiseLike<editor.ISingleEditOperation[]> { return;
const resource = model.uri; }
return edits.map(toTextEdit);
return this._worker(resource).then((worker) => }),
worker.format(String(resource), fromFormattingOptions(options)).then((edits) => { );
if (!edits || edits.length === 0) { },
return; };
}
return edits.map(toTextEdit);
}),
);
}
} }

View file

@ -1,35 +1,36 @@
import { Emitter, IEvent, languages } from 'monaco-editor/esm/vs/editor/editor.api'; import { Emitter, languages } from 'monaco-editor/esm/vs/editor/editor.api';
import { setupMode } from './yamlMode'; import { setupMode } from './yamlMode';
// --- YAML configuration and defaults --------- // --- YAML configuration and defaults ---------
export class LanguageServiceDefaultsImpl implements languages.yaml.LanguageServiceDefaults { export function createLanguageServiceDefaults(
private _onDidChange = new Emitter<languages.yaml.LanguageServiceDefaults>(); languageId: string,
private _diagnosticsOptions: languages.yaml.DiagnosticsOptions; initialDiagnosticsOptions: languages.yaml.DiagnosticsOptions,
private _languageId: string; ): languages.yaml.LanguageServiceDefaults {
const onDidChange = new Emitter<languages.yaml.LanguageServiceDefaults>();
let diagnosticsOptions = initialDiagnosticsOptions;
constructor(languageId: string, diagnosticsOptions: languages.yaml.DiagnosticsOptions) { const languageServiceDefaults: languages.yaml.LanguageServiceDefaults = {
this._languageId = languageId; get onDidChange() {
this.setDiagnosticsOptions(diagnosticsOptions); return onDidChange.event;
} },
get onDidChange(): IEvent<languages.yaml.LanguageServiceDefaults> { get languageId() {
return this._onDidChange.event; return languageId;
} },
get languageId(): string { get diagnosticsOptions() {
return this._languageId; return diagnosticsOptions;
} },
get diagnosticsOptions(): languages.yaml.DiagnosticsOptions { setDiagnosticsOptions(options) {
return this._diagnosticsOptions; diagnosticsOptions = options || {};
} onDidChange.fire(languageServiceDefaults);
},
};
setDiagnosticsOptions(options: languages.yaml.DiagnosticsOptions): void { return languageServiceDefaults;
this._diagnosticsOptions = options || Object.create(null);
this._onDidChange.fire(this);
}
} }
const diagnosticDefault: languages.yaml.DiagnosticsOptions = { const diagnosticDefault: languages.yaml.DiagnosticsOptions = {
@ -38,7 +39,7 @@ const diagnosticDefault: languages.yaml.DiagnosticsOptions = {
enableSchemaRequest: false, enableSchemaRequest: false,
}; };
const yamlDefaults = new LanguageServiceDefaultsImpl('yaml', diagnosticDefault); const yamlDefaults = createLanguageServiceDefaults('yaml', diagnosticDefault);
// Export API // Export API
function createAPI(): typeof languages.yaml { function createAPI(): typeof languages.yaml {

View file

@ -1,85 +1,82 @@
import { editor, IDisposable, Uri } from 'monaco-editor/esm/vs/editor/editor.api'; import { editor, IDisposable, languages, Uri } from 'monaco-editor/esm/vs/editor/editor.api';
import { LanguageServiceDefaultsImpl } from './monaco.contribution';
import { YAMLWorker } from './yamlWorker'; import { YAMLWorker } from './yamlWorker';
export interface WorkerManager extends IDisposable {
getLanguageServiceWorker: (...resources: Uri[]) => Promise<YAMLWorker>;
}
// 2min // 2min
const STOP_WHEN_IDLE_FOR = 2 * 60 * 1000; const STOP_WHEN_IDLE_FOR = 2 * 60 * 1000;
export class WorkerManager { export function createWorkerManager(
private _defaults: LanguageServiceDefaultsImpl; defaults: languages.yaml.LanguageServiceDefaults,
private _idleCheckInterval: number; ): WorkerManager {
private _lastUsedTime: number; let worker: editor.MonacoWebWorker<YAMLWorker>;
private _configChangeListener: IDisposable; let client: Promise<YAMLWorker>;
let lastUsedTime = 0;
private _worker: editor.MonacoWebWorker<YAMLWorker>; const stopWorker = (): void => {
private _client: Promise<YAMLWorker>; if (worker) {
worker.dispose();
constructor(defaults: LanguageServiceDefaultsImpl) { worker = null;
this._defaults = defaults;
this._worker = null;
this._idleCheckInterval = setInterval(() => this._checkIfIdle(), 30 * 1000);
this._lastUsedTime = 0;
this._configChangeListener = this._defaults.onDidChange(() => this._stopWorker());
}
dispose(): void {
clearInterval(this._idleCheckInterval);
this._configChangeListener.dispose();
this._stopWorker();
}
getLanguageServiceWorker(...resources: Uri[]): Promise<YAMLWorker> {
let _client: YAMLWorker;
return this._getClient()
.then((client) => {
_client = client;
})
.then(() => this._worker.withSyncedResources(resources))
.then(() => _client);
}
private _stopWorker(): void {
if (this._worker) {
this._worker.dispose();
this._worker = null;
} }
this._client = null; client = null;
} };
private _checkIfIdle(): void { const idleCheckInterval = setInterval(() => {
if (!this._worker) { if (!worker) {
return; return;
} }
const timePassedSinceLastUsed = Date.now() - this._lastUsedTime; const timePassedSinceLastUsed = Date.now() - lastUsedTime;
if (timePassedSinceLastUsed > STOP_WHEN_IDLE_FOR) { if (timePassedSinceLastUsed > STOP_WHEN_IDLE_FOR) {
this._stopWorker(); stopWorker();
} }
} }, 30 * 1000);
private _getClient(): Promise<YAMLWorker> { const configChangeListener = defaults.onDidChange(() => stopWorker());
this._lastUsedTime = Date.now();
if (!this._client) { const getClient = (): Promise<YAMLWorker> => {
this._worker = editor.createWebWorker<YAMLWorker>({ lastUsedTime = Date.now();
if (!client) {
worker = editor.createWebWorker<YAMLWorker>({
// Module that exports the create() method and returns a `YAMLWorker` instance // Module that exports the create() method and returns a `YAMLWorker` instance
moduleId: 'vs/language/yaml/yamlWorker', moduleId: 'vs/language/yaml/yamlWorker',
label: this._defaults.languageId, label: defaults.languageId,
// Passed in to the create() method // Passed in to the create() method
createData: { createData: {
languageSettings: this._defaults.diagnosticsOptions, languageSettings: defaults.diagnosticsOptions,
languageId: this._defaults.languageId, languageId: defaults.languageId,
enableSchemaRequest: this._defaults.diagnosticsOptions.enableSchemaRequest, enableSchemaRequest: defaults.diagnosticsOptions.enableSchemaRequest,
prefix: this._defaults.diagnosticsOptions.prefix, prefix: defaults.diagnosticsOptions.prefix,
isKubernetes: this._defaults.diagnosticsOptions.isKubernetes, isKubernetes: defaults.diagnosticsOptions.isKubernetes,
}, },
}); });
this._client = this._worker.getProxy(); client = worker.getProxy();
} }
return this._client; return client;
} };
return {
dispose() {
clearInterval(idleCheckInterval);
configChangeListener.dispose();
stopWorker();
},
getLanguageServiceWorker(...resources) {
let _client: YAMLWorker;
return getClient()
.then((client) => {
_client = client;
})
.then(() => worker.withSyncedResources(resources))
.then(() => _client);
},
};
} }

View file

@ -1,8 +1,7 @@
import * as worker from 'monaco-editor/esm/vs/editor/editor.worker'; import { initialize } from 'monaco-editor/esm/vs/editor/editor.worker';
import { YAMLWorker } from './yamlWorker'; import { createYAMLWorker } from './yamlWorker';
self.onmessage = () => { self.onmessage = () => {
// Ignore the first message initialize((ctx, createData) => Object.create(createYAMLWorker(ctx, createData)));
worker.initialize((ctx, createData) => new YAMLWorker(ctx, createData));
}; };

View file

@ -1,8 +1,14 @@
import { IDisposable, languages, Uri } from 'monaco-editor/esm/vs/editor/editor.api'; import { IDisposable, languages, Uri } from 'monaco-editor/esm/vs/editor/editor.api';
import * as languageFeatures from './languageFeatures'; import {
import { LanguageServiceDefaultsImpl } from './monaco.contribution'; createCompletionItemProvider,
import { WorkerManager } from './workerManager'; createDiagnosticsAdapter,
createDocumentFormattingEditProvider,
createDocumentSymbolProvider,
createHoverProvider,
WorkerAccessor,
} from './languageFeatures';
import { createWorkerManager } from './workerManager';
import { YAMLWorker } from './yamlWorker'; import { YAMLWorker } from './yamlWorker';
const richEditConfiguration: languages.LanguageConfiguration = { const richEditConfiguration: languages.LanguageConfiguration = {
@ -37,32 +43,26 @@ const richEditConfiguration: languages.LanguageConfiguration = {
], ],
}; };
export function setupMode(defaults: LanguageServiceDefaultsImpl): void { export function setupMode(defaults: languages.yaml.LanguageServiceDefaults): void {
const disposables: IDisposable[] = []; const disposables: IDisposable[] = [];
const client = new WorkerManager(defaults); const client = createWorkerManager(defaults);
disposables.push(client); disposables.push(client);
const worker: languageFeatures.WorkerAccessor = (...uris: Uri[]): Promise<YAMLWorker> => const worker: WorkerAccessor = (...uris: Uri[]): Promise<YAMLWorker> =>
client.getLanguageServiceWorker(...uris); client.getLanguageServiceWorker(...uris);
const { languageId } = defaults; const { languageId } = defaults;
disposables.push( disposables.push(
languages.registerCompletionItemProvider( languages.registerCompletionItemProvider(languageId, createCompletionItemProvider(worker)),
languageId, languages.registerHoverProvider(languageId, createHoverProvider(worker)),
new languageFeatures.CompletionAdapter(worker), languages.registerDocumentSymbolProvider(languageId, createDocumentSymbolProvider(worker)),
),
languages.registerHoverProvider(languageId, new languageFeatures.HoverAdapter(worker)),
languages.registerDocumentSymbolProvider(
languageId,
new languageFeatures.DocumentSymbolAdapter(worker),
),
languages.registerDocumentFormattingEditProvider( languages.registerDocumentFormattingEditProvider(
languageId, languageId,
new languageFeatures.DocumentFormattingEditProvider(worker), createDocumentFormattingEditProvider(worker),
), ),
new languageFeatures.DiagnosticsAdapter(languageId, worker, defaults), createDiagnosticsAdapter(languageId, worker, defaults),
languages.setLanguageConfiguration(languageId, richEditConfiguration), languages.setLanguageConfiguration(languageId, richEditConfiguration),
); );
} }

View file

@ -1,6 +1,10 @@
import { worker } from 'monaco-editor/esm/vs/editor/editor.api'; import { worker } from 'monaco-editor/esm/vs/editor/editor.api';
import * as ls from 'vscode-languageserver-types'; import * as ls from 'vscode-languageserver-types';
import * as yamlService from 'yaml-language-server/lib/esm/languageservice/yamlLanguageService'; import {
CustomFormatterOptions,
getLanguageService,
LanguageSettings,
} from 'yaml-language-server/lib/esm/languageservice/yamlLanguageService';
let defaultSchemaRequestService: (url: string) => PromiseLike<string>; let defaultSchemaRequestService: (url: string) => PromiseLike<string>;
@ -8,90 +12,96 @@ if (typeof fetch !== 'undefined') {
defaultSchemaRequestService = (url) => fetch(url).then((response) => response.text()); defaultSchemaRequestService = (url) => fetch(url).then((response) => response.text());
} }
export class YAMLWorker { export interface YAMLWorker {
private _ctx: worker.IWorkerContext; doValidation: (uri: string) => PromiseLike<ls.Diagnostic[]>;
private _languageService: yamlService.LanguageService;
private _languageSettings: yamlService.LanguageSettings;
private _languageId: string;
private _isKubernetes: boolean;
constructor(ctx: worker.IWorkerContext, createData: ICreateData) { doComplete: (uri: string, position: ls.Position) => PromiseLike<ls.CompletionList>;
const prefix = createData.prefix || '';
const service = (url: string): PromiseLike<string> =>
defaultSchemaRequestService(`${prefix}${url}`);
this._ctx = ctx;
this._languageSettings = createData.languageSettings;
this._languageId = createData.languageId;
this._languageService = yamlService.getLanguageService(
createData.enableSchemaRequest && service,
null,
[],
);
this._isKubernetes = createData.isKubernetes || false;
this._languageService.configure({
...this._languageSettings,
hover: true,
isKubernetes: this._isKubernetes,
});
}
doValidation(uri: string): PromiseLike<ls.Diagnostic[]> { doResolve: (item: ls.CompletionItem) => PromiseLike<ls.CompletionItem>;
const document = this._getTextDocument(uri);
if (document) {
return this._languageService.doValidation(document, this._isKubernetes);
}
return Promise.resolve([]);
}
doComplete(uri: string, position: ls.Position): PromiseLike<ls.CompletionList> { doHover: (uri: string, position: ls.Position) => PromiseLike<ls.Hover>;
const document = this._getTextDocument(uri);
return this._languageService.doComplete(document, position, this._isKubernetes);
}
doResolve(item: ls.CompletionItem): PromiseLike<ls.CompletionItem> { format: (uri: string, options: CustomFormatterOptions) => PromiseLike<ls.TextEdit[]>;
return this._languageService.doResolve(item);
}
doHover(uri: string, position: ls.Position): PromiseLike<ls.Hover> { resetSchema: (uri: string) => PromiseLike<boolean>;
const document = this._getTextDocument(uri);
return this._languageService.doHover(document, position);
}
format(uri: string, options: yamlService.CustomFormatterOptions): PromiseLike<ls.TextEdit[]> { findDocumentSymbols: (uri: string) => PromiseLike<ls.DocumentSymbol[]>;
const document = this._getTextDocument(uri); }
const textEdits = this._languageService.doFormat(document, options);
return Promise.resolve(textEdits);
}
resetSchema(uri: string): PromiseLike<boolean> { export function createYAMLWorker(
return Promise.resolve(this._languageService.resetSchema(uri)); ctx: worker.IWorkerContext,
} {
enableSchemaRequest,
isKubernetes = false,
languageId,
languageSettings,
prefix = '',
}: ICreateData,
): YAMLWorker {
const service = (url: string): PromiseLike<string> =>
defaultSchemaRequestService(`${prefix}${url}`);
const languageService = getLanguageService(enableSchemaRequest && service, null, []);
languageService.configure({
...languageSettings,
hover: true,
isKubernetes,
});
findDocumentSymbols(uri: string): PromiseLike<ls.DocumentSymbol[]> { const getTextDocument = (uri: string): ls.TextDocument => {
const document = this._getTextDocument(uri); const models = ctx.getMirrorModels();
const symbols = this._languageService.findDocumentSymbols2(document);
return Promise.resolve(symbols);
}
private _getTextDocument(uri: string): ls.TextDocument {
const models = this._ctx.getMirrorModels();
for (const model of models) { for (const model of models) {
if (String(model.uri) === uri) { if (String(model.uri) === uri) {
return ls.TextDocument.create(uri, this._languageId, model.version, model.getValue()); return ls.TextDocument.create(uri, languageId, model.version, model.getValue());
} }
} }
return null; return null;
} };
return {
doValidation(uri) {
const document = getTextDocument(uri);
if (document) {
return languageService.doValidation(document, isKubernetes);
}
return Promise.resolve([]);
},
doComplete(uri, position) {
const document = getTextDocument(uri);
return languageService.doComplete(document, position, isKubernetes);
},
doResolve(item) {
return languageService.doResolve(item);
},
doHover(uri, position) {
const document = getTextDocument(uri);
return languageService.doHover(document, position);
},
format(uri, options) {
const document = getTextDocument(uri);
const textEdits = languageService.doFormat(document, options);
return Promise.resolve(textEdits);
},
resetSchema(uri) {
return Promise.resolve(languageService.resetSchema(uri));
},
findDocumentSymbols(uri) {
const document = getTextDocument(uri);
const symbols = languageService.findDocumentSymbols2(document);
return Promise.resolve(symbols);
},
};
} }
export interface ICreateData { export interface ICreateData {
languageId: string; languageId: string;
languageSettings: yamlService.LanguageSettings; languageSettings: LanguageSettings;
enableSchemaRequest: boolean; enableSchemaRequest: boolean;
prefix?: string; prefix?: string;
isKubernetes?: boolean; isKubernetes?: boolean;
} }
export function create(ctx: worker.IWorkerContext, createData: ICreateData): YAMLWorker {
return new YAMLWorker(ctx, createData);
}