Skip to content

Commit

Permalink
Hover working with tests and removal of schemaSequence property
Browse files Browse the repository at this point in the history
  • Loading branch information
JPinkney committed May 26, 2019
1 parent 29e6a21 commit 1beb482
Show file tree
Hide file tree
Showing 14 changed files with 97 additions and 148 deletions.
2 changes: 0 additions & 2 deletions src/languageservice/jsonSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ export interface JSONSchema {
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
"x-kubernetes-group-version-kind"?; //Kubernetes extension
}

export interface JSONSchemaMap {
Expand Down
2 changes: 1 addition & 1 deletion src/languageservice/parser/yamlParser2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ function recursivelyBuildAst(parent: ASTNode, node: Yaml.YAMLNode): ASTNode {

// Technically, this is an arbitrary node in YAML
// I doubt we would get a better string representation by parsing it
const keyNode = new StringASTNodeImpl(null, key.startPosition, key.endPosition - key.startPosition);
const keyNode = new StringASTNodeImpl(result, key.startPosition, key.endPosition - key.startPosition);
keyNode.value = key.value;

const valueNode = (instance.value) ? recursivelyBuildAst(result, instance.value) : new NullASTNodeImpl(parent, instance.endPosition, 0)
Expand Down
2 changes: 1 addition & 1 deletion src/languageservice/services/jsonSchemaService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,7 @@ export class JSONSchemaService implements IJSONSchemaService {
}
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);
collectArrayEntries(next.anyOf, next.allOf, next.oneOf, <JSONSchema[]>next.items);
}
return this.promise.all(openPromises);
};
Expand Down
3 changes: 0 additions & 3 deletions src/languageservice/services/yamlCompletion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,6 @@ export class YAMLCompletion {
return Promise.resolve(result);
}
let newSchema = schema;
if (schema.schema && schema.schema.schemaSequence && schema.schema.schemaSequence[currentDocIndex]) {
newSchema = new SchemaService.ResolvedSchema(schema.schema.schemaSequence[currentDocIndex]);
}

let collectionPromises: Thenable<any>[] = [];

Expand Down
110 changes: 7 additions & 103 deletions src/languageservice/services/yamlHover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
'use strict';


import * as Parser from '../parser/jsonParser';
import * as Parser from '../parser/jsonParser2';
import * as SchemaService from './jsonSchemaService';
import {JSONWorkerContribution} from '../jsonContributions';
import {PromiseConstructor, Thenable} from 'vscode-json-languageservice';
import {PromiseConstructor, Thenable, LanguageService} from 'vscode-json-languageservice';

import {Hover, TextDocument, Position, Range, MarkedString} from 'vscode-languageserver-types';
import { matchOffsetToDocument } from '../utils/arrUtils';
import { matchOffsetToDocument2 } from '../utils/arrUtils';
import { LanguageSettings } from '../yamlLanguageService';

export class YAMLHover {
Expand All @@ -35,114 +35,18 @@ export class YAMLHover {
}
}

public doHover(document: TextDocument, position: Position, doc): Thenable<Hover> {
public doHover(jsonLanguageService: LanguageService, document: TextDocument, position: Position, doc): Thenable<Hover> {

if(!this.shouldHover || !document){
return this.promise.resolve(void 0);
}

let offset = document.offsetAt(position);
let currentDoc = matchOffsetToDocument(offset, doc);
let currentDoc = matchOffsetToDocument2(offset, doc);
if(currentDoc === null){
return this.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 this.promise.resolve(void 0);
}
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;
if (!node) {
return this.promise.resolve(void 0);
}
}
}

let hoverRange = Range.create(document.positionAt(hoverRangeNode.start), document.positionAt(hoverRangeNode.end));

var createHover = (contents: MarkedString[]) => {
let result: Hover = {
contents: contents,
range: hoverRange
};
return result;
};

let location = node.getPath();
for (let i = this.contributions.length - 1; i >= 0; i--) {
let contribution = this.contributions[i];
let promise = contribution.getInfoContribution(document.uri, location);
if (promise) {
return promise.then(htmlContent => createHover(htmlContent));
}
}

return this.schemaService.getSchemaForResource(document.uri).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 title: string = null;
let markdownDescription: string = null;
let markdownEnumValueDescription = null, enumValue = null;
matchingSchemas.every((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];
} else if (s.schema.enumDescriptions) {
markdownEnumValueDescription = toMarkdown(s.schema.enumDescriptions[idx]);
}
if (markdownEnumValueDescription) {
enumValue = s.schema.enum[idx];
if (typeof enumValue !== 'string') {
enumValue = JSON.stringify(enumValue);
}
}
}
}
return true;
});
let result = '';
if (title) {
result = toMarkdown(title);
}
if (markdownDescription) {
if (result.length > 0) {
result += "\n\n";
}
result += markdownDescription;
}
if (markdownEnumValueDescription) {
if (result.length > 0) {
result += "\n\n";
}
result += `\`${toMarkdown(enumValue)}\`: ${markdownEnumValueDescription}`;
}
return createHover([result]);
}
return void 0;
});

return jsonLanguageService.doHover(document, position, currentDoc);
}
}

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;
}
3 changes: 0 additions & 3 deletions src/languageservice/services/yamlValidation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@ export class YAMLValidation {
let documentIndex = 0;
for(let currentYAMLDoc in yamlDocument.documents){
let currentDoc = yamlDocument.documents[currentYAMLDoc];
if (schema.schema && schema.schema.schemaSequence && schema.schema.schemaSequence[documentIndex]) {
newSchema = new ResolvedSchema(schema.schema.schemaSequence[documentIndex]);
}
let diagnostics = currentDoc.getValidationProblems(newSchema.schema);
for(let diag in diagnostics){
let curDiagnostic = diagnostics[diag];
Expand Down
20 changes: 17 additions & 3 deletions src/languageservice/utils/arrUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,19 +61,33 @@ export function removeDuplicatesObj(objArray){

}

export function matchOffsetToDocument(offset: number, jsonDocuments): SingleYAMLDocument {
export function matchOffsetToDocument(offset: number, jsonDocuments) {

for(let jsonDoc in jsonDocuments.documents){
let currJsonDoc = jsonDocuments.documents[jsonDoc];
let currJsonDoc: SingleYAMLDocument = jsonDocuments.documents[jsonDoc];
if(currJsonDoc.root && currJsonDoc.root.end >= offset && currJsonDoc.root.start <= offset){
return currJsonDoc;
}
}

return null;
// TODO: Fix this so that it returns the correct document
return jsonDocuments.documents[0];
}

export function matchOffsetToDocument2(offset: number, jsonDocuments) {

for(let jsonDoc of jsonDocuments.documents){
if(jsonDoc.root && jsonDoc.root.offset <= offset && (jsonDoc.root.length + jsonDoc.root.offset) >= offset){
return jsonDoc;
}
}

// TODO: Fix this so that it returns the correct document
return null;
}



export function filterInvalidCustomTags(customTags: String[]): String[] {
const validCustomTags = ['mapping', 'scalar', 'sequence'];

Expand Down
2 changes: 1 addition & 1 deletion src/languageservice/yamlLanguageService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export interface LanguageService {
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);
doHover(jsonLanguageService: JSONLanguageService, document: TextDocument, position: Position, doc);
findDocumentSymbols(jsonLanguageService: JSONLanguageService, document: TextDocument, doc);
doResolve(completionItem);
resetSchema(uri: string): boolean;
Expand Down
40 changes: 25 additions & 15 deletions src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ import { getLanguageService as getCustomLanguageService, LanguageSettings, Custo
import * as nls from 'vscode-nls';
import { FilePatternAssociation, CustomSchemaProvider } from './languageservice/services/jsonSchemaService';
import { parse as parseYAML } from './languageservice/parser/yamlParser';
import { parse as parseYAML2 } from './languageservice/parser/yamlParser2';
import { JSONDocument } from './languageservice/parser/jsonParser';
import { JSONSchema } from './languageservice/jsonSchema';
import { createJSONLanguageService } from '../test/testHelper';
import { getLanguageService as getJSONLanguageService } from 'vscode-json-languageservice';
nls.config(<any>process.env['VSCODE_NLS_CONFIG']);

interface ISchemaAssociations {
Expand Down Expand Up @@ -164,6 +165,10 @@ let schemaRequestService = (uri: string): Thenable<string> => {
export let KUBERNETES_SCHEMA_URL = "https://gist.githubusercontent.com/JPinkney/ccaf3909ef811e5657ca2e2e1fa05d76/raw/f85e51bfb67fdb99ab7653c2953b60087cc871ea/openshift_schema_all.json";
export let KEDGE_SCHEMA_URL = "https://raw.githubusercontent.com/kedgeproject/json-schema/master/master/kedge-json-schema.json";
export let customLanguageService = getCustomLanguageService(schemaRequestService, workspaceContext, []);
export let jsonLanguageService = getJSONLanguageService({
schemaRequestService,
workspaceContext
});

// The settings interface describes the server relevant settings part
interface Settings {
Expand Down Expand Up @@ -356,6 +361,12 @@ function updateConfiguration() {
}
languageSettings = configureSchemas(uri, schema.fileMatch, schema.schema, languageSettings);
}
jsonLanguageService.configure({
schemas: [{
fileMatch: ['*.yaml', '*.yml'],
uri: 'https://gist.githubusercontent.com/JPinkney/db62cf5f52780f62c1e303f08ecb5a19/raw/3ab2a4739e2c955eae3b0977c76cc0fd65dc977b/test.json'
}]
})
});
}
if(schemaStoreSettings){
Expand Down Expand Up @@ -393,13 +404,13 @@ function configureSchemas(uri, fileMatch, schema, languageSettings){
return languageSettings;
}

function setKubernetesParserOption(jsonDocuments: JSONDocument[], option: boolean){
for(let jsonDoc in jsonDocuments){
jsonDocuments[jsonDoc].configureSettings({
isKubernetes: option
});
}
}
// function setKubernetesParserOption(jsonDocuments: JSONDocument[], option: boolean){
// for(let jsonDoc in jsonDocuments){
// jsonDocuments[jsonDoc].configureSettings({
// isKubernetes: option
// });
// }
// }

function isKubernetes(textDocument){
for(let path in specificValidatorPaths){
Expand Down Expand Up @@ -452,7 +463,7 @@ function validateTextDocument(textDocument: TextDocument): void {
}

let yamlDocument = parseYAML(textDocument.getText(), customTags);
isKubernetes(textDocument) ? setKubernetesParserOption(yamlDocument.documents, true) : setKubernetesParserOption(yamlDocument.documents, false);
// isKubernetes(textDocument) ? setKubernetesParserOption(yamlDocument.documents, true) : setKubernetesParserOption(yamlDocument.documents, false);
customLanguageService.doValidation(textDocument, yamlDocument).then(function(diagnosticResults){

let diagnostics = [];
Expand Down Expand Up @@ -493,7 +504,7 @@ connection.onCompletion(textDocumentPosition => {
let completionFix = completionHelper(textDocument, textDocumentPosition.position);
let newText = completionFix.newText;
let jsonDocument = parseYAML(newText);
isKubernetes(textDocument) ? setKubernetesParserOption(jsonDocument.documents, true) : setKubernetesParserOption(jsonDocument.documents, false);
// isKubernetes(textDocument) ? setKubernetesParserOption(jsonDocument.documents, true) : setKubernetesParserOption(jsonDocument.documents, false);
return customLanguageService.doComplete(textDocument, textDocumentPosition.position, jsonDocument);
});

Expand Down Expand Up @@ -567,9 +578,9 @@ connection.onHover(textDocumentPositionParams => {
return Promise.resolve(void 0);
}

let jsonDocument = parseYAML(document.getText());
isKubernetes(document) ? setKubernetesParserOption(jsonDocument.documents, true) : setKubernetesParserOption(jsonDocument.documents, false);
return customLanguageService.doHover(document, textDocumentPositionParams.position, jsonDocument);
let jsonDocument = parseYAML2(document.getText());
// isKubernetes(document) ? setKubernetesParserOption(jsonDocument.documents, true) : setKubernetesParserOption(jsonDocument.documents, false);
return customLanguageService.doHover(jsonLanguageService, document, textDocumentPositionParams.position, jsonDocument);
});

connection.onDocumentSymbol(documentSymbolParams => {
Expand All @@ -579,8 +590,7 @@ connection.onDocumentSymbol(documentSymbolParams => {
return;
}

let jsonDocument = parseYAML(document.getText());
const jsonLanguageService = createJSONLanguageService();
let jsonDocument = parseYAML2(document.getText());
return customLanguageService.findDocumentSymbols(jsonLanguageService, document, jsonDocument);
});

Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/customMultipleSchemaSequences.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"schemaSequence": [
"oneOf": [
{
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Person object",
Expand Down
15 changes: 11 additions & 4 deletions test/hover.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import URI from '../src/languageservice/utils/uri';
import * as URL from 'url';
import fs = require('fs');
import {JSONSchemaService} from '../src/languageservice/services/jsonSchemaService'
import {schemaRequestService, workspaceContext} from './testHelper';
import { parse as parseYAML } from '../src/languageservice/parser/yamlParser';
import {schemaRequestService, workspaceContext, createJSONLanguageService} from './testHelper';
import { parse as parseYAML } from '../src/languageservice/parser/yamlParser2';
import { getLineOffsets } from "../src/languageservice/utils/arrUtils";
var assert = require('assert');

Expand Down Expand Up @@ -47,8 +47,15 @@ suite("Hover Tests", () => {

function parseSetup(content: string, position){
let testTextDocument = setup(content);
let jsonDocument = parseYAML(testTextDocument.getText());
return languageService.doHover(testTextDocument, testTextDocument.positionAt(position), jsonDocument);
let jsonDocument = parseYAML(testTextDocument.getText());
const jsonLanguageService = createJSONLanguageService();
jsonLanguageService.configure({
schemas: [{
fileMatch,
uri
}]
});
return languageService.doHover(jsonLanguageService, testTextDocument, testTextDocument.positionAt(position), jsonDocument);
}

it('Hover on key on root', (done) => {
Expand Down
15 changes: 11 additions & 4 deletions test/hover2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import URI from '../src/languageservice/utils/uri';
import * as URL from 'url';
import fs = require('fs');
import {JSONSchemaService} from '../src/languageservice/services/jsonSchemaService'
import {schemaRequestService, workspaceContext} from './testHelper';
import { parse as parseYAML } from '../src/languageservice/parser/yamlParser';
import {schemaRequestService, workspaceContext, createJSONLanguageService} from './testHelper';
import { parse as parseYAML } from '../src/languageservice/parser/yamlParser2';
import { getLineOffsets } from "../src/languageservice/utils/arrUtils";
var assert = require('assert');

Expand Down Expand Up @@ -47,8 +47,15 @@ suite("Hover Tests", () => {

function parseSetup(content: string, position){
let testTextDocument = setup(content);
let jsonDocument = parseYAML(testTextDocument.getText());
return languageService.doHover(testTextDocument, testTextDocument.positionAt(position), jsonDocument);
let jsonDocument = parseYAML(testTextDocument.getText());
const jsonLanguageService = createJSONLanguageService();
jsonLanguageService.configure({
schemas: [{
fileMatch,
uri
}]
})
return languageService.doHover(jsonLanguageService, testTextDocument, testTextDocument.positionAt(position), jsonDocument);
}

it('Hover works on array nodes', (done) => {
Expand Down
Loading

0 comments on commit 1beb482

Please sign in to comment.