Skip to content

Commit

Permalink
Merge branch 'main' into dependabot/npm_and_yarn/babel/traverse-7.23.2
Browse files Browse the repository at this point in the history
  • Loading branch information
msivasubramaniaan committed Jan 5, 2024
2 parents 0d8297f + 5458ed3 commit 8097579
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 44 deletions.
36 changes: 18 additions & 18 deletions README.md
Expand Up @@ -58,7 +58,7 @@ The following settings are supported:

In order to use the custom tags in your YAML file you need to first specify the custom tags in the setting of your code editor. For example, we can have the following custom tags:

```YAML
```yaml
"yaml.customTags": [
"!Scalar-example scalar",
"!Seq-example sequence",
Expand All @@ -70,7 +70,7 @@ The !Scalar-example would map to a scalar custom tag, the !Seq-example would map

We can then use the newly defined custom tags inside our YAML file:

```YAML
```yaml
some_key: !Scalar-example some_value
some_sequence: !Seq-example
- some_seq_key_1: some_seq_value_1
Expand All @@ -93,7 +93,7 @@ myProject

you can do

```
```yaml
yaml.schemas: {
"https://json.schemastore.org/composer": "/myYamlFile.yaml"
}
Expand All @@ -109,7 +109,7 @@ and that will associate the composer schema with myYamlFile.yaml.

When associating a schema it should follow the format below

```json
```yaml
yaml.schemas: {
"url": "globPattern",
"Kubernetes": "globPattern"
Expand All @@ -118,23 +118,23 @@ yaml.schemas: {

e.g.

```json
```yaml
yaml.schemas: {
"https://json.schemastore.org/composer": "/*"
}
```

e.g.

```json
```yaml
yaml.schemas: {
"kubernetes": "/myYamlFile.yaml"
}
```

e.g.

```json
```yaml
yaml.schemas: {
"https://json.schemastore.org/composer": "/*",
"kubernetes": "/myYamlFile.yaml"
Expand All @@ -143,37 +143,37 @@ yaml.schemas: {

On Windows with full path:

```json
```yaml
yaml.schemas: {
"C:\\Users\\user\\Documents\\custom_schema.json": "someFilePattern.yaml",
}
```

On Mac/Linux with full path:

```json
```yaml
yaml.schemas: {
"/home/user/custom_schema.json": "someFilePattern.yaml",
}
```

Since `0.11.0` YAML Schemas can be used for validation:

```json
```yaml
"/home/user/custom_schema.yaml": "someFilePattern.yaml"
```

A schema can be associated with multiple globs using a json array, e.g.

```json
```yaml
yaml.schemas: {
"kubernetes": ["filePattern1.yaml", "filePattern2.yaml"]
}
```

e.g.

```json
```yaml
"yaml.schemas": {
"http://json.schemastore.org/composer": ["/*"],
"file:///home/johnd/some-schema.json": ["some.yaml"],
Expand All @@ -184,15 +184,15 @@ e.g.

e.g.

```json
```yaml
"yaml.schemas": {
"kubernetes": ["/myYamlFile.yaml"]
}
```

e.g.

```json
```yaml
"yaml.schemas": {
"http://json.schemastore.org/composer": ["/*"],
"kubernetes": ["/myYamlFile.yaml"]
Expand All @@ -205,7 +205,7 @@ You can also use relative paths when working with multi root workspaces.

Suppose you have a multi root workspace that is laid out like:

```
```yaml
My_first_project:
test.yaml
my_schema.json
Expand All @@ -216,7 +216,7 @@ My_second_project:

You must then associate schemas relative to the root of the multi root workspace project.

```
```yaml
yaml.schemas: {
"My_first_project/my_schema.json": "test.yaml",
"My_second_project/my_schema2.json": "test2.yaml"
Expand All @@ -229,7 +229,7 @@ yaml.schemas: {

Suppose a file is meant to be a component of an existing schema (like a `job.yaml` file in a circleci orb), but there isn't a standalone schema that you can reference. If there is a nested schema definition for this subcomponent, you can reference it using a url fragment, e.g.:

```
```yaml
yaml.schemas: {
"https://json.schemastore.org/circleciconfig#/definitions/jobs/additionalProperties": "/src/jobs/*.yaml",
}
Expand Down Expand Up @@ -275,7 +275,7 @@ The image is located at `quay.io/redhat-developer/yaml-language-server`

To run the image you can use:

```
```sh
docker run -it quay.io/redhat-developer/yaml-language-server:latest
```

Expand Down
67 changes: 44 additions & 23 deletions src/languageservice/services/yamlHover.ts
Expand Up @@ -12,7 +12,7 @@ import { setKubernetesParserOption } from '../parser/isKubernetes';
import { TextDocument } from 'vscode-languageserver-textdocument';
import { yamlDocumentsCache } from '../parser/yaml-documents';
import { SingleYAMLDocument } from '../parser/yamlParser07';
import { getNodeValue, IApplicableSchema } from '../parser/jsonParser07';
import { IApplicableSchema } from '../parser/jsonParser07';
import { JSONSchema } from '../jsonSchema';
import { URI } from 'vscode-uri';
import * as path from 'path';
Expand Down Expand Up @@ -113,27 +113,31 @@ export class YAMLHover {

let title: string | undefined = undefined;
let markdownDescription: string | undefined = undefined;
let markdownEnumValueDescription: string | undefined = undefined;
let enumValue: string | undefined = undefined;
let markdownEnumDescriptions: string[] = [];
const markdownExamples: string[] = [];
const markdownEnums: markdownEnum[] = [];

matchingSchemas.every((s) => {
if ((s.node === node || (node.type === 'property' && node.valueNode === s.node)) && !s.inverted && s.schema) {
title = title || s.schema.title || s.schema.closestTitle;
markdownDescription = markdownDescription || s.schema.markdownDescription || toMarkdown(s.schema.description);
if (s.schema.enum) {
const idx = s.schema.enum.indexOf(getNodeValue(node));
if (s.schema.markdownEnumDescriptions) {
markdownEnumValueDescription = s.schema.markdownEnumDescriptions[idx];
markdownEnumDescriptions = s.schema.markdownEnumDescriptions;
} else if (s.schema.enumDescriptions) {
markdownEnumValueDescription = toMarkdown(s.schema.enumDescriptions[idx]);
markdownEnumDescriptions = s.schema.enumDescriptions.map(toMarkdown);
} else {
markdownEnumDescriptions = [];
}
if (markdownEnumValueDescription) {
enumValue = s.schema.enum[idx];
s.schema.enum.forEach((enumValue, idx) => {
if (typeof enumValue !== 'string') {
enumValue = JSON.stringify(enumValue);
}
}
markdownEnums.push({
value: enumValue,
description: markdownEnumDescriptions[idx],
});
});
}
if (s.schema.anyOf && isAllSchemasMatched(node, matchingSchemas, s.schema)) {
//if append title and description of all matched schemas on hover
Expand Down Expand Up @@ -163,28 +167,30 @@ export class YAMLHover {
result = '#### ' + toMarkdown(title);
}
if (markdownDescription) {
if (result.length > 0) {
result += '\n\n';
}
result = ensureLineBreak(result);
result += markdownDescription;
}
if (markdownEnumValueDescription) {
if (result.length > 0) {
result += '\n\n';
}
result += `\`${toMarkdownCodeBlock(enumValue)}\`: ${markdownEnumValueDescription}`;
if (markdownEnums.length !== 0) {
result = ensureLineBreak(result);
result += 'Allowed Values:\n\n';
markdownEnums.forEach((me) => {
if (me.description) {
result += `* \`${toMarkdownCodeBlock(me.value)}\`: ${me.description}\n`;
} else {
result += `* \`${toMarkdownCodeBlock(me.value)}\`\n`;
}
});
}
if (markdownExamples.length !== 0) {
if (result.length > 0) {
result += '\n\n';
}
result += 'Examples:';
result = ensureLineBreak(result);
result += 'Examples:\n\n';
markdownExamples.forEach((example) => {
result += `\n\n\`\`\`${example}\`\`\``;
result += `* \`\`\`${example}\`\`\`\n`;
});
}
if (result.length > 0 && schema.schema.url) {
result += `\n\nSource: [${getSchemaName(schema.schema)}](${schema.schema.url})`;
result = ensureLineBreak(result);
result += `Source: [${getSchemaName(schema.schema)}](${schema.schema.url})`;
}
return createHover(result);
}
Expand All @@ -193,6 +199,21 @@ export class YAMLHover {
}
}

interface markdownEnum {
value: string;
description: string;
}

function ensureLineBreak(content: string): string {
if (content.length === 0) {
return content;
}
if (!content.endsWith('\n')) {
content += '\n';
}
return content + '\n';
}

function getSchemaName(schema: JSONSchema): string {
let result = 'JSON Schema';
const urlString = schema.url;
Expand Down
41 changes: 38 additions & 3 deletions test/hover.test.ts
Expand Up @@ -556,6 +556,37 @@ users:
);
});

it('Hover displays enum descriptions if present', async () => {
schemaProvider.addSchema(SCHEMA_ID, {
type: 'object',
properties: {
animal: {
type: 'string',
description: 'should return this description',
enum: ['cat', 'dog', 'non'],
enumDescriptions: ['', 'Canis familiaris'],
},
},
});
const content = 'animal:\n ca|t|'; // len: 13, pos: 12
const result = await parseSetup(content);

assert.strictEqual(MarkupContent.is(result.contents), true);
assert.strictEqual((result.contents as MarkupContent).kind, 'markdown');
assert.strictEqual(
(result.contents as MarkupContent).value,
`should return this description
Allowed Values:
* \`cat\`
* \`dog\`: Canis familiaris
* \`non\`
Source: [${SCHEMA_ID}](file:///${SCHEMA_ID})`
);
});

it('Hover works on examples', async () => {
schemaProvider.addSchema(SCHEMA_ID, {
type: 'object',
Expand All @@ -577,11 +608,15 @@ users:
(result.contents as MarkupContent).value,
`should return this description
Examples:
Allowed Values:
* \`cat\`
* \`dog\`
\`\`\`"cat"\`\`\`
Examples:
\`\`\`"dog"\`\`\`
* \`\`\`"cat"\`\`\`
* \`\`\`"dog"\`\`\`
Source: [${SCHEMA_ID}](file:///${SCHEMA_ID})`
);
Expand Down

0 comments on commit 8097579

Please sign in to comment.