Merge pull request #5 from kpdecker/feat/2.0

build: migrate latest json language service implementation
This commit is contained in:
Peng Xiao 2018-11-30 15:05:52 +08:00 committed by GitHub
commit 37dae21bbd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 3781 additions and 2726 deletions

14
.editorconfig Normal file
View file

@ -0,0 +1,14 @@
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
end_of_line = lf
[*.md]
max_line_length = off
trim_trailing_whitespace = false

View file

@ -5,5 +5,7 @@
"**/node_modules": true,
"**/release": true,
"**/out": true
}
},
"javascript.preferences.quoteStyle": "single",
"typescript.preferences.quoteStyle": "single"
}

View file

@ -1,6 +1,6 @@
{
"name": "monaco-yaml",
"version": "1.3.1",
"version": "2.0.0",
"description": "YAML plugin for the Monaco Editor",
"scripts": {
"compile": "rimraf ./out && yarn compile:umd && yarn compile:esm",
@ -35,7 +35,7 @@
"rimraf": "^2.6.2",
"typescript": "^3.1.6",
"uglify-es": "^3.3.9",
"vscode-json-languageservice": "^3.1.6",
"vscode-languageserver-types": "3.12.0"
"vscode-languageserver-types": "3.12.0",
"yaml-language-server": "^0.1.0"
}
}

View file

@ -46,10 +46,7 @@ function bundleOne(moduleId, exclude) {
name: 'jsonc-parser',
location: path.join(REPO_ROOT, 'node_modules/jsonc-parser/lib/umd'),
main: 'main'
}, {
name: 'vscode-json-languageservice/lib',
location: path.join(REPO_ROOT, 'node_modules/vscode-json-languageservice/lib/umd')
},
},
{
name: 'vscode-languageserver-types',

View file

@ -22,7 +22,6 @@ helpers.packageESM({
"jsonc-parser/lib/esm": "jsonc-parser",
"vscode-languageserver-types/lib/esm": "vscode-languageserver-types",
"vscode-uri/lib/esm": "vscode-uri",
"vscode-json-languageservice/lib/esm": "vscode-json-languageservice",
// "js-yaml/dist": "js-yaml"
}
});

View file

@ -1,432 +1,479 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { LanguageServiceDefaultsImpl } from './monaco.contribution';
import { YAMLWorker } from './yamlWorker';
import * as ls from 'vscode-languageserver-types';
import Uri = monaco.Uri;
import Position = monaco.Position;
import Range = monaco.Range;
import IRange = monaco.IRange;
import Thenable = monaco.Thenable;
import CancellationToken = monaco.CancellationToken;
import IDisposable = monaco.IDisposable;
export interface WorkerAccessor {
(...more: Uri[]): Thenable<YAMLWorker>
}
// --- diagnostics --- ---
export class DiagnosticsAdapter {
private _disposables: IDisposable[] = [];
private _listener: { [uri: string]: IDisposable } = Object.create(null);
constructor(private _languageId: string, private _worker: WorkerAccessor, defaults: LanguageServiceDefaultsImpl) {
const onModelAdd = (model: monaco.editor.IModel): void => {
let modeId = model.getModeId();
if (modeId !== this._languageId) {
return;
}
let handle: NodeJS.Timer;
this._listener[model.uri.toString()] = model.onDidChangeContent(() => {
clearTimeout(handle);
handle = setTimeout(() => this._doValidate(model.uri, modeId), 500);
});
this._doValidate(model.uri, modeId);
};
const onModelRemoved = (model: monaco.editor.IModel): void => {
monaco.editor.setModelMarkers(model, this._languageId, []);
let uriStr = model.uri.toString();
let listener = this._listener[uriStr];
if (listener) {
listener.dispose();
delete this._listener[uriStr];
}
};
this._disposables.push(monaco.editor.onDidCreateModel(onModelAdd));
this._disposables.push(monaco.editor.onWillDisposeModel(model => {
onModelRemoved(model);
this._resetSchema(model.uri);
}));
this._disposables.push(monaco.editor.onDidChangeModelLanguage(event => {
onModelRemoved(event.model);
onModelAdd(event.model);
this._resetSchema(event.model.uri);
}));
this._disposables.push(defaults.onDidChange(_ => {
monaco.editor.getModels().forEach(model => {
if (model.getModeId() === this._languageId) {
onModelRemoved(model);
onModelAdd(model);
}
});
}));
this._disposables.push({
dispose: () => {
monaco.editor.getModels().forEach(onModelRemoved);
for (let key in this._listener) {
this._listener[key].dispose();
}
}
});
monaco.editor.getModels().forEach(onModelAdd);
}
public dispose(): void {
this._disposables.forEach(d => d && d.dispose());
this._disposables = [];
}
private _resetSchema(resource: Uri): void {
this._worker().then(worker => {
worker.resetSchema(resource.toString());
});
}
private _doValidate(resource: Uri, languageId: string): void {
this._worker(resource).then(worker => {
return worker.doValidation(resource.toString()).then(diagnostics => {
const markers = diagnostics.map(d => toDiagnostics(resource, d));
let model = monaco.editor.getModel(resource);
if (model.getModeId() === languageId) {
monaco.editor.setModelMarkers(model, languageId, markers);
}
});
}).then(undefined, err => {
console.error(err);
});
}
}
function toSeverity(lsSeverity: number): monaco.MarkerSeverity {
switch (lsSeverity) {
case ls.DiagnosticSeverity.Error: return monaco.MarkerSeverity.Error;
case ls.DiagnosticSeverity.Warning: return monaco.MarkerSeverity.Warning;
case ls.DiagnosticSeverity.Information: return monaco.MarkerSeverity.Info;
case ls.DiagnosticSeverity.Hint: return monaco.MarkerSeverity.Hint;
default:
return monaco.MarkerSeverity.Info;
}
}
function toDiagnostics(resource: Uri, diag: ls.Diagnostic): monaco.editor.IMarkerData {
let code = typeof diag.code === 'number' ? String(diag.code) : <string>diag.code;
return {
severity: toSeverity(diag.severity),
startLineNumber: diag.range.start.line + 1,
startColumn: diag.range.start.character + 1,
endLineNumber: diag.range.end.line + 1,
endColumn: diag.range.end.character + 1,
message: diag.message,
code: code,
source: diag.source
};
}
// --- completion ------
function fromPosition(position: Position): ls.Position {
if (!position) {
return void 0;
}
return { character: position.column - 1, line: position.lineNumber - 1 };
}
function fromRange(range: IRange): ls.Range {
if (!range) {
return void 0;
}
return { start: { line: range.startLineNumber - 1, character: range.startColumn - 1 }, end: { line: range.endLineNumber - 1, character: range.endColumn - 1 } };
}
function toRange(range: ls.Range): Range {
if (!range) {
return void 0;
}
return new Range(range.start.line + 1, range.start.character + 1, range.end.line + 1, range.end.character + 1);
}
function toCompletionItemKind(kind: number): monaco.languages.CompletionItemKind {
let mItemKind = monaco.languages.CompletionItemKind;
switch (kind) {
case ls.CompletionItemKind.Text: return mItemKind.Text;
case ls.CompletionItemKind.Method: return mItemKind.Method;
case ls.CompletionItemKind.Function: return mItemKind.Function;
case ls.CompletionItemKind.Constructor: return mItemKind.Constructor;
case ls.CompletionItemKind.Field: return mItemKind.Field;
case ls.CompletionItemKind.Variable: return mItemKind.Variable;
case ls.CompletionItemKind.Class: return mItemKind.Class;
case ls.CompletionItemKind.Interface: return mItemKind.Interface;
case ls.CompletionItemKind.Module: return mItemKind.Module;
case ls.CompletionItemKind.Property: return mItemKind.Property;
case ls.CompletionItemKind.Unit: return mItemKind.Unit;
case ls.CompletionItemKind.Value: return mItemKind.Value;
case ls.CompletionItemKind.Enum: return mItemKind.Enum;
case ls.CompletionItemKind.Keyword: return mItemKind.Keyword;
case ls.CompletionItemKind.Snippet: return mItemKind.Snippet;
case ls.CompletionItemKind.Color: return mItemKind.Color;
case ls.CompletionItemKind.File: return mItemKind.File;
case ls.CompletionItemKind.Reference: return mItemKind.Reference;
}
return mItemKind.Property;
}
function fromCompletionItemKind(kind: monaco.languages.CompletionItemKind): ls.CompletionItemKind {
let mItemKind = monaco.languages.CompletionItemKind;
switch (kind) {
case mItemKind.Text: return ls.CompletionItemKind.Text;
case mItemKind.Method: return ls.CompletionItemKind.Method;
case mItemKind.Function: return ls.CompletionItemKind.Function;
case mItemKind.Constructor: return ls.CompletionItemKind.Constructor;
case mItemKind.Field: return ls.CompletionItemKind.Field;
case mItemKind.Variable: return ls.CompletionItemKind.Variable;
case mItemKind.Class: return ls.CompletionItemKind.Class;
case mItemKind.Interface: return ls.CompletionItemKind.Interface;
case mItemKind.Module: return ls.CompletionItemKind.Module;
case mItemKind.Property: return ls.CompletionItemKind.Property;
case mItemKind.Unit: return ls.CompletionItemKind.Unit;
case mItemKind.Value: return ls.CompletionItemKind.Value;
case mItemKind.Enum: return ls.CompletionItemKind.Enum;
case mItemKind.Keyword: return ls.CompletionItemKind.Keyword;
case mItemKind.Snippet: return ls.CompletionItemKind.Snippet;
case mItemKind.Color: return ls.CompletionItemKind.Color;
case mItemKind.File: return ls.CompletionItemKind.File;
case mItemKind.Reference: return ls.CompletionItemKind.Reference;
}
return ls.CompletionItemKind.Property;
}
function toTextEdit(textEdit: ls.TextEdit): monaco.editor.ISingleEditOperation {
if (!textEdit) {
return void 0;
}
return {
range: toRange(textEdit.range),
text: textEdit.newText
}
}
export class CompletionAdapter implements monaco.languages.CompletionItemProvider {
constructor(private _worker: WorkerAccessor) {
}
public get triggerCharacters(): string[] {
return [' ', ':'];
}
provideCompletionItems(model: monaco.editor.IReadOnlyModel, position: Position, context: monaco.languages.CompletionContext, token: CancellationToken): Thenable<monaco.languages.CompletionList> {
const wordInfo = model.getWordUntilPosition(position);
const resource = model.uri;
return this._worker(resource).then(worker => {
return worker.doComplete(resource.toString(), fromPosition(position));
}).then(info => {
if (!info) {
return;
}
let items: monaco.languages.CompletionItem[] = info.items.map(entry => {
let item: monaco.languages.CompletionItem = {
label: entry.label,
insertText: entry.insertText || entry.label,
sortText: entry.sortText,
filterText: entry.filterText,
documentation: entry.documentation,
detail: entry.detail,
kind: toCompletionItemKind(entry.kind),
};
if (entry.textEdit) {
item.range = toRange(entry.textEdit.range);
item.insertText = entry.textEdit.newText;
}
if (entry.additionalTextEdits) {
item.additionalTextEdits = entry.additionalTextEdits.map(toTextEdit)
}
if (entry.insertTextFormat === ls.InsertTextFormat.Snippet) {
item.insertTextRules = monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet;
}
return item;
});
return {
isIncomplete: info.isIncomplete,
suggestions: items
};
});
}
}
function isMarkupContent(thing: any): thing is ls.MarkupContent {
return thing && typeof thing === 'object' && typeof (<ls.MarkupContent>thing).kind === 'string';
}
function toMarkdownString(entry: ls.MarkupContent | ls.MarkedString): monaco.IMarkdownString {
if (typeof entry === 'string') {
return {
value: entry
};
}
if (isMarkupContent(entry)) {
if (entry.kind === 'plaintext') {
return {
value: entry.value.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&')
};
}
return {
value: entry.value
};
}
return { value: '```' + entry.language + '\n' + entry.value + '\n```\n' };
}
function toMarkedStringArray(contents: ls.MarkupContent | ls.MarkedString | ls.MarkedString[]): monaco.IMarkdownString[] {
if (!contents) {
return void 0;
}
if (Array.isArray(contents)) {
return contents.map(toMarkdownString);
}
return [toMarkdownString(contents)];
}
// --- hover ------
export class HoverAdapter implements monaco.languages.HoverProvider {
constructor(private _worker: WorkerAccessor) {}
provideHover(model: monaco.editor.IReadOnlyModel, position: Position, token: CancellationToken): Thenable<monaco.languages.Hover> {
let resource = model.uri;
return this._worker(resource).then(worker => {
return worker.doHover(resource.toString(), fromPosition(position));
}).then(info => {
if (!info) {
return;
}
return <monaco.languages.Hover>{
range: toRange(info.range),
contents: toMarkedStringArray(info.contents)
};
});
}
}
// --- document symbols ------
function toSymbolKind(kind: ls.SymbolKind): monaco.languages.SymbolKind {
let mKind = monaco.languages.SymbolKind;
switch (kind) {
case ls.SymbolKind.File: return mKind.Array;
case ls.SymbolKind.Module: return mKind.Module;
case ls.SymbolKind.Namespace: return mKind.Namespace;
case ls.SymbolKind.Package: return mKind.Package;
case ls.SymbolKind.Class: return mKind.Class;
case ls.SymbolKind.Method: return mKind.Method;
case ls.SymbolKind.Property: return mKind.Property;
case ls.SymbolKind.Field: return mKind.Field;
case ls.SymbolKind.Constructor: return mKind.Constructor;
case ls.SymbolKind.Enum: return mKind.Enum;
case ls.SymbolKind.Interface: return mKind.Interface;
case ls.SymbolKind.Function: return mKind.Function;
case ls.SymbolKind.Variable: return mKind.Variable;
case ls.SymbolKind.Constant: return mKind.Constant;
case ls.SymbolKind.String: return mKind.String;
case ls.SymbolKind.Number: return mKind.Number;
case ls.SymbolKind.Boolean: return mKind.Boolean;
case ls.SymbolKind.Array: return mKind.Array;
}
return mKind.Function;
}
export class DocumentSymbolAdapter implements monaco.languages.DocumentSymbolProvider {
constructor(private _worker: WorkerAccessor) {
}
public provideDocumentSymbols(model: monaco.editor.IReadOnlyModel, token: CancellationToken): Thenable<monaco.languages.DocumentSymbol[]> {
const resource = model.uri;
return this._worker(resource).then(worker => worker.findDocumentSymbols(resource.toString())).then(items => {
if (!items) {
return;
}
return items.map(item => ({
name: item.name,
detail: '',
containerName: item.containerName,
kind: toSymbolKind(item.kind),
range: toRange(item.location.range),
selectionRange: toRange(item.location.range)
}));
});
}
}
function fromFormattingOptions(options: monaco.languages.FormattingOptions): ls.FormattingOptions {
return {
tabSize: options.tabSize,
insertSpaces: options.insertSpaces
};
}
export class DocumentFormattingEditProvider implements monaco.languages.DocumentFormattingEditProvider {
constructor(private _worker: WorkerAccessor) {
}
public provideDocumentFormattingEdits(model: monaco.editor.IReadOnlyModel, options: monaco.languages.FormattingOptions, token: CancellationToken): Thenable<monaco.editor.ISingleEditOperation[]> {
const resource = model.uri;
return this._worker(resource).then(worker => {
return worker.format(resource.toString(), null, fromFormattingOptions(options)).then(edits => {
if (!edits || edits.length === 0) {
return;
}
return edits.map(toTextEdit);
});
});
}
}
export class DocumentRangeFormattingEditProvider implements monaco.languages.DocumentRangeFormattingEditProvider {
constructor(private _worker: WorkerAccessor) {
}
public provideDocumentRangeFormattingEdits(model: monaco.editor.IReadOnlyModel, range: Range, options: monaco.languages.FormattingOptions, token: CancellationToken): Thenable<monaco.editor.ISingleEditOperation[]> {
const resource = model.uri;
return this._worker(resource).then(worker => {
return worker.format(resource.toString(), fromRange(range), fromFormattingOptions(options)).then(edits => {
if (!edits || edits.length === 0) {
return;
}
return edits.map(toTextEdit);
});
});
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { LanguageServiceDefaultsImpl } from './monaco.contribution';
import { YAMLWorker } from './yamlWorker';
import * as ls from 'vscode-languageserver-types';
import Uri = monaco.Uri;
import Position = monaco.Position;
import Range = monaco.Range;
import IRange = monaco.IRange;
import Thenable = monaco.Thenable;
import CancellationToken = monaco.CancellationToken;
import IDisposable = monaco.IDisposable;
export interface WorkerAccessor {
(...more: Uri[]): Thenable<YAMLWorker>
}
// --- diagnostics --- ---
export class DiagnosticsAdapter {
private _disposables: IDisposable[] = [];
private _listener: { [uri: string]: IDisposable } = Object.create(null);
constructor(private _languageId: string, private _worker: WorkerAccessor, defaults: LanguageServiceDefaultsImpl) {
const onModelAdd = (model: monaco.editor.IModel): void => {
let modeId = model.getModeId();
if (modeId !== this._languageId) {
return;
}
let handle: NodeJS.Timer;
this._listener[model.uri.toString()] = model.onDidChangeContent(() => {
clearTimeout(handle);
handle = setTimeout(() => this._doValidate(model.uri, modeId), 500);
});
this._doValidate(model.uri, modeId);
};
const onModelRemoved = (model: monaco.editor.IModel): void => {
monaco.editor.setModelMarkers(model, this._languageId, []);
let uriStr = model.uri.toString();
let listener = this._listener[uriStr];
if (listener) {
listener.dispose();
delete this._listener[uriStr];
}
};
this._disposables.push(monaco.editor.onDidCreateModel(onModelAdd));
this._disposables.push(monaco.editor.onWillDisposeModel(model => {
onModelRemoved(model);
this._resetSchema(model.uri);
}));
this._disposables.push(monaco.editor.onDidChangeModelLanguage(event => {
onModelRemoved(event.model);
onModelAdd(event.model);
this._resetSchema(event.model.uri);
}));
this._disposables.push(defaults.onDidChange(_ => {
monaco.editor.getModels().forEach(model => {
if (model.getModeId() === this._languageId) {
onModelRemoved(model);
onModelAdd(model);
}
});
}));
this._disposables.push({
dispose: () => {
monaco.editor.getModels().forEach(onModelRemoved);
for (let key in this._listener) {
this._listener[key].dispose();
}
}
});
monaco.editor.getModels().forEach(onModelAdd);
}
public dispose(): void {
this._disposables.forEach(d => d && d.dispose());
this._disposables = [];
}
private _resetSchema(resource: Uri): void {
this._worker().then(worker => {
worker.resetSchema(resource.toString());
});
}
private _doValidate(resource: Uri, languageId: string): void {
this._worker(resource).then(worker => {
return worker.doValidation(resource.toString()).then(diagnostics => {
const markers = diagnostics.map(d => toDiagnostics(resource, d));
let model = monaco.editor.getModel(resource);
if (model.getModeId() === languageId) {
monaco.editor.setModelMarkers(model, languageId, markers);
}
});
}).then(undefined, err => {
console.error(err);
});
}
}
function toSeverity(lsSeverity: number): monaco.MarkerSeverity {
switch (lsSeverity) {
case ls.DiagnosticSeverity.Error: return monaco.MarkerSeverity.Error;
case ls.DiagnosticSeverity.Warning: return monaco.MarkerSeverity.Warning;
case ls.DiagnosticSeverity.Information: return monaco.MarkerSeverity.Info;
case ls.DiagnosticSeverity.Hint: return monaco.MarkerSeverity.Hint;
default:
return monaco.MarkerSeverity.Info;
}
}
function toDiagnostics(resource: Uri, diag: ls.Diagnostic): monaco.editor.IMarkerData {
let code = typeof diag.code === 'number' ? String(diag.code) : <string>diag.code;
return {
severity: toSeverity(diag.severity),
startLineNumber: diag.range.start.line + 1,
startColumn: diag.range.start.character + 1,
endLineNumber: diag.range.end.line + 1,
endColumn: diag.range.end.character + 1,
message: diag.message,
code: code,
source: diag.source
};
}
// --- completion ------
function fromPosition(position: Position): ls.Position {
if (!position) {
return void 0;
}
return { character: position.column - 1, line: position.lineNumber - 1 };
}
function fromRange(range: IRange): ls.Range {
if (!range) {
return void 0;
}
return { start: { line: range.startLineNumber - 1, character: range.startColumn - 1 }, end: { line: range.endLineNumber - 1, character: range.endColumn - 1 } };
}
function toRange(range: ls.Range): Range {
if (!range) {
return void 0;
}
return new Range(range.start.line + 1, range.start.character + 1, range.end.line + 1, range.end.character + 1);
}
function toCompletionItemKind(kind: number): monaco.languages.CompletionItemKind {
let mItemKind = monaco.languages.CompletionItemKind;
switch (kind) {
case ls.CompletionItemKind.Text: return mItemKind.Text;
case ls.CompletionItemKind.Method: return mItemKind.Method;
case ls.CompletionItemKind.Function: return mItemKind.Function;
case ls.CompletionItemKind.Constructor: return mItemKind.Constructor;
case ls.CompletionItemKind.Field: return mItemKind.Field;
case ls.CompletionItemKind.Variable: return mItemKind.Variable;
case ls.CompletionItemKind.Class: return mItemKind.Class;
case ls.CompletionItemKind.Interface: return mItemKind.Interface;
case ls.CompletionItemKind.Module: return mItemKind.Module;
case ls.CompletionItemKind.Property: return mItemKind.Property;
case ls.CompletionItemKind.Unit: return mItemKind.Unit;
case ls.CompletionItemKind.Value: return mItemKind.Value;
case ls.CompletionItemKind.Enum: return mItemKind.Enum;
case ls.CompletionItemKind.Keyword: return mItemKind.Keyword;
case ls.CompletionItemKind.Snippet: return mItemKind.Snippet;
case ls.CompletionItemKind.Color: return mItemKind.Color;
case ls.CompletionItemKind.File: return mItemKind.File;
case ls.CompletionItemKind.Reference: return mItemKind.Reference;
}
return mItemKind.Property;
}
function fromCompletionItemKind(kind: monaco.languages.CompletionItemKind): ls.CompletionItemKind {
let mItemKind = monaco.languages.CompletionItemKind;
switch (kind) {
case mItemKind.Text: return ls.CompletionItemKind.Text;
case mItemKind.Method: return ls.CompletionItemKind.Method;
case mItemKind.Function: return ls.CompletionItemKind.Function;
case mItemKind.Constructor: return ls.CompletionItemKind.Constructor;
case mItemKind.Field: return ls.CompletionItemKind.Field;
case mItemKind.Variable: return ls.CompletionItemKind.Variable;
case mItemKind.Class: return ls.CompletionItemKind.Class;
case mItemKind.Interface: return ls.CompletionItemKind.Interface;
case mItemKind.Module: return ls.CompletionItemKind.Module;
case mItemKind.Property: return ls.CompletionItemKind.Property;
case mItemKind.Unit: return ls.CompletionItemKind.Unit;
case mItemKind.Value: return ls.CompletionItemKind.Value;
case mItemKind.Enum: return ls.CompletionItemKind.Enum;
case mItemKind.Keyword: return ls.CompletionItemKind.Keyword;
case mItemKind.Snippet: return ls.CompletionItemKind.Snippet;
case mItemKind.Color: return ls.CompletionItemKind.Color;
case mItemKind.File: return ls.CompletionItemKind.File;
case mItemKind.Reference: return ls.CompletionItemKind.Reference;
}
return ls.CompletionItemKind.Property;
}
function toTextEdit(textEdit: ls.TextEdit): monaco.editor.ISingleEditOperation {
if (!textEdit) {
return void 0;
}
return {
range: toRange(textEdit.range),
text: textEdit.newText
}
}
export class CompletionAdapter implements monaco.languages.CompletionItemProvider {
constructor(private _worker: WorkerAccessor) {
}
public get triggerCharacters(): string[] {
return [' ', ':'];
}
provideCompletionItems(model: monaco.editor.IReadOnlyModel, position: Position, context: monaco.languages.CompletionContext, token: CancellationToken): Thenable<monaco.languages.CompletionList> {
const wordInfo = model.getWordUntilPosition(position);
const resource = model.uri;
return this._worker(resource).then(worker => {
return worker.doComplete(resource.toString(), fromPosition(position));
}).then(info => {
if (!info) {
return;
}
let items: monaco.languages.CompletionItem[] = info.items.map(entry => {
let item: monaco.languages.CompletionItem = {
label: entry.label,
insertText: entry.insertText || entry.label,
sortText: entry.sortText,
filterText: entry.filterText,
documentation: entry.documentation,
detail: entry.detail,
kind: toCompletionItemKind(entry.kind),
};
if (entry.textEdit) {
item.range = toRange(entry.textEdit.range);
item.insertText = entry.textEdit.newText;
}
if (entry.additionalTextEdits) {
item.additionalTextEdits = entry.additionalTextEdits.map(toTextEdit)
}
if (entry.insertTextFormat === ls.InsertTextFormat.Snippet) {
item.insertTextRules = monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet;
}
return item;
});
return {
isIncomplete: info.isIncomplete,
suggestions: items
};
});
}
}
function isMarkupContent(thing: any): thing is ls.MarkupContent {
return thing && typeof thing === 'object' && typeof (<ls.MarkupContent>thing).kind === 'string';
}
function toMarkdownString(entry: ls.MarkupContent | ls.MarkedString): monaco.IMarkdownString {
if (typeof entry === 'string') {
return {
value: entry
};
}
if (isMarkupContent(entry)) {
if (entry.kind === 'plaintext') {
return {
value: entry.value.replace(/[\\`*_{}[\]()#+\-.!]/g, '\\$&')
};
}
return {
value: entry.value
};
}
return { value: '```' + entry.language + '\n' + entry.value + '\n```\n' };
}
function toMarkedStringArray(contents: ls.MarkupContent | ls.MarkedString | ls.MarkedString[]): monaco.IMarkdownString[] {
if (!contents) {
return void 0;
}
if (Array.isArray(contents)) {
return contents.map(toMarkdownString);
}
return [toMarkdownString(contents)];
}
// --- hover ------
export class HoverAdapter implements monaco.languages.HoverProvider {
constructor(private _worker: WorkerAccessor) { }
provideHover(model: monaco.editor.IReadOnlyModel, position: Position, token: CancellationToken): Thenable<monaco.languages.Hover> {
let resource = model.uri;
return this._worker(resource).then(worker => {
return worker.doHover(resource.toString(), fromPosition(position));
}).then(info => {
if (!info) {
return;
}
return <monaco.languages.Hover>{
range: toRange(info.range),
contents: toMarkedStringArray(info.contents)
};
});
}
}
// --- document symbols ------
function toSymbolKind(kind: ls.SymbolKind): monaco.languages.SymbolKind {
let mKind = monaco.languages.SymbolKind;
switch (kind) {
case ls.SymbolKind.File: return mKind.Array;
case ls.SymbolKind.Module: return mKind.Module;
case ls.SymbolKind.Namespace: return mKind.Namespace;
case ls.SymbolKind.Package: return mKind.Package;
case ls.SymbolKind.Class: return mKind.Class;
case ls.SymbolKind.Method: return mKind.Method;
case ls.SymbolKind.Property: return mKind.Property;
case ls.SymbolKind.Field: return mKind.Field;
case ls.SymbolKind.Constructor: return mKind.Constructor;
case ls.SymbolKind.Enum: return mKind.Enum;
case ls.SymbolKind.Interface: return mKind.Interface;
case ls.SymbolKind.Function: return mKind.Function;
case ls.SymbolKind.Variable: return mKind.Variable;
case ls.SymbolKind.Constant: return mKind.Constant;
case ls.SymbolKind.String: return mKind.String;
case ls.SymbolKind.Number: return mKind.Number;
case ls.SymbolKind.Boolean: return mKind.Boolean;
case ls.SymbolKind.Array: return mKind.Array;
}
return mKind.Function;
}
export class DocumentSymbolAdapter implements monaco.languages.DocumentSymbolProvider {
constructor(private _worker: WorkerAccessor) {
}
public provideDocumentSymbols(model: monaco.editor.IReadOnlyModel, token: CancellationToken): Thenable<monaco.languages.DocumentSymbol[]> {
const resource = model.uri;
return this._worker(resource).then(worker => worker.findDocumentSymbols(resource.toString())).then(items => {
if (!items) {
return;
}
return items.map(item => toDocumentSymbol(item));
});
}
}
function toDocumentSymbol(item: ls.DocumentSymbol): monaco.languages.DocumentSymbol {
return {
detail: '',
range: toRange(item.range),
name: item.name,
kind: toSymbolKind(item.kind),
selectionRange: toRange(item.selectionRange),
children: item.children.map(child => toDocumentSymbol(child)),
}
}
function fromFormattingOptions(options: monaco.languages.FormattingOptions): ls.FormattingOptions {
return {
tabSize: options.tabSize,
insertSpaces: options.insertSpaces
};
}
export class DocumentFormattingEditProvider implements monaco.languages.DocumentFormattingEditProvider {
constructor(private _worker: WorkerAccessor) {
}
public provideDocumentFormattingEdits(model: monaco.editor.IReadOnlyModel, options: monaco.languages.FormattingOptions, token: CancellationToken): Thenable<monaco.editor.ISingleEditOperation[]> {
const resource = model.uri;
return this._worker(resource).then(worker => {
return worker.format(resource.toString(), null, fromFormattingOptions(options)).then(edits => {
if (!edits || edits.length === 0) {
return;
}
return edits.map(toTextEdit);
});
});
}
}
export class DocumentRangeFormattingEditProvider implements monaco.languages.DocumentRangeFormattingEditProvider {
constructor(private _worker: WorkerAccessor) {
}
public provideDocumentRangeFormattingEdits(model: monaco.editor.IReadOnlyModel, range: Range, options: monaco.languages.FormattingOptions, token: CancellationToken): Thenable<monaco.editor.ISingleEditOperation[]> {
const resource = model.uri;
return this._worker(resource).then(worker => {
return worker.format(resource.toString(), fromRange(range), fromFormattingOptions(options)).then(edits => {
if (!edits || edits.length === 0) {
return;
}
return edits.map(toTextEdit);
});
});
}
}
export class DocumentColorAdapter implements monaco.languages.DocumentColorProvider {
constructor(private _worker: WorkerAccessor) {
}
public provideDocumentColors(model: monaco.editor.IReadOnlyModel, token: CancellationToken): Thenable<monaco.languages.IColorInformation[]> {
const resource = model.uri;
return this._worker(resource).then(worker => worker.findDocumentColors(resource.toString())).then(infos => {
if (!infos) {
return;
}
return infos.map(item => ({
color: item.color,
range: toRange(item.range)
}));
});
}
public provideColorPresentations(model: monaco.editor.IReadOnlyModel, info: monaco.languages.IColorInformation, token: CancellationToken): Thenable<monaco.languages.IColorPresentation[]> {
const resource = model.uri;
return this._worker(resource).then(worker => worker.getColorPresentations(resource.toString(), info.color, fromRange(info.range))).then(presentations => {
if (!presentations) {
return;
}
return presentations.map(presentation => {
let item: monaco.languages.IColorPresentation = {
label: presentation.label,
};
if (presentation.textEdit) {
item.textEdit = toTextEdit(presentation.textEdit)
}
if (presentation.additionalTextEdits) {
item.additionalTextEdits = presentation.additionalTextEdits.map(toTextEdit)
}
return item;
});
});
}
}

View file

@ -5,7 +5,8 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import {Thenable, MarkedString, CompletionItem} from 'vscode-json-languageservice';
import { Thenable } from './jsonLanguageTypes';
import { MarkedString, CompletionItem } from 'vscode-languageserver-types';
export interface JSONWorkerContribution {
getInfoContribution(uri: string, location: JSONPath): Thenable<MarkedString[]>;
@ -23,4 +24,4 @@ export interface CompletionsCollector {
log(message: string): void;
setAsIncomplete(): void;
getNumberOfProposals(): number;
}
}

View file

@ -0,0 +1,258 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { JSONWorkerContribution, JSONPath, Segment, CompletionsCollector } from './jsonContributions';
import { JSONSchema } from './jsonSchema';
import { Range, TextEdit, Color, ColorInformation, ColorPresentation, FoldingRange, FoldingRangeKind, MarkupKind } from 'vscode-languageserver-types';
export {
Range, TextEdit, JSONSchema, JSONWorkerContribution, JSONPath, Segment, CompletionsCollector,
Color, ColorInformation, ColorPresentation, FoldingRange, FoldingRangeKind
};
/**
* Error codes used by diagnostics
*/
export enum ErrorCode {
Undefined = 0,
EnumValueMismatch = 1,
UnexpectedEndOfComment = 0x101,
UnexpectedEndOfString = 0x102,
UnexpectedEndOfNumber = 0x103,
InvalidUnicode = 0x104,
InvalidEscapeCharacter = 0x105,
InvalidCharacter = 0x106,
PropertyExpected = 0x201,
CommaExpected = 0x202,
ColonExpected = 0x203,
ValueExpected = 0x204,
CommaOrCloseBacketExpected = 0x205,
CommaOrCloseBraceExpected = 0x206,
TrailingComma = 0x207,
DuplicateKey = 0x208,
CommentNotPermitted = 0x209,
SchemaResolveError = 0x300
}
export type ASTNode = ObjectASTNode | PropertyASTNode | ArrayASTNode | StringASTNode | NumberASTNode | BooleanASTNode | NullASTNode;
export interface BaseASTNode {
readonly type: 'object' | 'array' | 'property' | 'string' | 'number' | 'boolean' | 'null';
readonly parent?: ASTNode;
readonly offset: number;
readonly length: number;
readonly children?: ASTNode[];
readonly value?: string | boolean | number | null;
}
export interface ObjectASTNode extends BaseASTNode {
readonly type: 'object';
readonly properties: PropertyASTNode[];
readonly children: ASTNode[];
}
export interface PropertyASTNode extends BaseASTNode {
readonly type: 'property';
readonly keyNode: StringASTNode;
readonly valueNode?: ASTNode;
readonly colonOffset?: number;
readonly children: ASTNode[];
}
export interface ArrayASTNode extends BaseASTNode {
readonly type: 'array';
readonly items: ASTNode[];
readonly children: ASTNode[];
}
export interface StringASTNode extends BaseASTNode {
readonly type: 'string';
readonly value: string;
}
export interface NumberASTNode extends BaseASTNode {
readonly type: 'number';
readonly value: number;
readonly isInteger: boolean;
}
export interface BooleanASTNode extends BaseASTNode {
readonly type: 'boolean';
readonly value: boolean;
}
export interface NullASTNode extends BaseASTNode {
readonly type: 'null';
readonly value: null;
}
export interface LanguageSettings {
/**
* If set, the validator will return syntax and semantic errors.
*/
validate?: boolean;
/**
* Defines whether comments are allowed or not. If set to false, comments will be reported as errors.
* DocumentLanguageSettings.allowComments will override this setting.
*/
allowComments?: boolean;
/**
* A list of known schemas and/or associations of schemas to file names.
*/
schemas?: SchemaConfiguration[];
}
export type SeverityLevel = 'error' | 'warning' | 'ignore';
export interface DocumentLanguageSettings {
/**
* The severity of reported comments. If not set, 'LanguageSettings.allowComments' defines wheter comments are ignored or reported as errors.
*/
comments?: SeverityLevel;
/**
* The severity of reported trailing commas. If not set, trailing commas will be reported as errors.
*/
trailingCommas?: SeverityLevel;
}
export interface SchemaConfiguration {
/**
* The URI of the schema, which is also the identifier of the schema.
*/
uri: string;
/**
* A list of file names that are associated to the schema. The '*' wildcard can be used. For example '*.schema.json', 'package.json'
*/
fileMatch?: string[];
/**
* The schema for the given URI.
* If no schema is provided, the schema will be fetched with the schema request service (if available).
*/
schema?: JSONSchema;
}
export interface WorkspaceContextService {
resolveRelativePath(relativePath: string, resource: string): string;
}
/**
* The schema request service is used to fetch schemas. The result should the schema file comment, or,
* in case of an error, a displayable error string
*/
export interface SchemaRequestService {
(uri: string): Thenable<string>;
}
export interface PromiseConstructor {
/**
* Creates a new Promise.
* @param executor A callback used to initialize the promise. This callback is passed two arguments:
* a resolve callback used resolve the promise with a value or the result of another promise,
* and a reject callback used to reject the promise with a provided reason or error.
*/
new <T>(executor: (resolve: (value?: T | Thenable<T>) => void, reject: (reason?: any) => void) => void): Thenable<T>;
/**
* Creates a Promise that is resolved with an array of results when all of the provided Promises
* resolve, or rejected when any Promise is rejected.
* @param values An array of Promises.
* @returns A new Promise.
*/
all<T>(values: Array<T | Thenable<T>>): Thenable<T[]>;
/**
* Creates a new rejected promise for the provided reason.
* @param reason The reason the promise was rejected.
* @returns A new rejected Promise.
*/
reject<T>(reason: any): Thenable<T>;
/**
* Creates a new resolved promise for the provided value.
* @param value A promise.
* @returns A promise whose internal state matches the provided promise.
*/
resolve<T>(value: T | Thenable<T>): Thenable<T>;
}
export interface Thenable<R> {
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult>(onfulfilled?: (value: R) => TResult | Thenable<TResult>, onrejected?: (reason: any) => TResult | Thenable<TResult>): Thenable<TResult>;
then<TResult>(onfulfilled?: (value: R) => TResult | Thenable<TResult>, onrejected?: (reason: any) => void): Thenable<TResult>;
}
export interface LanguageServiceParams {
/**
* The schema request service is used to fetch schemas. The result should the schema file comment, or,
* in case of an error, a displayable error string
*/
schemaRequestService?: SchemaRequestService;
/**
* The workspace context is used to resolve relative paths for relative schema references.
*/
workspaceContext?: WorkspaceContextService;
/**
* An optional set of completion and hover participants.
*/
contributions?: JSONWorkerContribution[];
/**
* A promise constructor. If not set, the ES5 Promise will be used.
*/
promiseConstructor?: PromiseConstructor;
/**
* Describes the LSP capabilities the client supports.
*/
clientCapabilities?: ClientCapabilities;
}
/**
* Describes what LSP capabilities the client supports
*/
export interface ClientCapabilities {
/**
* The text document client capabilities
*/
textDocument?: {
/**
* Capabilities specific to completions.
*/
completion?: {
/**
* The client supports the following `CompletionItem` specific
* capabilities.
*/
completionItem?: {
/**
* Client supports the follow content formats for the documentation
* property. The order describes the preferred format of the client.
*/
documentationFormat?: MarkupKind[];
};
};
/**
* Capabilities specific to hovers.
*/
hover?: {
/**
* Client supports the follow content formats for the content
* property. The order describes the preferred format of the client.
*/
contentFormat?: MarkupKind[];
};
};
}
export namespace ClientCapabilities {
export const LATEST: ClientCapabilities = {
textDocument: {
completion: {
completionItem: {
documentationFormat: [MarkupKind.Markdown, MarkupKind.PlainText]
}
}
}
};
}

View file

@ -1,53 +1,76 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Red Hat, Inc. All rights reserved.
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
export type JSONSchemaRef = JSONSchema | boolean;
export interface JSONSchema {
id?: string;
$id?: string;
$schema?: string;
type?: string | string[];
title?: string;
default?: any;
definitions?: JSONSchemaMap;
definitions?: { [name: string]: JSONSchema };
description?: string;
properties?: JSONSchemaMap;
patternProperties?: JSONSchemaMap;
additionalProperties?: any;
additionalProperties?: boolean | JSONSchemaRef;
minProperties?: number;
maxProperties?: number;
dependencies?: JSONSchemaMap | string[];
items?: any;
dependencies?: JSONSchemaMap | { [prop: string]: string[] };
items?: JSONSchemaRef | JSONSchemaRef[];
minItems?: number;
maxItems?: number;
uniqueItems?: boolean;
additionalItems?: boolean;
additionalItems?: boolean | JSONSchemaRef;
pattern?: string;
minLength?: number;
maxLength?: number;
minimum?: number;
maximum?: number;
exclusiveMinimum?: boolean;
exclusiveMaximum?: boolean;
exclusiveMinimum?: boolean | number;
exclusiveMaximum?: boolean | number;
multipleOf?: number;
required?: string[];
$ref?: string;
anyOf?: JSONSchema[];
allOf?: JSONSchema[];
oneOf?: JSONSchema[];
not?: JSONSchema;
anyOf?: JSONSchemaRef[];
allOf?: JSONSchemaRef[];
oneOf?: JSONSchemaRef[];
not?: JSONSchemaRef;
enum?: any[];
format?: string;
// schema draft 06
const?: any;
contains?: JSONSchemaRef;
propertyNames?: JSONSchemaRef;
examples?: any[];
// schema draft 07
$comment?: string;
if?: JSONSchemaRef;
then?: JSONSchemaRef;
else?: JSONSchemaRef;
// VSCode extensions
defaultSnippets?: { label?: string; description?: string; markdownDescription?: string; body?: any; bodyText?: string; }[]; // VSCode extension: body: a object that will be converted to a JSON string. bodyText: text with \t and \n
errorMessage?: string; // VSCode extension
patternErrorMessage?: string; // VSCode extension
deprecationMessage?: string; // VSCode extension
enumDescriptions?: string[]; // VSCode extension
schemaSequence?: JSONSchema[]; // extension for multiple schemas related to multiple documents in single yaml file
markdownEnumDescriptions?: string[]; // VSCode extension
markdownDescription?: string; // VSCode extension
doNotSuggest?: boolean; // VSCode extension
allowComments?: boolean; // VSCode extension
schemaSequence?: JSONSchema[]; // extension for multiple schemas related to multiple documents in single yaml file
"x-kubernetes-group-version-kind"?; //Kubernetes extension
}
export interface JSONSchemaMap {
[name: string]:JSONSchema;
[name: string]: JSONSchemaRef;
}

File diff suppressed because it is too large Load diff

View file

@ -5,270 +5,188 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { ASTNode, ErrorCode, BooleanASTNode, NullASTNode, ArrayASTNode, NumberASTNode, ObjectASTNode, PropertyASTNode, StringASTNode, IApplicableSchema, JSONDocument } from './jsonParser';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
import * as Yaml from '../../yaml-ast-parser/index'
import { Kind } from '../../yaml-ast-parser/index'
import { Schema, Type } from 'js-yaml';
import { getLineStartPositions, getPosition } from '../utils/documentPositionCalculator'
import { getLineStartPositions } from '../utils/documentPositionCalculator'
import { parseYamlBoolean } from './scalar-type';
export class SingleYAMLDocument extends JSONDocument {
private lines;
public root;
public errors;
public warnings;
constructor(lines: number[]) {
super(null, []);
this.lines = lines;
this.root = null;
this.errors = [];
this.warnings = [];
}
public getSchemas(schema, doc, node) {
let matchingSchemas = [];
doc.validate(schema, matchingSchemas, node.start);
return matchingSchemas;
}
public getNodeFromOffset(offset: number): ASTNode {
return this.getNodeFromOffsetEndInclusive(offset);
}
private getNodeByIndent = (lines: number[], offset: number, node: ASTNode) => {
const { line, column: indent } = getPosition(offset, this.lines)
const children = node.getChildNodes()
function findNode(children) {
for (var idx = 0; idx < children.length; idx++) {
var child = children[idx];
const { line: childLine, column: childCol } = getPosition(child.start, lines);
if (childCol > indent) {
return null;
}
const newChildren = child.getChildNodes()
const foundNode = findNode(newChildren)
if (foundNode) {
return foundNode;
}
// We have the right indentation, need to return based on line
if (childLine == line) {
return child;
}
if (childLine > line) {
// Get previous
(idx - 1) >= 0 ? children[idx - 1] : child;
}
// Else continue loop to try next element
}
// Special case, we found the correct
return children[children.length - 1]
}
return findNode(children) || node
}
}
import { ObjectASTNodeImpl, StringASTNodeImpl, PropertyASTNodeImpl, NullASTNodeImpl, ArrayASTNodeImpl, BooleanASTNodeImpl, NumberASTNodeImpl } from './jsonParser';
import { ASTNode, PropertyASTNode, ErrorCode } from '../jsonLanguageTypes';
import { SingleYAMLDocument, YAMLDocument } from '../yamlLanguageTypes';
function recursivelyBuildAst(parent: ASTNode, node: Yaml.YAMLNode): ASTNode {
if (!node) {
return;
}
if (!node) {
return;
}
switch (node.kind) {
case Yaml.Kind.MAP: {
const instance = <Yaml.YamlMap>node;
switch (node.kind) {
case Yaml.Kind.MAP: {
const instance = <Yaml.YamlMap>node;
const result = new ObjectASTNode(parent, null, node.startPosition, node.endPosition)
result.addProperty
const result = new ObjectASTNodeImpl(parent, node.startPosition, node.endPosition - node.startPosition)
for (const mapping of instance.mappings) {
result.addProperty(<PropertyASTNode>recursivelyBuildAst(result, mapping))
}
for (const mapping of instance.mappings) {
result.properties.push(<PropertyASTNode>recursivelyBuildAst(result, mapping));
}
return result;
}
case Yaml.Kind.MAPPING: {
const instance = <Yaml.YAMLMapping>node;
const key = instance.key;
return result;
}
case Yaml.Kind.MAPPING: {
const instance = <Yaml.YAMLMapping>node;
const key = instance.key;
// Technically, this is an arbitrary node in YAML
// I doubt we would get a better string representation by parsing it
const keyNode = new StringASTNode(null, null, true, key.startPosition, key.endPosition);
keyNode.value = key.value;
const result = new PropertyASTNodeImpl(<ObjectASTNodeImpl>parent, key.startPosition, instance.endPosition - key.startPosition);
const result = new PropertyASTNode(parent, keyNode)
result.end = instance.endPosition
const valueNode = (instance.value) ? recursivelyBuildAst(result, instance.value) : new NullASTNode(parent, key.value, instance.endPosition, instance.endPosition)
valueNode.location = key.value
// Technically, this is an arbitrary node in YAML
// I doubt we would get a better string representation by parsing it
const keyNode = new StringASTNodeImpl(result, key.startPosition, key.endPosition - key.startPosition);
keyNode.value = key.value;
result.setValue(valueNode)
const valueNode = (instance.value) ? recursivelyBuildAst(result, instance.value) : new NullASTNodeImpl(parent, instance.startPosition)
return result;
}
case Yaml.Kind.SEQ: {
const instance = <Yaml.YAMLSequence>node;
result.keyNode = keyNode;
result.valueNode = valueNode;
const result = new ArrayASTNode(parent, null, instance.startPosition, instance.endPosition);
return result;
}
case Yaml.Kind.SEQ: {
const instance = <Yaml.YAMLSequence>node;
let count = 0;
for (const item of instance.items) {
if (item === null && count === instance.items.length - 1) {
break;
}
const result = new ArrayASTNodeImpl(parent, instance.startPosition, instance.endPosition - instance.startPosition);
// Be aware of https://github.com/nodeca/js-yaml/issues/321
// Cannot simply work around it here because we need to know if we are in Flow or Block
var itemNode = (item === null) ? new NullASTNode(parent, null, instance.endPosition, instance.endPosition) : recursivelyBuildAst(result, item);
let count = 0;
for (const item of instance.items) {
if (item === null && count === instance.items.length - 1) {
break;
}
itemNode.location = count++;
result.addItem(itemNode);
}
// Be aware of https://github.com/nodeca/js-yaml/issues/321
// Cannot simply work around it here because we need to know if we are in Flow or Block
var itemNode = (item === null) ? new NullASTNodeImpl(parent, instance.startPosition, instance.endPosition - instance.startPosition) : recursivelyBuildAst(result, item);
return result;
}
case Yaml.Kind.SCALAR: {
const instance = <Yaml.YAMLScalar>node;
const type = Yaml.determineScalarType(instance)
result.items.push(itemNode);
}
// The name is set either by the sequence or the mapping case.
const name = null;
const value = instance.value;
return result;
}
case Yaml.Kind.SCALAR: {
const instance = <Yaml.YAMLScalar>node;
const type = Yaml.determineScalarType(instance)
//This is a patch for redirecting values with these strings to be boolean nodes because its not supported in the parser.
let possibleBooleanValues = ['y', 'Y', 'yes', 'Yes', 'YES', 'n', 'N', 'no', 'No', 'NO', 'on', 'On', 'ON', 'off', 'Off', 'OFF'];
if (instance.plainScalar && possibleBooleanValues.indexOf(value.toString()) !== -1) {
return new BooleanASTNode(parent, name, parseYamlBoolean(value), node.startPosition, node.endPosition)
}
// The name is set either by the sequence or the mapping case.
const name = null;
const value = instance.value;
switch (type) {
case Yaml.ScalarType.null: {
return new StringASTNode(parent, name, false, instance.startPosition, instance.endPosition);
}
case Yaml.ScalarType.bool: {
return new BooleanASTNode(parent, name, Yaml.parseYamlBoolean(value), node.startPosition, node.endPosition)
}
case Yaml.ScalarType.int: {
const result = new NumberASTNode(parent, name, node.startPosition, node.endPosition);
result.value = Yaml.parseYamlInteger(value);
result.isInteger = true;
return result;
}
case Yaml.ScalarType.float: {
const result = new NumberASTNode(parent, name, node.startPosition, node.endPosition);
result.value = Yaml.parseYamlFloat(value);
result.isInteger = false;
return result;
}
case Yaml.ScalarType.string: {
const result = new StringASTNode(parent, name, false, node.startPosition, node.endPosition);
result.value = node.value;
return result;
}
}
//This is a patch for redirecting values with these strings to be boolean nodes because its not supported in the parser.
let possibleBooleanValues = ['y', 'Y', 'yes', 'Yes', 'YES', 'n', 'N', 'no', 'No', 'NO', 'on', 'On', 'ON', 'off', 'Off', 'OFF'];
if (instance.plainScalar && possibleBooleanValues.indexOf(value.toString()) !== -1) {
return new BooleanASTNodeImpl(parent, parseYamlBoolean(value), node.startPosition, node.endPosition - node.startPosition)
}
break;
}
case Yaml.Kind.ANCHOR_REF: {
const instance = (<Yaml.YAMLAnchorReference>node).value
switch (type) {
case Yaml.ScalarType.null: {
return new NullASTNodeImpl(parent, instance.startPosition, instance.endPosition - instance.startPosition);
}
case Yaml.ScalarType.bool: {
return new BooleanASTNodeImpl(parent, Yaml.parseYamlBoolean(value), node.startPosition, node.endPosition - node.startPosition)
}
case Yaml.ScalarType.int: {
const result = new NumberASTNodeImpl(parent, node.startPosition, node.endPosition - node.startPosition);
result.value = Yaml.parseYamlInteger(value);
result.isInteger = true;
return result;
}
case Yaml.ScalarType.float: {
const result = new NumberASTNodeImpl(parent, node.startPosition, node.endPosition - node.startPosition);
result.value = Yaml.parseYamlFloat(value);
result.isInteger = false;
return result;
}
case Yaml.ScalarType.string: {
const result = new StringASTNodeImpl(parent, node.startPosition, node.endPosition - node.startPosition);
result.value = node.value;
return result;
}
}
return recursivelyBuildAst(parent, instance) ||
new NullASTNode(parent, null, node.startPosition, node.endPosition);
}
case Yaml.Kind.INCLUDE_REF: {
const result = new StringASTNode(parent, null, false, node.startPosition, node.endPosition);
result.value = node.value;
return result;
}
}
break;
}
case Yaml.Kind.ANCHOR_REF: {
const instance = (<Yaml.YAMLAnchorReference>node).value
return recursivelyBuildAst(parent, instance) ||
new NullASTNodeImpl(parent, node.startPosition, node.endPosition - node.startPosition);
}
case Yaml.Kind.INCLUDE_REF: {
const result = new StringASTNodeImpl(parent, node.startPosition, node.endPosition - node.startPosition);
result.value = node.value;
return result;
}
}
}
function convertError(e: Yaml.Error) {
return { message: `${e.reason}`, location: { start: e.mark.position, end: e.mark.position + e.mark.column, code: ErrorCode.Undefined } }
return { message: `${e.reason}`, location: { start: e.mark.position, end: e.mark.position + e.mark.column, code: ErrorCode.Undefined } }
}
function createJSONDocument(yamlDoc: Yaml.YAMLNode, startPositions: number[], text: string) {
let _doc = new SingleYAMLDocument(startPositions);
_doc.root = recursivelyBuildAst(null, yamlDoc)
let _doc = new SingleYAMLDocument(startPositions);
_doc.root = recursivelyBuildAst(null, yamlDoc)
if (!_doc.root) {
// TODO: When this is true, consider not pushing the other errors.
_doc.errors.push({ message: localize('Invalid symbol', 'Expected a YAML object, array or literal'), code: ErrorCode.Undefined, location: { start: yamlDoc.startPosition, end: yamlDoc.endPosition } });
}
if (!_doc.root) {
// TODO: When this is true, consider not pushing the other errors.
_doc.errors.push({ message: localize('Invalid symbol', 'Expected a YAML object, array or literal'), code: ErrorCode.Undefined, location: { start: yamlDoc.startPosition, end: yamlDoc.endPosition } });
}
const duplicateKeyReason = 'duplicate key'
const duplicateKeyReason = 'duplicate key'
//Patch ontop of yaml-ast-parser to disable duplicate key message on merge key
let isDuplicateAndNotMergeKey = function (error: Yaml.Error, yamlText: string) {
let errorConverted = convertError(error);
let errorStart = errorConverted.location.start;
let errorEnd = errorConverted.location.end;
if (error.reason === duplicateKeyReason && yamlText.substring(errorStart, errorEnd).startsWith("<<")) {
return false;
}
return true;
};
const errors = yamlDoc.errors.filter(e => e.reason !== duplicateKeyReason && !e.isWarning).map(e => convertError(e))
const warnings = yamlDoc.errors.filter(e => (e.reason === duplicateKeyReason && isDuplicateAndNotMergeKey(e, text)) || e.isWarning).map(e => convertError(e))
//Patch ontop of yaml-ast-parser to disable duplicate key message on merge key
let isDuplicateAndNotMergeKey = function (error: Yaml.Error, yamlText: string) {
let errorConverted = convertError(error);
let errorStart = errorConverted.location.start;
let errorEnd = errorConverted.location.end;
if (error.reason === duplicateKeyReason && yamlText.substring(errorStart, errorEnd).startsWith("<<")) {
return false;
}
return true;
};
const errors = yamlDoc.errors.filter(e => e.reason !== duplicateKeyReason && !e.isWarning).map(e => convertError(e))
const warnings = yamlDoc.errors.filter(e => (e.reason === duplicateKeyReason && isDuplicateAndNotMergeKey(e, text)) || e.isWarning).map(e => convertError(e))
errors.forEach(e => _doc.errors.push(e));
warnings.forEach(e => _doc.warnings.push(e));
return _doc;
}
export class YAMLDocument {
public documents: JSONDocument[]
private errors;
private warnings;
constructor(documents: JSONDocument[]) {
this.documents = documents;
this.errors = [];
this.warnings = [];
}
errors.forEach(e => _doc.errors.push(e));
warnings.forEach(e => _doc.warnings.push(e));
return _doc;
}
export function parse(text: string, customTags = []): YAMLDocument {
const startPositions = getLineStartPositions(text)
// This is documented to return a YAMLNode even though the
// typing only returns a YAMLDocument
const yamlDocs = []
const startPositions = getLineStartPositions(text)
// This is documented to return a YAMLNode even though the
// typing only returns a YAMLDocument
const yamlDocs = []
let schemaWithAdditionalTags = Schema.create(customTags.map((tag) => {
const typeInfo = tag.split(' ');
return new Type(typeInfo[0], { kind: typeInfo[1] || 'scalar' });
}));
let schemaWithAdditionalTags = Schema.create(customTags.map((tag) => {
const typeInfo = tag.split(' ');
return new Type(typeInfo[0], { kind: typeInfo[1] || 'scalar' });
}));
//We need compiledTypeMap to be available from schemaWithAdditionalTags before we add the new custom properties
customTags.map((tag) => {
const typeInfo = tag.split(' ');
schemaWithAdditionalTags.compiledTypeMap[typeInfo[0]] = new Type(typeInfo[0], { kind: typeInfo[1] || 'scalar' });
});
//We need compiledTypeMap to be available from schemaWithAdditionalTags before we add the new custom properties
customTags.map((tag) => {
const typeInfo = tag.split(' ');
schemaWithAdditionalTags.compiledTypeMap[typeInfo[0]] = new Type(typeInfo[0], { kind: typeInfo[1] || 'scalar' });
});
let additionalOptions: Yaml.LoadOptions = {
schema: schemaWithAdditionalTags
}
let additionalOptions: Yaml.LoadOptions = {
schema: schemaWithAdditionalTags
}
Yaml.loadAll(text, doc => yamlDocs.push(doc), additionalOptions);
Yaml.loadAll(text, doc => yamlDocs.push(doc), additionalOptions);
return new YAMLDocument(yamlDocs.map(doc => createJSONDocument(doc, startPositions, text)));
}
return new YAMLDocument(yamlDocs.map(doc => createJSONDocument(doc, startPositions, text)));
}

View file

@ -5,68 +5,130 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as Parser from '../parser/jsonParser';
import { SymbolInformation, SymbolKind, TextDocument, Range, Location } from 'vscode-languageserver-types';
import { Thenable } from "../yamlLanguageService";
import { IJSONSchemaService } from "./jsonSchemaService";
import { SymbolKind, TextDocument, Range, DocumentSymbol, ColorInformation, ColorPresentation, Color, TextEdit } from 'vscode-languageserver-types';
import { ASTNode, PropertyASTNode, Thenable } from '../jsonLanguageTypes';
import { YAMLDocument, SingleYAMLDocument } from '../yamlLanguageTypes';
import { IJSONSchemaService } from './jsonSchemaService';
import { colorFromHex } from '../utils/colors';
import { getNodeValue } from '../parser/jsonParser';
export class YAMLDocumentSymbols {
constructor(private schemaService: IJSONSchemaService) {
}
public findDocumentSymbols(document: TextDocument, doc: Parser.JSONDocument): SymbolInformation[] {
public findDocumentSymbols(document: TextDocument, doc: YAMLDocument): DocumentSymbol[] {
if (!doc || doc.documents.length === 0) {
return null;
}
if(!doc || doc["documents"].length === 0){
return null;
}
let collectOutlineEntries = (result: DocumentSymbol[], node: ASTNode): DocumentSymbol[] => {
if (node.type === 'array') {
node.items.forEach((node, index) => {
if (node) {
let range = getRange(document, node);
let selectionRange = range;
let name = String(index);
let children = collectOutlineEntries([], node);
result.push({ name, kind: this.getSymbolKind(node.type), range, selectionRange, children });
}
});
} else if (node.type === 'object') {
node.properties.forEach((property: PropertyASTNode) => {
let valueNode = property.valueNode;
if (valueNode) {
let range = getRange(document, property);
let selectionRange = getRange(document, property.keyNode);
let name = property.keyNode.value;
let children = collectOutlineEntries([], valueNode);
result.push({ name, kind: this.getSymbolKind(valueNode.type), range, selectionRange, children });
}
});
}
return result;
};
let collectOutlineEntries = (result: SymbolInformation[], node: Parser.ASTNode, containerName: string): SymbolInformation[] => {
if (node.type === 'array') {
(<Parser.ArrayASTNode>node).items.forEach((node: Parser.ASTNode) => {
collectOutlineEntries(result, node, containerName);
});
} else if (node.type === 'object') {
let objectNode = <Parser.ObjectASTNode>node;
let results = [];
for (let yamlDoc of doc.documents) {
if (yamlDoc.root) {
const result = collectOutlineEntries([], yamlDoc.root);
results = results.concat(result);
}
}
objectNode.properties.forEach((property: Parser.PropertyASTNode) => {
let location = Location.create(document.uri, Range.create(document.positionAt(property.start), document.positionAt(property.end)));
let valueNode = property.value;
if (valueNode) {
let childContainerName = containerName ? containerName + '.' + property.key.value : property.key.value;
result.push({ name: property.key.getValue(), kind: this.getSymbolKind(valueNode.type), location: location, containerName: containerName });
collectOutlineEntries(result, valueNode, childContainerName);
}
});
}
return result;
};
return results;
}
let results = [];
for(let yamlDoc in doc["documents"]){
let currentYAMLDoc = doc["documents"][yamlDoc];
if(currentYAMLDoc.root){
let result = collectOutlineEntries([], currentYAMLDoc.root, void 0);
results = results.concat(result);
}
}
private getSymbolKind(nodeType: string): SymbolKind {
switch (nodeType) {
case 'object':
return SymbolKind.Module;
case 'string':
return SymbolKind.String;
case 'number':
return SymbolKind.Number;
case 'array':
return SymbolKind.Array;
case 'boolean':
return SymbolKind.Boolean;
default: // 'null'
return SymbolKind.Variable;
}
}
return results;
}
public findDocumentColors(document: TextDocument, doc: YAMLDocument): Thenable<ColorInformation[]> {
if (!doc || doc.documents.length === 0) {
return Promise.resolve([]);
}
private getSymbolKind(nodeType: string): SymbolKind {
switch (nodeType) {
case 'object':
return SymbolKind.Module;
case 'string':
return SymbolKind.String;
case 'number':
return SymbolKind.Number;
case 'array':
return SymbolKind.Array;
case 'boolean':
return SymbolKind.Boolean;
default: // 'null'
return SymbolKind.Variable;
}
}
const _findDocumentColors = (currentDoc: SingleYAMLDocument) => {
return this.schemaService.getSchemaForResource(document.uri, currentDoc).then(schema => {
let result: ColorInformation[] = [];
if (schema) {
let matchingSchemas = currentDoc.getMatchingSchemas(schema.schema);
let visitedNode = {};
for (let s of matchingSchemas) {
if (!s.inverted && s.schema && (s.schema.format === 'color' || s.schema.format === 'color-hex') && s.node && s.node.type === 'string') {
let nodeId = String(s.node.offset);
if (!visitedNode[nodeId]) {
let color = colorFromHex(getNodeValue(s.node));
if (color) {
let range = getRange(document, s.node);
result.push({ color, range });
}
visitedNode[nodeId] = true;
}
}
}
}
return result;
});
}
}
return Promise.all(doc.documents.map(currentDoc => _findDocumentColors(currentDoc)))
.then(infoArray => infoArray.reduce((acc, infos) => ([...acc, ...infos]), []));
}
public getColorPresentations(document: TextDocument, doc: YAMLDocument, color: Color, range: Range): ColorPresentation[] {
let result: ColorPresentation[] = [];
let red256 = Math.round(color.red * 255), green256 = Math.round(color.green * 255), blue256 = Math.round(color.blue * 255);
function toTwoDigitHex(n: number): string {
const r = n.toString(16);
return r.length !== 2 ? '0' + r : r;
}
let label;
if (color.alpha === 1) {
label = `#${toTwoDigitHex(red256)}${toTwoDigitHex(green256)}${toTwoDigitHex(blue256)}`;
} else {
label = `#${toTwoDigitHex(red256)}${toTwoDigitHex(green256)}${toTwoDigitHex(blue256)}${toTwoDigitHex(Math.round(color.alpha * 255))}`;
}
result.push({ label: label, textEdit: TextEdit.replace(range, JSON.stringify(label)) });
return result;
}
}
function getRange(document: TextDocument, node: ASTNode) {
return Range.create(document.positionAt(node.offset), document.positionAt(node.offset + node.length));
}

View file

@ -6,36 +6,17 @@
'use strict';
import * as Json from 'jsonc-parser';
import {JSONSchema, JSONSchemaMap} from '../jsonSchema';
import {JSONSchema, JSONSchemaMap, JSONSchemaRef} from '../jsonSchema';
import URI from 'vscode-uri';
import * as Strings from '../utils/strings';
import * as Parser from '../parser/jsonParser';
import {SchemaRequestService, WorkspaceContextService, Thenable} from '../yamlLanguageService';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
/**
* getParseErrorMessage has been removed from jsonc-parser since 1.0.0
*
* see https://github.com/Microsoft/node-jsonc-parser/blob/42ec16f9c91582d4267a0c48199cdac283c90fc9/CHANGELOG.md
* 1.0.0
* remove nls dependency (remove getParseErrorMessage)
*/
function getParseErrorMessage(errorCode: Json.ParseErrorCode): string {
switch (errorCode) {
case Json.ParseErrorCode.InvalidSymbol: return localize('error.invalidSymbol', 'Invalid symbol');
case Json.ParseErrorCode.InvalidNumberFormat: return localize('error.invalidNumberFormat', 'Invalid number format');
case Json.ParseErrorCode.PropertyNameExpected: return localize('error.propertyNameExpected', 'Property name expected');
case Json.ParseErrorCode.ValueExpected: return localize('error.valueExpected', 'Value expected');
case Json.ParseErrorCode.ColonExpected: return localize('error.colonExpected', 'Colon expected');
case Json.ParseErrorCode.CommaExpected: return localize('error.commaExpected', 'Comma expected');
case Json.ParseErrorCode.CloseBraceExpected: return localize('error.closeBraceExpected', 'Closing brace expected');
case Json.ParseErrorCode.CloseBracketExpected: return localize('error.closeBracketExpected', 'Closing bracket expected');
case Json.ParseErrorCode.EndOfFileExpected: return localize('error.endOfFileExpected', 'End of file expected');
default: return '';
}
}
export declare type CustomSchemaProvider = (uri: string) => Thenable<string>;
export interface IJSONSchemaService {
@ -57,7 +38,7 @@ export interface IJSONSchemaService {
/**
* Looks up the appropriate schema for the given URI
*/
getSchemaForResource(resource: string): Thenable<ResolvedSchema>;
getSchemaForResource(resource: string, document?: Parser.JSONDocument): Thenable<ResolvedSchema>;
/**
* Returns all registered schema ids
@ -74,8 +55,6 @@ export interface ISchemaContributions {
schemaAssociations?: ISchemaAssociations;
}
export declare type CustomSchemaProvider = (uri: string) => Thenable<string>;
export interface ISchemaHandle {
/**
* The schema id
@ -94,39 +73,31 @@ export interface ISchemaHandle {
}
export class FilePatternAssociation {
class FilePatternAssociation {
private schemas: string[];
private combinedSchemaId: string;
private patternRegExp: RegExp;
private combinedSchema: ISchemaHandle;
constructor(pattern: string) {
this.combinedSchemaId = 'schemaservice://combinedSchema/' + encodeURIComponent(pattern);
try {
this.patternRegExp = Strings.convertSimple2RegExp(pattern);
this.patternRegExp = new RegExp(Strings.convertSimple2RegExpPattern(pattern) + '$');
} catch (e) {
// invalid pattern
this.patternRegExp = null;
}
this.schemas = [];
this.combinedSchema = null;
}
public addSchema(id: string) {
this.schemas.push(id);
this.combinedSchema = null;
}
public matchesPattern(fileName: string): boolean {
return this.patternRegExp && this.patternRegExp.test(fileName);
}
public getCombinedSchema(service: JSONSchemaService): ISchemaHandle {
if (!this.combinedSchema) {
this.combinedSchema = service.createCombinedSchema(this.combinedSchemaId, this.schemas);
}
return this.combinedSchema;
public getSchemas() {
return this.schemas;
}
}
@ -188,40 +159,34 @@ export class ResolvedSchema {
}
public getSection(path: string[]): JSONSchema {
return this.getSectionRecursive(path, this.schema);
return Parser.asSchema(this.getSectionRecursive(path, this.schema));
}
private getSectionRecursive(path: string[], schema: JSONSchema): JSONSchema {
if (!schema || path.length === 0) {
private getSectionRecursive(path: string[], schema: JSONSchemaRef): JSONSchemaRef {
if (!schema || typeof schema === 'boolean' || path.length === 0) {
return schema;
}
let next = path.shift();
if (schema.properties && schema.properties[next]) {
if (schema.properties && typeof schema.properties[next]) {
return this.getSectionRecursive(path, schema.properties[next]);
} else if (schema.patternProperties) {
Object.keys(schema.patternProperties).forEach((pattern) => {
for (const pattern of Object.keys(schema.patternProperties)) {
let regex = new RegExp(pattern);
if (regex.test(next)) {
return this.getSectionRecursive(path, schema.patternProperties[pattern]);
}
});
} else if (schema.additionalProperties) {
}
} else if (typeof schema.additionalProperties === 'object') {
return this.getSectionRecursive(path, schema.additionalProperties);
} else if (next.match('[0-9]+')) {
if (schema.items) {
if (Array.isArray(schema.items)) {
let index = parseInt(next, 10);
if (!isNaN(index) && schema.items[index]) {
return this.getSectionRecursive(path, schema.items[index]);
}
} else if (schema.items) {
return this.getSectionRecursive(path, schema.items);
} else if (Array.isArray(schema.items)) {
try {
let index = parseInt(next, 10);
if (schema.items[index]) {
return this.getSectionRecursive(path, schema.items[index]);
}
return null;
}
catch (e) {
return null;
}
}
}
@ -248,7 +213,7 @@ export class JSONSchemaService implements IJSONSchemaService {
this.contextService = contextService;
this.requestService = requestService;
this.callOnDispose = [];
this.customSchemaProvider = undefined;
this.contributionSchemas = {};
this.contributionAssociations = {};
this.schemasById = {};
@ -257,10 +222,6 @@ export class JSONSchemaService implements IJSONSchemaService {
this.registeredSchemasIds = {};
}
registerCustomSchemaProvider(customSchemaProvider: CustomSchemaProvider) {
this.customSchemaProvider = customSchemaProvider;
}
public getRegisteredSchemaIds(filter?: (scheme) => boolean): string[] {
return Object.keys(this.registeredSchemasIds).filter(id => {
let scheme = URI.parse(id).scheme;
@ -268,6 +229,10 @@ export class JSONSchemaService implements IJSONSchemaService {
});
}
registerCustomSchemaProvider(customSchemaProvider: CustomSchemaProvider) {
this.customSchemaProvider = customSchemaProvider;
}
public dispose(): void {
while (this.callOnDispose.length > 0) {
this.callOnDispose.pop()();
@ -304,10 +269,10 @@ export class JSONSchemaService implements IJSONSchemaService {
this.contributionAssociations[pattern] = associations;
var fpa = this.getOrAddFilePatternAssociation(pattern);
associations.forEach(schemaId => {
for (const schemaId of associations) {
let id = this.normalizeId(schemaId);
fpa.addSchema(id);
});
}
}
}
}
@ -337,9 +302,9 @@ export class JSONSchemaService implements IJSONSchemaService {
this.registeredSchemasIds[id] = true;
if (filePatterns) {
filePatterns.forEach(pattern => {
for (const pattern of filePatterns) {
this.getOrAddFilePatternAssociation(pattern).addSchema(id);
});
}
}
return unresolvedSchemaContent ? this.addSchemaHandle(id, unresolvedSchemaContent) : this.getOrAddSchemaHandle(id);
}
@ -356,11 +321,10 @@ export class JSONSchemaService implements IJSONSchemaService {
}
for (let pattern in this.contributionAssociations) {
var fpa = this.getOrAddFilePatternAssociation(pattern);
this.contributionAssociations[pattern].forEach(schemaId => {
for (const schemaId of this.contributionAssociations[pattern]) {
let id = this.normalizeId(schemaId);
fpa.addSchema(id);
});
}
}
}
@ -386,13 +350,18 @@ export class JSONSchemaService implements IJSONSchemaService {
}
let schemaContent: JSONSchema = {};
let jsonErrors = [];
let jsonErrors: Json.ParseError[] = [];
schemaContent = Json.parse(content, jsonErrors);
let errors = jsonErrors.length ? [localize('json.schema.invalidFormat', 'Unable to parse content from \'{0}\': {1}.', toDisplayString(url), getParseErrorMessage(jsonErrors[0]))] : [];
let errors = jsonErrors.length ? [localize('json.schema.invalidFormat', 'Unable to parse content from \'{0}\': Parse error at offset {1}.', toDisplayString(url), jsonErrors[0].offset)] : [];
return new UnresolvedSchema(schemaContent, errors);
},
(error: any) => {
let errorMessage = localize('json.schema.unabletoload', 'Unable to load schema from \'{0}\': {1}', toDisplayString(url), error.toString());
let errorMessage = error.toString();
let errorSplit = error.toString().split('Error: ');
if(errorSplit.length > 1) {
// more concise error message, URL and context are attached by caller anyways
errorMessage = errorSplit[1];
}
return new UnresolvedSchema(<JSONSchema>{}, [errorMessage]);
}
);
@ -419,21 +388,20 @@ export class JSONSchemaService implements IJSONSchemaService {
return current;
};
let resolveLink = (node: any, linkedSchema: JSONSchema, linkPath: string): void => {
let section = findSection(linkedSchema, linkPath);
let merge = (target: JSONSchema, sourceRoot: JSONSchema, sourceURI: string, path: string): void => {
let section = findSection(sourceRoot, path);
if (section) {
for (let key in section) {
if (section.hasOwnProperty(key) && !node.hasOwnProperty(key)) {
node[key] = section[key];
if (section.hasOwnProperty(key) && !target.hasOwnProperty(key)) {
target[key] = section[key];
}
}
} else {
resolveErrors.push(localize('json.schema.invalidref', '$ref \'{0}\' in {1} can not be resolved.', linkPath, linkedSchema.id));
resolveErrors.push(localize('json.schema.invalidref', '$ref \'{0}\' in \'{1}\' can not be resolved.', path, sourceURI));
}
delete node.$ref;
};
let resolveExternalLink = (node: any, uri: string, linkPath: string, parentSchemaURL: string): Thenable<any> => {
let resolveExternalLink = (node: JSONSchema, uri: string, linkPath: string, parentSchemaURL: string): Thenable<any> => {
if (contextService && !/^\w+:\/\/.*/.test(uri)) {
uri = contextService.resolveRelativePath(uri, parentSchemaURL);
}
@ -443,13 +411,13 @@ export class JSONSchemaService implements IJSONSchemaService {
let loc = linkPath ? uri + '#' + linkPath : uri;
resolveErrors.push(localize('json.schema.problemloadingref', 'Problems loading reference \'{0}\': {1}', loc, unresolvedSchema.errors[0]));
}
resolveLink(node, unresolvedSchema.schema, linkPath);
merge(node, unresolvedSchema.schema, uri, linkPath);
return resolveRefs(node, unresolvedSchema.schema, uri);
});
};
let resolveRefs = (node: JSONSchema, parentSchema: JSONSchema, parentSchemaURL: string): Thenable<any> => {
if (!node) {
if (!node || typeof node !== 'object') {
return Promise.resolve(null);
}
@ -458,7 +426,7 @@ export class JSONSchemaService implements IJSONSchemaService {
let openPromises: Thenable<any>[] = [];
let collectEntries = (...entries: JSONSchema[]) => {
let collectEntries = (...entries: JSONSchemaRef[]) => {
for (let entry of entries) {
if (typeof entry === 'object') {
toWalk.push(entry);
@ -470,36 +438,48 @@ export class JSONSchemaService implements IJSONSchemaService {
if (typeof map === 'object') {
for (let key in map) {
let entry = map[key];
toWalk.push(entry);
if (typeof entry === 'object') {
toWalk.push(entry);
}
}
}
}
};
let collectArrayEntries = (...arrays: JSONSchema[][]) => {
let collectArrayEntries = (...arrays: JSONSchemaRef[][]) => {
for (let array of arrays) {
if (Array.isArray(array)) {
toWalk.push.apply(toWalk, array);
for (let entry of array) {
if (typeof entry === 'object') {
toWalk.push(entry);
}
}
}
}
};
let handleRef = (next: JSONSchema) => {
while (next.$ref) {
let segments = next.$ref.split('#', 2);
delete next.$ref;
if (segments[0].length > 0) {
openPromises.push(resolveExternalLink(next, segments[0], segments[1], parentSchemaURL));
return;
} else {
merge(next, parentSchema, parentSchemaURL, segments[1]); // can set next.$ref again
}
}
collectEntries(<JSONSchema>next.items, <JSONSchema>next.additionalProperties, next.not, next.contains, next.propertyNames, next.if, next.then, next.else);
collectMapEntries(next.definitions, next.properties, next.patternProperties, <JSONSchemaMap>next.dependencies);
collectArrayEntries(next.anyOf, next.allOf, next.oneOf, <JSONSchema[]>next.items);
};
while (toWalk.length) {
let next = toWalk.pop();
if (seen.indexOf(next) >= 0) {
continue;
}
seen.push(next);
if (next.$ref) {
let segments = next.$ref.split('#', 2);
if (segments[0].length > 0) {
openPromises.push(resolveExternalLink(next, segments[0], segments[1], parentSchemaURL));
continue;
} else {
resolveLink(next, parentSchema, segments[1]);
}
}
collectEntries(next.items, next.additionalProperties, next.not);
collectMapEntries(next.definitions, next.properties, next.patternProperties, <JSONSchemaMap>next.dependencies);
collectArrayEntries(next.anyOf, next.allOf, next.oneOf, <JSONSchema[]>next.items, next.schemaSequence);
handleRef(next);
}
return Promise.all(openPromises);
};
@ -507,32 +487,47 @@ export class JSONSchemaService implements IJSONSchemaService {
return resolveRefs(schema, schema, schemaURL).then(_ => new ResolvedSchema(schema, resolveErrors));
}
public getSchemaForResource(resource: string ): Thenable<ResolvedSchema> {
const resolveSchema = () => {
// check for matching file names, last to first
for (let i = this.filePatternAssociations.length - 1; i >= 0; i--) {
let entry = this.filePatternAssociations[i];
if (entry.matchesPattern(resource)) {
return entry.getCombinedSchema(this).getResolvedSchema();
public getSchemaForResource(resource: string, document?: Parser.JSONDocument): Thenable<ResolvedSchema> {
// first use $schema if present
if (document && document.root && document.root.type === 'object') {
let schemaProperties = document.root.properties.filter(p => (p.keyNode.value === '$schema') && p.valueNode && p.valueNode.type === 'string');
if (schemaProperties.length > 0) {
let schemeId = <string>Parser.getNodeValue(schemaProperties[0].valueNode);
if (schemeId && Strings.startsWith(schemeId, '.') && this.contextService) {
schemeId = this.contextService.resolveRelativePath(schemeId, resource);
}
if (schemeId) {
let id = this.normalizeId(schemeId);
return this.getOrAddSchemaHandle(id).getResolvedSchema();
}
}
return Promise.resolve(null);
};
if (this.customSchemaProvider) {
return this.customSchemaProvider(resource).then(schemaUri => {
return this.loadSchema(schemaUri).then(unsolvedSchema => this.resolveSchemaContent(unsolvedSchema, schemaUri));
}).then(schema => schema, err => {
return resolveSchema();
});
} else {
return resolveSchema();
}
let seen: { [schemaId: string]: boolean } = Object.create(null);
let schemas: string[] = [];
for (let entry of this.filePatternAssociations) {
if (entry.matchesPattern(resource)) {
for (let schemaId of entry.getSchemas()) {
if (!seen[schemaId]) {
schemas.push(schemaId);
seen[schemaId] = true;
}
}
}
}
if (schemas.length > 0) {
return this.createCombinedSchema(resource, schemas).getResolvedSchema();
}
return Promise.resolve(null);
}
public createCombinedSchema(combinedSchemaId: string, schemaIds: string[]): ISchemaHandle {
private createCombinedSchema(resource: string, schemaIds: string[]): ISchemaHandle {
if (schemaIds.length === 1) {
return this.getOrAddSchemaHandle(schemaIds[0]);
} else {
let combinedSchemaId = 'schemaservice://combinedSchema/' + encodeURIComponent(resource);
let combinedSchema: JSONSchema = {
allOf: schemaIds.map(schemaId => ({ $ref: schemaId }))
};

File diff suppressed because it is too large Load diff

View file

@ -8,62 +8,44 @@
import * as Parser from '../parser/jsonParser';
import * as SchemaService from './jsonSchemaService';
import {JSONWorkerContribution} from '../jsonContributions';
import {Thenable} from 'vscode-json-languageservice';
import { JSONWorkerContribution } from '../jsonContributions';
import { Thenable } from 'vscode-json-languageservice';
import {Hover, TextDocument, Position, Range, MarkedString} from 'vscode-languageserver-types';
import { Hover, TextDocument, Position, Range, MarkedString } from 'vscode-languageserver-types';
import { YAMLDocument } from '../yamlLanguageTypes';
import { matchOffsetToDocument } from '../utils/arrUtils';
import { LanguageSettings } from '../yamlLanguageService';
export class YAMLHover {
private schemaService: SchemaService.IJSONSchemaService;
private contributions: JSONWorkerContribution[];
private shouldHover: boolean;
constructor(private schemaService: SchemaService.IJSONSchemaService, private contributions: JSONWorkerContribution[] = []) {
}
constructor(schemaService: SchemaService.IJSONSchemaService, contributions: JSONWorkerContribution[] = []) {
this.schemaService = schemaService;
this.contributions = contributions;
this.shouldHover = true;
}
public doHover(document: TextDocument, position: Position, doc: YAMLDocument): Thenable<Hover> {
public configure(languageSettings: LanguageSettings){
if(languageSettings){
this.shouldHover = languageSettings.hover;
}
}
public doHover(document: TextDocument, position: Position, doc): Thenable<Hover> {
if(!this.shouldHover || !document){
return Promise.resolve(void 0);
}
let offset = document.offsetAt(position);
let offset = document.offsetAt(position);
let currentDoc = matchOffsetToDocument(offset, doc);
if(currentDoc === null){
return Promise.resolve(void 0);
}
const currentDocIndex = doc.documents.indexOf(currentDoc);
let node = currentDoc.getNodeFromOffset(offset);
if (!node || (node.type === 'object' || node.type === 'array') && offset > node.start + 1 && offset < node.end - 1) {
return Promise.resolve(void 0);
if (!node || (node.type === 'object' || node.type === 'array') && offset > node.offset + 1 && offset < node.offset + node.length - 1) {
return Promise.resolve(null);
}
let hoverRangeNode = node;
// use the property description when hovering over an object key
if (node.type === 'string') {
let stringNode = <Parser.StringASTNode>node;
if (stringNode.isKey) {
let propertyNode = <Parser.PropertyASTNode>node.parent;
node = propertyNode.value;
let parent = node.parent;
if (parent && parent.type === 'property' && parent.keyNode === node) {
node = parent.valueNode;
if (!node) {
return Promise.resolve(void 0);
return Promise.resolve(null);
}
}
}
let hoverRange = Range.create(document.positionAt(hoverRangeNode.start), document.positionAt(hoverRangeNode.end));
let hoverRange = Range.create(document.positionAt(hoverRangeNode.offset), document.positionAt(hoverRangeNode.offset + hoverRangeNode.length));
var createHover = (contents: MarkedString[]) => {
let result: Hover = {
@ -73,7 +55,7 @@ export class YAMLHover {
return result;
};
let location = node.getPath();
let location = Parser.getNodePath(node);
for (let i = this.contributions.length - 1; i >= 0; i--) {
let contribution = this.contributions[i];
let promise = contribution.getInfoContribution(document.uri, location);
@ -82,25 +64,21 @@ export class YAMLHover {
}
}
return this.schemaService.getSchemaForResource(document.uri).then((schema) => {
return this.schemaService.getSchemaForResource(document.uri, currentDoc).then((schema) => {
if (schema) {
let newSchema = schema;
if (schema.schema && schema.schema.schemaSequence && schema.schema.schemaSequence[currentDocIndex]) {
newSchema = new SchemaService.ResolvedSchema(schema.schema.schemaSequence[currentDocIndex]);
}
let matchingSchemas = currentDoc.getMatchingSchemas(newSchema.schema, node.start);
let matchingSchemas = currentDoc.getMatchingSchemas(schema.schema, node.offset);
let title: string = null;
let markdownDescription: string = null;
let markdownEnumValueDescription = null, enumValue = null;
matchingSchemas.every((s) => {
matchingSchemas.forEach((s) => {
if (s.node === node && !s.inverted && s.schema) {
title = title || s.schema.title;
markdownDescription = markdownDescription || s.schema["markdownDescription"] || toMarkdown(s.schema.description);
if (s.schema.enum) {
let idx = s.schema.enum.indexOf(node.getValue());
if (s.schema["markdownEnumDescriptions"]) {
markdownEnumValueDescription = s.schema["markdownEnumDescriptions"][idx];
markdownDescription = markdownDescription || s.schema.markdownDescription || toMarkdown(s.schema.description);
if (s.schema.enum) {
let idx = s.schema.enum.indexOf(Parser.getNodeValue(node));
if (s.schema.markdownEnumDescriptions) {
markdownEnumValueDescription = s.schema.markdownEnumDescriptions[idx];
} else if (s.schema.enumDescriptions) {
markdownEnumValueDescription = toMarkdown(s.schema.enumDescriptions[idx]);
}
@ -132,15 +110,15 @@ export class YAMLHover {
}
return createHover([result]);
}
return void 0;
return null;
});
}
}
function toMarkdown(plain: string) {
if (plain) {
let res = plain.replace(/([^\n\r])(\r?\n)([^\n\r])/gm, '$1\n\n$3'); // single new lines to \n\n (Markdown paragraph)
return res.replace(/[\\`*_{}[\]()#+\-.!]/g, "\\$&"); // escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash
}
return void 0;
}
if (plain) {
let res = plain.replace(/([^\n\r])(\r?\n)([^\n\r])/gm, '$1\n\n$3'); // single new lines to \n\n (Markdown paragraph)
return res.replace(/[\\`*_{}[\]()#+\-.!]/g, "\\$&"); // escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash
}
return void 0;
}

View file

@ -6,31 +6,27 @@
'use strict';
import { JSONSchemaService, ResolvedSchema } from './jsonSchemaService';
import { DiagnosticSeverity } from 'vscode-languageserver-types';
import { LanguageSettings} from '../yamlLanguageService';
import { DiagnosticSeverity, TextDocument } from 'vscode-languageserver-types';
import { LanguageSettings } from '../yamlLanguageService';
import { YAMLDocument } from '../yamlLanguageTypes';
export class YAMLValidation {
private jsonSchemaService: JSONSchemaService;
private validationEnabled: boolean;
private validationEnabled: boolean;
public constructor(private jsonSchemaService: JSONSchemaService) {
this.validationEnabled = true;
}
public constructor(jsonSchemaService) {
this.jsonSchemaService = jsonSchemaService;
this.validationEnabled = true;
}
public configure(shouldValidate: LanguageSettings){
if(shouldValidate){
this.validationEnabled = shouldValidate.validate;
public configure(raw: LanguageSettings) {
if (raw) {
this.validationEnabled = raw.validate;
}
}
public doValidation(textDocument, yamlDocument) {
if(!this.validationEnabled){
public doValidation(textDocument: TextDocument, yamlDocument: YAMLDocument) {
if (!this.validationEnabled) {
return Promise.resolve([]);
}
return this.jsonSchemaService.getSchemaForResource(textDocument.uri).then(function (schema) {
var diagnostics = [];
var added = {};
@ -42,10 +38,10 @@ export class YAMLValidation {
if (schema.schema && schema.schema.schemaSequence && schema.schema.schemaSequence[documentIndex]) {
newSchema = new ResolvedSchema(schema.schema.schemaSequence[documentIndex]);
}
let diagnostics = currentDoc.getValidationProblems(newSchema.schema);
let diagnostics = currentDoc.validate(textDocument, newSchema.schema);
for(let diag in diagnostics){
let curDiagnostic = diagnostics[diag];
currentDoc.errors.push({ location: { start: curDiagnostic.location.start, end: curDiagnostic.location.end }, message: curDiagnostic.message })
currentDoc.errors.push({ location: { start: curDiagnostic.range.start, end: curDiagnostic.range.end }, message: curDiagnostic.message })
}
documentIndex++;
}
@ -93,4 +89,4 @@ export class YAMLValidation {
return diagnostics;
});
}
}
}

View file

@ -1,75 +1,71 @@
import { SingleYAMLDocument, YAMLDocument } from '../yamlLanguageTypes';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Red Hat, Inc. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { SingleYAMLDocument } from "../parser/yamlParser";
export function removeDuplicates(arr, prop) {
var new_arr = [];
var lookup = {};
var new_arr = [];
var lookup = {};
for (var i in arr) {
lookup[arr[i][prop]] = arr[i];
}
for (var i in arr) {
lookup[arr[i][prop]] = arr[i];
}
for (i in lookup) {
new_arr.push(lookup[i]);
}
for (i in lookup) {
new_arr.push(lookup[i]);
}
return new_arr;
return new_arr;
}
export function getLineOffsets(textDocString: String): number[] {
let lineOffsets: number[] = [];
let text = textDocString;
let isLineStart = true;
for (let i = 0; i < text.length; i++) {
if (isLineStart) {
lineOffsets.push(i);
isLineStart = false;
}
let ch = text.charAt(i);
isLineStart = (ch === '\r' || ch === '\n');
if (ch === '\r' && i + 1 < text.length && text.charAt(i + 1) === '\n') {
i++;
}
}
if (isLineStart && text.length > 0) {
lineOffsets.push(text.length);
}
return lineOffsets;
let lineOffsets: number[] = [];
let text = textDocString;
let isLineStart = true;
for (let i = 0; i < text.length; i++) {
if (isLineStart) {
lineOffsets.push(i);
isLineStart = false;
}
let ch = text.charAt(i);
isLineStart = (ch === '\r' || ch === '\n');
if (ch === '\r' && i + 1 < text.length && text.charAt(i + 1) === '\n') {
i++;
}
}
if (isLineStart && text.length > 0) {
lineOffsets.push(text.length);
}
return lineOffsets;
}
export function removeDuplicatesObj(objArray){
let nonDuplicateSet = new Set();
let nonDuplicateArr = [];
for(let obj in objArray){
export function removeDuplicatesObj(objArray) {
let currObj = objArray[obj];
let stringifiedObj = JSON.stringify(currObj);
if(!nonDuplicateSet.has(stringifiedObj)){
nonDuplicateArr.push(currObj);
nonDuplicateSet.add(stringifiedObj);
}
let nonDuplicateSet = new Set();
let nonDuplicateArr = [];
for (let obj in objArray) {
}
let currObj = objArray[obj];
let stringifiedObj = JSON.stringify(currObj);
if (!nonDuplicateSet.has(stringifiedObj)) {
nonDuplicateArr.push(currObj);
nonDuplicateSet.add(stringifiedObj);
}
return nonDuplicateArr;
}
return nonDuplicateArr;
}
export function matchOffsetToDocument(offset: number, jsonDocuments): SingleYAMLDocument {
for(let jsonDoc in jsonDocuments.documents){
let currJsonDoc = jsonDocuments.documents[jsonDoc];
if(currJsonDoc.root && currJsonDoc.root.end >= offset && currJsonDoc.root.start <= offset){
return currJsonDoc;
}
}
return null;
}
export function matchOffsetToDocument(offset: number, doc: YAMLDocument): SingleYAMLDocument {
for (let currDoc of doc.documents) {
if (currDoc.root && (currDoc.root.length + currDoc.root.offset) >= offset && currDoc.root.offset <= offset) {
return currDoc;
}
}
return null;
}

View file

@ -0,0 +1,75 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { Color } from "../jsonLanguageTypes";
const Digit0 = 48;
const Digit9 = 57;
const A = 65;
const a = 97;
const f = 102;
export function hexDigit(charCode: number) {
if (charCode < Digit0) {
return 0;
}
if (charCode <= Digit9) {
return charCode - Digit0;
}
if (charCode < a) {
charCode += (a - A);
}
if (charCode >= a && charCode <= f) {
return charCode - a + 10;
}
return 0;
}
export function colorFromHex(text: string): Color {
if (text[0] !== '#') {
return null;
}
switch (text.length) {
case 4:
return {
red: (hexDigit(text.charCodeAt(1)) * 0x11) / 255.0,
green: (hexDigit(text.charCodeAt(2)) * 0x11) / 255.0,
blue: (hexDigit(text.charCodeAt(3)) * 0x11) / 255.0,
alpha: 1
};
case 5:
return {
red: (hexDigit(text.charCodeAt(1)) * 0x11) / 255.0,
green: (hexDigit(text.charCodeAt(2)) * 0x11) / 255.0,
blue: (hexDigit(text.charCodeAt(3)) * 0x11) / 255.0,
alpha: (hexDigit(text.charCodeAt(4)) * 0x11) / 255.0,
};
case 7:
return {
red: (hexDigit(text.charCodeAt(1)) * 0x10 + hexDigit(text.charCodeAt(2))) / 255.0,
green: (hexDigit(text.charCodeAt(3)) * 0x10 + hexDigit(text.charCodeAt(4))) / 255.0,
blue: (hexDigit(text.charCodeAt(5)) * 0x10 + hexDigit(text.charCodeAt(6))) / 255.0,
alpha: 1
};
case 9:
return {
red: (hexDigit(text.charCodeAt(1)) * 0x10 + hexDigit(text.charCodeAt(2))) / 255.0,
green: (hexDigit(text.charCodeAt(3)) * 0x10 + hexDigit(text.charCodeAt(4))) / 255.0,
blue: (hexDigit(text.charCodeAt(5)) * 0x10 + hexDigit(text.charCodeAt(6))) / 255.0,
alpha: (hexDigit(text.charCodeAt(7)) * 0x10 + hexDigit(text.charCodeAt(8))) / 255.0
};
}
return null;
}
export function colorFrom256RGB(red: number, green: number, blue: number, alpha: number = 1.0) {
return {
red: red / 255.0,
green: green / 255.0,
blue: blue / 255.0,
alpha
};
}

View file

@ -0,0 +1,44 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
export function stringifyObject(obj: any, indent: string, stringifyLiteral: (val: any) => string) : string {
if (obj !== null && typeof obj === 'object') {
let newIndent = indent + '\t';
if (Array.isArray(obj)) {
if (obj.length === 0) {
return '[]';
}
let result = '[\n';
for (let i = 0; i < obj.length; i++) {
result += newIndent + stringifyObject(obj[i], newIndent, stringifyLiteral);
if (i < obj.length - 1) {
result += ',';
}
result += '\n';
}
result += indent + ']';
return result;
} else {
let keys = Object.keys(obj);
if (keys.length === 0) {
return '{}';
}
let result = '{\n';
for (let i = 0; i < keys.length; i++) {
let key = keys[i];
result += newIndent + JSON.stringify(key) + ': ' + stringifyObject(obj[key], newIndent, stringifyLiteral);
if (i < keys.length - 1) {
result += ',';
}
result += '\n';
}
result += indent + '}';
return result;
}
}
return stringifyLiteral(obj);
}

View file

@ -55,4 +55,20 @@ export function equals(one: any, other: any): boolean {
}
}
return true;
}
}
export function isNumber(val: any): val is number {
return typeof val === 'number';
}
export function isDefined(val: any): val is object {
return typeof val !== 'undefined';
}
export function isBoolean(val: any): val is boolean {
return typeof val === 'boolean';
}
export function isString(val: any): val is string {
return typeof val === 'string';
}

View file

@ -38,10 +38,14 @@ export function convertSimple2RegExp(pattern: string): RegExp {
: convertGlobalPattern2RegExp(pattern)
}
export function convertSimple2RegExpPattern(pattern: string): string {
return pattern.replace(/[\-\\\{\}\+\?\|\^\$\.\,\[\]\(\)\#\s]/g, '\\$&').replace(/[\*]/g, '.*');
}
function convertGlobalPattern2RegExp(pattern: string): RegExp {
return new RegExp(pattern.replace(/[\-\\\{\}\+\?\|\^\$\.\,\[\]\(\)\#\s]/g, '\\$&').replace(/[\*]/g, '.*') + '$');
}
function convertRegexString2RegExp(pattern: string, flag: string): RegExp {
return new RegExp(pattern, flag);
}
}

View file

@ -5,15 +5,16 @@
*--------------------------------------------------------------------------------------------*/
import { JSONSchemaService, CustomSchemaProvider } from './services/jsonSchemaService'
import { TextDocument, Position, CompletionList, Diagnostic, FormattingOptions } from 'vscode-languageserver-types';
import { TextDocument, Position, CompletionList, Diagnostic, FormattingOptions, DocumentSymbol, CompletionItem, Color, ColorInformation, ColorPresentation, Range } from 'vscode-languageserver-types';
import { JSONSchema } from './jsonSchema';
import { YAMLDocumentSymbols } from './services/documentSymbols';
import { YAMLCompletion } from './services/yamlCompletion';
import { YAMLHover } from './services/yamlHover';
import { YAMLValidation } from './services/yamlValidation';
import { format } from './services/yamlFormatter';
import { JSONDocument, JSONWorkerContribution } from 'vscode-json-languageservice';
import { parse as parseYAML } from "./parser/yamlParser";
import { parse as parseYAML } from './parser/yamlParser';
import { JSONWorkerContribution } from './jsonContributions';
import { YAMLDocument } from './yamlLanguageTypes';
export interface LanguageSettings {
validate?: boolean; //Setting for whether we want to validate the schema
@ -24,54 +25,54 @@ export interface LanguageSettings {
customTags?: Array<String>; //Array of Custom Tags
}
export type YAMLDocument = { documents: JSONDocument[] };
export interface Thenable<R> {
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult>(onfulfilled?: (value: R) => TResult | Thenable<TResult>, onrejected?: (reason: any) => TResult | Thenable<TResult>): Thenable<TResult>;
then<TResult>(onfulfilled?: (value: R) => TResult | Thenable<TResult>, onrejected?: (reason: any) => void): Thenable<TResult>;
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult>(onfulfilled?: (value: R) => TResult | Thenable<TResult>, onrejected?: (reason: any) => TResult | Thenable<TResult>): Thenable<TResult>;
then<TResult>(onfulfilled?: (value: R) => TResult | Thenable<TResult>, onrejected?: (reason: any) => void): Thenable<TResult>;
}
export interface WorkspaceContextService {
resolveRelativePath(relativePath: string, resource: string): string;
resolveRelativePath(relativePath: string, resource: string): string;
}
/**
* The schema request service is used to fetch schemas. The result should the schema file comment, or,
* in case of an error, a displayable error string
*/
export interface SchemaRequestService {
(uri: string): Thenable<string>;
(uri: string): Thenable<string>;
}
export interface SchemaConfiguration {
/**
* The URI of the schema, which is also the identifier of the schema.
*/
uri: string;
uri: string;
/**
* A list of file names that are associated to the schema. The '*' wildcard can be used. For example '*.schema.json', 'package.json'
*/
fileMatch?: string[];
fileMatch?: string[];
/**
* The schema for the given URI.
* If no schema is provided, the schema will be fetched with the schema request service (if available).
*/
schema?: JSONSchema;
schema?: JSONSchema;
}
export interface LanguageService {
configure(settings: LanguageSettings): void;
registerCustomSchemaProvider(schemaProvider: CustomSchemaProvider): void; // Register a custom schema provider
doComplete(document: TextDocument, position: Position, doc): Thenable<CompletionList>;
doValidation(document: TextDocument, yamlDocument): Thenable<Diagnostic[]>;
doHover(document: TextDocument, position: Position, doc);
findDocumentSymbols(document: TextDocument, doc);
doResolve(completionItem);
doComplete(document: TextDocument, position: Position, doc: YAMLDocument): Thenable<CompletionList>;
doValidation(document: TextDocument, yamlDocument: YAMLDocument): Thenable<Diagnostic[]>;
doHover(document: TextDocument, position: Position, doc: YAMLDocument);
findDocumentSymbols(document: TextDocument, doc: YAMLDocument): DocumentSymbol[];
findDocumentColors(document: TextDocument, doc: YAMLDocument): Thenable<ColorInformation[]>;
getColorPresentations(document: TextDocument, doc: YAMLDocument, color: Color, range: Range): ColorPresentation[];
doResolve(completionItem: CompletionItem): Thenable<CompletionItem>;
resetSchema(uri: string): boolean;
doFormat(document: TextDocument, options: FormattingOptions, customTags: Array<String>);
parseYAMLDocument(document: TextDocument): YAMLDocument;
@ -82,32 +83,30 @@ export function getLanguageService(schemaRequestService: SchemaRequestService, w
let completer = new YAMLCompletion(schemaService, contributions);
let hover = new YAMLHover(schemaService, contributions);
let yamlDocumentSymbols = new YAMLDocumentSymbols();
let yamlDocumentSymbols = new YAMLDocumentSymbols(schemaService);
let yamlValidation = new YAMLValidation(schemaService);
return {
configure: (settings) => {
schemaService.clearExternalSchemas();
if (settings.schemas) {
settings.schemas.forEach(settings => {
schemaService.registerExternalSchema(settings.uri, settings.fileMatch, settings.schema);
});
}
yamlValidation.configure(settings);
hover.configure(settings);
let customTagsSetting = settings && settings['customTags'] ? settings['customTags'] : [];
completer.configure(settings, customTagsSetting);
},
registerCustomSchemaProvider: (schemaProvider: CustomSchemaProvider) => {
schemaService.registerCustomSchemaProvider(schemaProvider);
},
doComplete: completer.doComplete.bind(completer),
doResolve: completer.doResolve.bind(completer),
doValidation: yamlValidation.doValidation.bind(yamlValidation),
doHover: hover.doHover.bind(hover),
findDocumentSymbols: yamlDocumentSymbols.findDocumentSymbols.bind(yamlDocumentSymbols),
resetSchema: (uri: string) => schemaService.onResourceChange(uri),
doFormat: format,
parseYAMLDocument: (document: TextDocument) => parseYAML(document.getText()),
configure: (settings) => {
schemaService.clearExternalSchemas();
if (settings.schemas) {
settings.schemas.forEach(settings => {
schemaService.registerExternalSchema(settings.uri, settings.fileMatch, settings.schema);
});
}
},
registerCustomSchemaProvider: (schemaProvider: CustomSchemaProvider) => {
schemaService.registerCustomSchemaProvider(schemaProvider);
},
doComplete: completer.doComplete.bind(completer),
doResolve: completer.doResolve.bind(completer),
doValidation: yamlValidation.doValidation.bind(yamlValidation),
doHover: hover.doHover.bind(hover),
findDocumentSymbols: yamlDocumentSymbols.findDocumentSymbols.bind(yamlDocumentSymbols),
findDocumentColors: yamlDocumentSymbols.findDocumentColors.bind(yamlDocumentSymbols),
getColorPresentations: yamlDocumentSymbols.getColorPresentations.bind(yamlDocumentSymbols),
resetSchema: (uri: string) => schemaService.onResourceChange(uri),
doFormat: format,
parseYAMLDocument: (document: TextDocument) => parseYAML(document.getText()),
}
}

View file

@ -0,0 +1,37 @@
import { JSONDocument } from './parser/jsonParser';
import { ASTNode } from './jsonLanguageTypes';
export class SingleYAMLDocument extends JSONDocument {
public lines;
public errors;
public warnings;
constructor(lines: number[]) {
super(null, []);
this.lines = lines;
this.errors = [];
this.warnings = [];
}
public getSchemas(schema, doc, node) {
let matchingSchemas = [];
doc.validate(schema, matchingSchemas, node.start);
return matchingSchemas;
}
public getNodeFromOffset(offset: number, includeRightBound = false): ASTNode {
return super.getNodeFromOffset(offset, includeRightBound);
}
}
export class YAMLDocument {
public documents: SingleYAMLDocument[]
public errors;
public warnings;
constructor(documents: SingleYAMLDocument[]) {
this.documents = documents;
this.errors = [];
this.warnings = [];
}
}

View file

@ -26,13 +26,14 @@ export function setupMode(defaults: LanguageServiceDefaultsImpl): void {
let languageId = defaults.languageId;
disposables.push(monaco.languages.registerCompletionItemProvider(languageId, new languageFeatures.CompletionAdapter(worker)));
// TODO:
// disposables.push(monaco.languages.registerCompletionItemProvider(languageId, new languageFeatures.CompletionAdapter(worker)));
disposables.push(monaco.languages.registerHoverProvider(languageId, new languageFeatures.HoverAdapter(worker)));
disposables.push(monaco.languages.registerDocumentSymbolProvider(languageId, new languageFeatures.DocumentSymbolAdapter(worker)));
disposables.push(monaco.languages.registerDocumentSymbolProvider(languageId, new languageFeatures.DocumentSymbolAdapter(worker)));
disposables.push(monaco.languages.registerColorProvider(languageId, new languageFeatures.DocumentColorAdapter(worker)));
disposables.push(monaco.languages.registerDocumentFormattingEditProvider(languageId, new languageFeatures.DocumentFormattingEditProvider(worker)));
disposables.push(monaco.languages.registerDocumentRangeFormattingEditProvider(languageId, new languageFeatures.DocumentRangeFormattingEditProvider(worker)));
disposables.push(new languageFeatures.DiagnosticsAdapter(languageId, worker, defaults));
// disposables.push(monaco.languages.setTokensProvider(languageId, createTokenizationSupport(true)));
disposables.push(monaco.languages.setLanguageConfiguration(languageId, richEditConfiguration));
}

View file

@ -63,11 +63,23 @@ export class YAMLWorker {
resetSchema(uri: string): Thenable<boolean> {
return Promise.as(this._languageService.resetSchema(uri));
}
findDocumentSymbols(uri: string): Thenable<ls.SymbolInformation[]> {
findDocumentSymbols(uri: string): Thenable<ls.DocumentSymbol[]> {
let document = this._getTextDocument(uri);
let yamlDocument = this._languageService.parseYAMLDocument(document);
let symbols = this._languageService.findDocumentSymbols(document, yamlDocument);
return Promise.as(symbols);
}
findDocumentColors(uri: string): Thenable<ls.ColorInformation[]> {
let document = this._getTextDocument(uri);
let stylesheet = this._languageService.parseYAMLDocument(document);
let colorSymbols = this._languageService.findDocumentColors(document, stylesheet);
return Promise.as(colorSymbols);
}
getColorPresentations(uri: string, color: ls.Color, range: ls.Range): Thenable<ls.ColorPresentation[]> {
let document = this._getTextDocument(uri);
let stylesheet = this._languageService.parseYAMLDocument(document);
let colorPresentations = this._languageService.getColorPresentations(document, stylesheet, color, range);
return Promise.as(colorPresentations);
}
private _getTextDocument(uri: string): ls.TextDocument {
let models = this._ctx.getMirrorModels();
@ -88,4 +100,4 @@ export interface ICreateData {
export function create(ctx: IWorkerContext, createData: ICreateData): YAMLWorker {
return new YAMLWorker(ctx, createData);
}
}

View file

@ -1,90 +1,90 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible"
content="IE=edge" />
<meta http-equiv="Content-Type"
content="text/html;charset=utf-8" />
<link rel="stylesheet"
data-name="vs/editor/editor.main"
href="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.css">
</head>
<body>
<h2>Monaco Editor YAML test page</h2>
<code id="path"></code>
<div id="container"
style="width:800px;height:600px;border:1px solid grey"></div>
<script>
// Loading basic-languages to get the YAML language definition
var paths = {
'vs/basic-languages': '../node_modules/monaco-languages/release/dev',
'vs/language/yaml': '../release/dev',
'vs': '../node_modules/monaco-editor-core/dev/vs'
}
if (document.location.protocol === 'http:') {
// Add support for running local http server
let testIndex = document.location.pathname.indexOf('/test/');
if (testIndex !== -1) {
let prefix = document.location.pathname.substr(0, testIndex);
paths['vs/language/yaml'] = prefix + '/release/dev';
}
}
var require = {
paths: paths
};
</script>
<script src="../node_modules/monaco-editor-core/dev/vs/loader.js"></script>
<script src="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.nls.js"></script>
<script src="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.js"></script>
<script>
require([
'vs/basic-languages/monaco.contribution',
'vs/language/yaml/monaco.contribution'
], function () {
const yaml = `apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: default
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
apps.deployment: nginx
template:
metadata:
labels:
apps.deployment: nginx
spec:
containers:
- name: nginx
image: nginx:alpine`;
var editor = monaco.editor.create(document.getElementById('container'), {
value: yaml,
language: 'yaml'
});
monaco.languages.yaml.yamlDefaults.setDiagnosticsOptions({
enableSchemaRequest: true,
validate: true,
schemas: [
{
uri: 'https://raw.githubusercontent.com/garethr/kubernetes-json-schema/master/master/deployment.json',
fileMatch: ['*'],
},
],
});
});
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible"
content="IE=edge" />
<meta http-equiv="Content-Type"
content="text/html;charset=utf-8" />
<link rel="stylesheet"
data-name="vs/editor/editor.main"
href="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.css">
</head>
<body>
<h2>Monaco Editor YAML test page</h2>
<code id="path"></code>
<div id="container"
style="width:800px;height:600px;border:1px solid grey"></div>
<script>
// Loading basic-languages to get the YAML language definition
var paths = {
'vs/basic-languages': '../node_modules/monaco-languages/release/dev',
'vs/language/yaml': '../release/dev',
'vs': '../node_modules/monaco-editor-core/dev/vs'
}
if (document.location.protocol === 'http:') {
// Add support for running local http server
let testIndex = document.location.pathname.indexOf('/test/');
if (testIndex !== -1) {
let prefix = document.location.pathname.substr(0, testIndex);
paths['vs/language/yaml'] = prefix + '/release/dev';
}
}
var require = {
paths: paths
};
</script>
<script src="../node_modules/monaco-editor-core/dev/vs/loader.js"></script>
<script src="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.nls.js"></script>
<script src="../node_modules/monaco-editor-core/dev/vs/editor/editor.main.js"></script>
<script>
require([
'vs/basic-languages/monaco.contribution',
'vs/language/yaml/monaco.contribution'
], function () {
const yaml = `apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: default
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
apps.deployment: nginx
template:
metadata:
labels:
apps.deployment: nginx
spec:
containers:
- name: nginx
image: nginx:alpine`;
var editor = monaco.editor.create(document.getElementById('container'), {
value: yaml,
language: 'yaml'
});
monaco.languages.yaml.yamlDefaults.setDiagnosticsOptions({
enableSchemaRequest: true,
validate: true,
schemas: [
{
uri: 'https://raw.githubusercontent.com/garethr/kubernetes-json-schema/master/master/deployment.json',
fileMatch: ['*'],
},
],
});
});
</script>
</body>
</html>

159
yarn.lock
View file

@ -14,6 +14,13 @@
version "10.9.3"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.9.3.tgz#85f288502503ade0b3bfc049fe1777b05d0327d5"
agent-base@4, agent-base@^4.1.0:
version "4.2.1"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9"
integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==
dependencies:
es6-promisify "^5.0.0"
argparse@^1.0.7:
version "1.0.10"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
@ -39,6 +46,32 @@ concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
debug@3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
dependencies:
ms "2.0.0"
debug@^3.1.0:
version "3.2.6"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
dependencies:
ms "^2.1.1"
es6-promise@^4.0.3:
version "4.2.5"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.5.tgz#da6d0d5692efb461e082c14817fe2427d8f5d054"
integrity sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==
es6-promisify@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=
dependencies:
es6-promise "^4.0.3"
esprima@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
@ -58,6 +91,22 @@ glob@^7.0.5:
once "^1.3.0"
path-is-absolute "^1.0.0"
http-proxy-agent@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405"
integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==
dependencies:
agent-base "4"
debug "3.1.0"
https-proxy-agent@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0"
integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==
dependencies:
agent-base "^4.1.0"
debug "^3.1.0"
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
@ -76,7 +125,12 @@ js-yaml@^3.12.0:
argparse "^1.0.7"
esprima "^4.0.0"
jsonc-parser@^2.0.1, jsonc-parser@^2.0.2:
jsonc-parser@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-1.0.3.tgz#1d53d7160e401a783dbceabaad82473f80e6ad7e"
integrity sha512-hk/69oAeaIzchq/v3lS50PXuzn5O2ynldopMC+SWBql7J2WtdptfB9dy8Y7+Og5rPkTCpn83zTiO8FMcqlXJ/g==
jsonc-parser@^2.0.0-next.1, jsonc-parser@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.0.2.tgz#42fcf56d70852a043fadafde51ddb4a85649978d"
@ -102,6 +156,16 @@ monaco-plugin-helpers@^1.0.2:
dependencies:
typescript "^2.7.2"
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
ms@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
once@^1.3.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
@ -112,6 +176,20 @@ path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
prettier@^1.14.3:
version "1.15.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.15.2.tgz#d31abe22afa4351efa14c7f8b94b58bb7452205e"
integrity sha512-YgPLFFA0CdKL4Eg2IHtUSjzj/BWgszDHiNQAe0VAIBse34148whfdzLagRL+QiKS+YfK5ftB6X4v/MBw8yCoug==
request-light@^0.2.3:
version "0.2.4"
resolved "https://registry.yarnpkg.com/request-light/-/request-light-0.2.4.tgz#3cea29c126682e6bcadf7915353322eeba01a755"
integrity sha512-pM9Fq5jRnSb+82V7M97rp8FE9/YNeP2L9eckB4Szd7lyeclSIx02aIpPO/6e4m6Dy31+FBN/zkFMTd2HkNO3ow==
dependencies:
http-proxy-agent "^2.1.0"
https-proxy-agent "^2.2.1"
vscode-nls "^4.0.0"
requirejs@^2.3.5:
version "2.3.6"
resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.6.tgz#e5093d9601c2829251258c0b9445d4d19fa9e7c9"
@ -146,27 +224,86 @@ uglify-es@^3.3.9:
commander "~2.13.0"
source-map "~0.6.1"
vscode-json-languageservice@^3.1.6:
version "3.1.6"
resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.1.6.tgz#272e21eb9abcefe6c1ed38be141f0a76d5ddf0cd"
vscode-json-languageservice@3.0.12:
version "3.0.12"
resolved "https://registry.yarnpkg.com/vscode-json-languageservice/-/vscode-json-languageservice-3.0.12.tgz#85258632f2f7718028fbdfbb95b4ad009107b821"
integrity sha512-XSgRVY/vsPqOa//ZwLD5DWx1wzTQGgeZfsOlVqFlLya10dpimSnd27kbuL45hzxh4B+MvmHZtZeWQKjSYnNF0A==
dependencies:
jsonc-parser "^2.0.1"
vscode-languageserver-types "^3.12.0"
vscode-nls "^3.2.4"
vscode-uri "^1.0.6"
jsonc-parser "^2.0.0-next.1"
vscode-languageserver-types "^3.6.1"
vscode-nls "^3.2.1"
vscode-uri "^1.0.3"
vscode-languageserver-types@3.12.0, vscode-languageserver-types@^3.12.0:
vscode-jsonrpc@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz#a7bf74ef3254d0a0c272fab15c82128e378b3be9"
integrity sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg==
vscode-languageserver-protocol@^3.10.3:
version "3.13.0"
resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.13.0.tgz#710d8e42119bb3affb1416e1e104bd6b4d503595"
integrity sha512-2ZGKwI+P2ovQll2PGAp+2UfJH+FK9eait86VBUdkPd9HRlm8e58aYT9pV/NYanHOcp3pL6x2yTLVCFMcTer0mg==
dependencies:
vscode-jsonrpc "^4.0.0"
vscode-languageserver-types "3.13.0"
vscode-languageserver-types@3.12.0:
version "3.12.0"
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.12.0.tgz#f96051381b6a050b7175b37d6cb5d2f2eb64b944"
integrity sha512-UxqnpzBToPO7Mi2tr/s5JeyPOSKSJtLB8lIdxCg9ZNdvP2cU8wS7iTDtwQKz91Ne4CUmTdf85ddR5SIZKXmMjQ==
vscode-nls@^3.2.4:
vscode-languageserver-types@3.13.0, vscode-languageserver-types@^3.6.1:
version "3.13.0"
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.13.0.tgz#b704b024cef059f7b326611c99b9c8753c0a18b4"
integrity sha512-BnJIxS+5+8UWiNKCP7W3g9FlE7fErFw0ofP5BXJe7c2tl0VeWh+nNHFbwAS2vmVC4a5kYxHBjRy0UeOtziemVA==
vscode-languageserver@^4.0.0:
version "4.4.2"
resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-4.4.2.tgz#600ae9cc7a6ff1e84d93c7807840c2cb5b22821b"
integrity sha512-61y8Raevi9EigDgg9NelvT9cUAohiEbUl1LOwQQgOCAaNX62yKny/ddi0uC+FUTm4CzsjhBu+06R+vYgfCYReA==
dependencies:
vscode-languageserver-protocol "^3.10.3"
vscode-uri "^1.0.5"
vscode-nls@^3.2.1, vscode-nls@^3.2.2:
version "3.2.5"
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-3.2.5.tgz#25520c1955108036dec607c85e00a522f247f1a4"
vscode-uri@^1.0.6:
vscode-nls@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002"
integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw==
vscode-uri@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.3.tgz#631bdbf716dccab0e65291a8dc25c23232085a52"
integrity sha1-Yxvb9xbcyrDmUpGo3CXCMjIIWlI=
vscode-uri@^1.0.3, vscode-uri@^1.0.5:
version "1.0.6"
resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.6.tgz#6b8f141b0bbc44ad7b07e94f82f168ac7608ad4d"
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
yaml-ast-parser@0.0.40:
version "0.0.40"
resolved "https://registry.yarnpkg.com/yaml-ast-parser/-/yaml-ast-parser-0.0.40.tgz#08536d4e73d322b1c9ce207ab8dd70e04d20ae6e"
integrity sha1-CFNtTnPTIrHJziB6uN1w4E0grm4=
yaml-language-server@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yaml-language-server/-/yaml-language-server-0.1.0.tgz#ab3aff5c601ae33e03dc08c0960fd7c70296e635"
integrity sha512-2sA9eMgBnvEnjcQVIxbakIkiL8PQ6xJw1yXfdiVRn8ms+dI3EuaaatoUuIPhYnwmDOeaobDwkJs1bpQvFO4nqQ==
dependencies:
js-yaml "^3.12.0"
jsonc-parser "^1.0.3"
prettier "^1.14.3"
request-light "^0.2.3"
vscode-json-languageservice "3.0.12"
vscode-languageserver "^4.0.0"
vscode-languageserver-types "^3.6.1"
vscode-nls "^3.2.2"
vscode-uri "1.0.3"
yaml-ast-parser "0.0.40"