diff --git a/src/services/jsonHover.ts b/src/services/jsonHover.ts
index 11d2fe1..afaf25b 100644
--- a/src/services/jsonHover.ts
+++ b/src/services/jsonHover.ts
@@ -60,61 +60,64 @@ export class JSONHover {
}
return this.schemaService.getSchemaForResource(document.uri, doc).then((schema) => {
- if (schema && node) {
- const matchingSchemas = doc.getMatchingSchemas(schema.schema, node.offset);
-
- let title: string | undefined = undefined;
- let markdownDescription: string | undefined = undefined;
- let markdownEnumValueDescription: string | undefined = undefined, enumValue: string | undefined = undefined;
- 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) {
- const 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]);
- }
- if (markdownEnumValueDescription) {
- enumValue = s.schema.enum[idx];
- if (typeof enumValue !== 'string') {
- enumValue = JSON.stringify(enumValue);
- }
- }
+ if (!schema) {
+ return null
+ }
+
+ let title: string | undefined = undefined;
+ let markdownDescription: string | undefined = undefined;
+ let markdownEnumValueDescription: string | undefined = undefined, enumValue: string | undefined = undefined;
+
+ const matchingSchemas = doc.getMatchingSchemas(schema.schema, node.offset).filter((s) => s.node === node && !s.inverted).map((s) => s.schema);
+ for (const schema of matchingSchemas) {
+ title = title || schema.title;
+ markdownDescription = markdownDescription || schema.markdownDescription || toMarkdown(schema.description);
+ if (schema.enum) {
+ const idx = schema.enum.indexOf(Parser.getNodeValue(node));
+ if (schema.markdownEnumDescriptions) {
+ markdownEnumValueDescription = schema.markdownEnumDescriptions[idx];
+ } else if (schema.enumDescriptions) {
+ markdownEnumValueDescription = toMarkdown(schema.enumDescriptions[idx]);
+ }
+ if (markdownEnumValueDescription) {
+ enumValue = 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;
+ }
+
+ let result = '';
+ if (title) {
+ result = toMarkdown(title);
+ }
+ if (markdownDescription) {
+ if (result.length > 0) {
+ result += "\n\n";
}
- if (markdownEnumValueDescription) {
- if (result.length > 0) {
- result += "\n\n";
- }
- result += `\`${toMarkdownCodeBlock(enumValue!)}\`: ${markdownEnumValueDescription}`;
+ result += markdownDescription;
+ }
+ if (markdownEnumValueDescription) {
+ if (result.length > 0) {
+ result += "\n\n";
}
- return createHover([result]);
+ result += `\`${toMarkdownCodeBlock(enumValue!)}\`: ${markdownEnumValueDescription}`;
}
- return null;
+ return createHover([result]);
});
}
}
+
function toMarkdown(plain: string): string;
function toMarkdown(plain: string | undefined): string | undefined;
function toMarkdown(plain: string | undefined): string | undefined {
if (plain) {
- const 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 plain
+ .trim()
+ .replace(/[\\`*_{}[\]()<>#+\-.!]/g, '\\$&') // escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash
+ .replace(/([ \t]+)/g, (_match, g1) => ' '.repeat(g1.length)) // escape spaces tabs
+ .replace(/\n/g, '\\\n'); // escape new lines
}
return undefined;
}
diff --git a/src/test/hover.test.ts b/src/test/hover.test.ts
index 342656b..6b9917c 100644
--- a/src/test/hover.test.ts
+++ b/src/test/hover.test.ts
@@ -5,7 +5,7 @@
import * as assert from 'assert';
-import { Hover, Position, MarkedString, TextDocument, getLanguageService, JSONSchema, LanguageServiceParams } from '../jsonLanguageService';
+import { Hover, Position, TextDocument, getLanguageService, JSONSchema, LanguageServiceParams } from '../jsonLanguageService';
suite('JSON Hover', () => {
@@ -33,7 +33,7 @@ suite('JSON Hover', () => {
test('Simple schema', async function () {
- const content = '{"a": 42, "b": "hello", "c": false}';
+ const content = '{"a": 42, "b": "hello", "c": false, "complex-description": false}';
const schema: JSONSchema = {
type: 'object',
description: 'a very special object',
@@ -49,20 +49,27 @@ suite('JSON Hover', () => {
'c': {
type: 'boolean',
description: 'C'
- }
+ },
+ 'complex-description': {
+ type: 'boolean',
+ description: 'For example:\n\n\n\n Test [1]'
+ },
}
};
await testComputeInfo(content, schema, { line: 0, character: 0 }).then((result) => {
- assert.deepEqual(result.contents, [MarkedString.fromPlainText('a very special object')]);
+ assert.deepEqual(result.contents, ['a very special object']);
});
await testComputeInfo(content, schema, { line: 0, character: 1 }).then((result) => {
- assert.deepEqual(result.contents, [MarkedString.fromPlainText('A')]);
+ assert.deepEqual(result.contents, ['A']);
});
await testComputeInfo(content, schema, { line: 0, character: 32 }).then((result) => {
- assert.deepEqual(result.contents, [MarkedString.fromPlainText('C')]);
+ assert.deepEqual(result.contents, ['C']);
+ });
+ await testComputeInfo(content, schema, { line: 0, character: 37 }).then((result) => {
+ assert.deepEqual(result.contents, ['For example:\\\n\\\n\\\\\n\\\n Test \\[1\\]']);
});
await testComputeInfo(content, schema, { line: 0, character: 7 }).then((result) => {
- assert.deepEqual(result.contents, [MarkedString.fromPlainText('A')]);
+ assert.deepEqual(result.contents, ['A']);
});
});
@@ -89,13 +96,13 @@ suite('JSON Hover', () => {
}]
};
await testComputeInfo(content, schema, { line: 0, character: 0 }).then((result) => {
- assert.deepEqual(result.contents, [MarkedString.fromPlainText('a very special object')]);
+ assert.deepEqual(result.contents, ['a very special object']);
});
await testComputeInfo(content, schema, { line: 0, character: 1 }).then((result) => {
- assert.deepEqual(result.contents, [MarkedString.fromPlainText('A')]);
+ assert.deepEqual(result.contents, ['A']);
});
await testComputeInfo(content, schema, { line: 0, character: 10 }).then((result) => {
- assert.deepEqual(result.contents, [MarkedString.fromPlainText('B\n\nIt\'s B')]);
+ assert.deepEqual(result.contents, ['B\n\nIt\'s B']);
});
});
@@ -154,10 +161,10 @@ suite('JSON Hover', () => {
};
await testComputeInfo('{ "prop1": "e1', schema, { line: 0, character: 12 }).then(result => {
- assert.deepEqual(result.contents, ['line1\n\nline2\n\nline3\n\n\nline4\n']);
+ assert.deepEqual(result.contents, ['line1\\\nline2\\\n\\\nline3\\\n\\\n\\\nline4']);
});
await testComputeInfo('{ "prop2": "e1', schema, { line: 0, character: 12 }).then(result => {
- assert.deepEqual(result.contents, ['line1\n\nline2\r\n\r\nline3']);
+ assert.deepEqual(result.contents, ['line1\r\\\nline2\r\\\n\r\\\nline3']);
});
});