Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into crd
Browse files Browse the repository at this point in the history
msivasubramaniaan authored Dec 19, 2024
2 parents b214e05 + 1e3d5ce commit 6ca861f
Showing 24 changed files with 419 additions and 128 deletions.
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
### 1.15.0
- Fix: some small type issues [#918](https://github.com/redhat-developer/yaml-language-server/pull/918)
- Add: volar-service-yaml to clients [#920](https://github.com/redhat-developer/yaml-language-server/pull/920)
- Fix: Remove ide-yaml from known clients [#921](https://github.com/redhat-developer/yaml-language-server/pull/921)
- Fix: schema loading performance [#923](https://github.com/redhat-developer/yaml-language-server/pull/923)
- Fix: undefined error in mergingResult.problemArgs [#924](https://github.com/redhat-developer/yaml-language-server/pull/924)
- Add: unify string insert text for array and property [#934](https://github.com/redhat-developer/yaml-language-server/pull/934)
- Add: Improve some special cases for selection ranges [#939](https://github.com/redhat-developer/yaml-language-server/pull/939)
- Fix: show all enums on hover [#942](https://github.com/redhat-developer/yaml-language-server/pull/942)
- Fix: update README syntax highlighting [#945](https://github.com/redhat-developer/yaml-language-server/pull/945)
- Fix: render examples as yaml on hover [#947](https://github.com/redhat-developer/yaml-language-server/pull/947)
- Fix: snippets in additionalProperties [#951](https://github.com/redhat-developer/yaml-language-server/pull/951)
- Fix: crash when url is undefined [#954](https://github.com/redhat-developer/yaml-language-server/pull/954)
- Fix: Add null check for customTags [#955](https://github.com/redhat-developer/yaml-language-server/pull/955)

Thanks to [Remco Haszing](https://github.com/remcohaszing), [Petr Spacek](https://github.com/p-spacek), [Tony](https://github.com/Legend-Master), [Gustav Eikaas](https://github.com/GustavEikaas), [Skip Baney](https://github.com/twelvelabs) and [Pierre Prinetti](https://github.com/pierreprinetti) for your contributions.

### 1.14.0
- Fix: Request textDocument/hover failed with message: Invalid regular expression: /(?s).*/: Invalid group [#874](https://github.com/redhat-developer/yaml-language-server/issues/874)
- Fix: nested anyof const [#888](https://github.com/redhat-developer/yaml-language-server/pull/888)
11 changes: 4 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -29,15 +29,13 @@
"type": "git",
"url": "https://github.com/redhat-developer/yaml-language-server.git"
},
"optionalDependencies": {
"prettier": "2.8.7"
},
"dependencies": {
"ajv": "^8.11.0",
"lodash": "4.17.21",
"prettier": "^3.0.0",
"request-light": "^0.5.7",
"vscode-json-languageservice": "4.1.8",
"vscode-languageserver": "^7.0.0",
"vscode-languageserver": "^9.0.0",
"vscode-languageserver-textdocument": "^1.0.1",
"vscode-languageserver-types": "^3.16.0",
"vscode-nls": "^5.0.0",
@@ -49,17 +47,16 @@
"@types/chai": "^4.2.12",
"@types/mocha": "8.2.2",
"@types/node": "16.x",
"@types/prettier": "2.7.2",
"@types/sinon": "^9.0.5",
"@types/sinon-chai": "^3.2.5",
"@typescript-eslint/eslint-plugin": "^5.38.0",
"@typescript-eslint/parser": "^5.38.0",
"chai": "^4.2.0",
"coveralls": "3.1.1",
"eslint": "^8.24.0",
"eslint-config-prettier": "^8.5.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-prettier": "^5.0.0",
"http-proxy-agent": "^5.0.0",
"https-proxy-agent": "^5.0.0",
"mocha": "9.2.2",
2 changes: 1 addition & 1 deletion src/languageserver/handlers/languageHandlers.ts
Original file line number Diff line number Diff line change
@@ -114,7 +114,7 @@ export class LanguageHandlers {
* Called when the formatter is invoked
* Returns the formatted document content using prettier
*/
formatterHandler(formatParams: DocumentFormattingParams): TextEdit[] {
formatterHandler(formatParams: DocumentFormattingParams): Promise<TextEdit[]> {
const document = this.yamlSettings.documents.get(formatParams.textDocument.uri);

if (!document) {
5 changes: 4 additions & 1 deletion src/languageserver/handlers/requestHandlers.ts
Original file line number Diff line number Diff line change
@@ -14,7 +14,10 @@ import { SchemaModificationNotification } from '../../requestTypes';

export class RequestHandlers {
private languageService: LanguageService;
constructor(private readonly connection: Connection, languageService: LanguageService) {
constructor(
private readonly connection: Connection,
languageService: LanguageService
) {
this.languageService = languageService;
}

4 changes: 2 additions & 2 deletions src/languageserver/handlers/settingsHandlers.ts
Original file line number Diff line number Diff line change
@@ -82,7 +82,7 @@ export class SettingsHandler {

if (settings.yaml.schemaStore) {
this.yamlSettings.schemaStoreEnabled = settings.yaml.schemaStore.enable;
if (settings.yaml.schemaStore.url.length !== 0) {
if (settings.yaml.schemaStore.url?.length !== 0) {
this.yamlSettings.schemaStoreUrl = settings.yaml.schemaStore.url;
}
}
@@ -181,7 +181,7 @@ export class SettingsHandler {
private async setSchemaStoreSettingsIfNotSet(): Promise<void> {
const schemaStoreIsSet = this.yamlSettings.schemaStoreSettings.length !== 0;
let schemaStoreUrl = '';
if (this.yamlSettings.schemaStoreUrl.length !== 0) {
if (this.yamlSettings.schemaStoreUrl?.length !== 0) {
schemaStoreUrl = this.yamlSettings.schemaStoreUrl;
} else {
schemaStoreUrl = JSON_SCHEMASTORE_URL;
6 changes: 5 additions & 1 deletion src/languageserver/handlers/validationHandlers.ts
Original file line number Diff line number Diff line change
@@ -14,7 +14,11 @@ export class ValidationHandler {
private languageService: LanguageService;
private yamlSettings: SettingsState;

constructor(private readonly connection: Connection, languageService: LanguageService, yamlSettings: SettingsState) {
constructor(
private readonly connection: Connection,
languageService: LanguageService,
yamlSettings: SettingsState
) {
this.languageService = languageService;
this.yamlSettings = yamlSettings;

5 changes: 4 additions & 1 deletion src/languageserver/handlers/workspaceHandlers.ts
Original file line number Diff line number Diff line change
@@ -7,7 +7,10 @@ import { ExecuteCommandParams, Connection } from 'vscode-languageserver';
import { CommandExecutor } from '../commandExecutor';

export class WorkspaceHandlers {
constructor(private readonly connection: Connection, private readonly commandExecutor: CommandExecutor) {}
constructor(
private readonly connection: Connection,
private readonly commandExecutor: CommandExecutor
) {}

registerHandlers(): void {
this.connection.onExecuteCommand((params) => this.executeCommand(params));
8 changes: 7 additions & 1 deletion src/languageservice/parser/jsonParser07.ts
Original file line number Diff line number Diff line change
@@ -286,7 +286,10 @@ export interface ISchemaCollector {

class SchemaCollector implements ISchemaCollector {
schemas: IApplicableSchema[] = [];
constructor(private focusOffset = -1, private exclude: ASTNode = null) {}
constructor(
private focusOffset = -1,
private exclude: ASTNode = null
) {}
add(schema: IApplicableSchema): void {
this.schemas.push(schema);
}
@@ -888,6 +891,7 @@ function validate(
),
source: getSchemaSource(schema, originalSchema),
schemaUri: getSchemaUri(schema, originalSchema),
data: { values: schema.enum },
});
}
}
@@ -907,6 +911,7 @@ function validate(
source: getSchemaSource(schema, originalSchema),
schemaUri: getSchemaUri(schema, originalSchema),
problemArgs: [JSON.stringify(schema.const)],
data: { values: [schema.const] },
});
validationResult.enumValueMatch = false;
} else {
@@ -1385,6 +1390,7 @@ function validate(
length: propertyNode.keyNode.length,
},
severity: DiagnosticSeverity.Warning,
code: ErrorCode.PropertyExpected,
message: schema.errorMessage || localize('DisallowedExtraPropWarning', MSG_PROPERTY_NOT_ALLOWED, propertyName),
source: getSchemaSource(schema, originalSchema),
schemaUri: getSchemaUri(schema, originalSchema),
5 changes: 4 additions & 1 deletion src/languageservice/services/documentSymbols.ts
Original file line number Diff line number Diff line change
@@ -17,7 +17,10 @@ import { convertErrorToTelemetryMsg } from '../utils/objects';
export class YAMLDocumentSymbols {
private jsonDocumentSymbols;

constructor(schemaService: YAMLSchemaService, private readonly telemetry?: Telemetry) {
constructor(
schemaService: YAMLSchemaService,
private readonly telemetry?: Telemetry
) {
this.jsonDocumentSymbols = new JSONDocumentSymbols(schemaService);

// override 'getKeyLabel' to handle complex mapping
57 changes: 52 additions & 5 deletions src/languageservice/services/yamlCodeActions.ts
Original file line number Diff line number Diff line change
@@ -28,9 +28,12 @@ import { FlowStyleRewriter } from '../utils/flow-style-rewriter';
import { ASTNode } from '../jsonASTTypes';
import * as _ from 'lodash';
import { SourceToken } from 'yaml/dist/parse/cst';
import { ErrorCode } from 'vscode-json-languageservice';

interface YamlDiagnosticData {
schemaUri: string[];
values?: string[];
properties?: string[];
}
export class YamlCodeActions {
private indentation = ' ';
@@ -54,6 +57,7 @@ export class YamlCodeActions {
result.push(...this.getUnusedAnchorsDelete(params.context.diagnostics, document));
result.push(...this.getConvertToBlockStyleActions(params.context.diagnostics, document));
result.push(...this.getKeyOrderActions(params.context.diagnostics, document));
result.push(...this.getQuickFixForPropertyOrValueMismatch(params.context.diagnostics, document));

return result;
}
@@ -221,7 +225,7 @@ export class YamlCodeActions {
const results: CodeAction[] = [];
for (const diagnostic of diagnostics) {
if (diagnostic.code === 'flowMap' || diagnostic.code === 'flowSeq') {
const node = getNodeforDiagnostic(document, diagnostic);
const node = getNodeForDiagnostic(document, diagnostic);
if (isMap(node.internalNode) || isSeq(node.internalNode)) {
const blockTypeDescription = isMap(node.internalNode) ? 'map' : 'sequence';
const rewriter = new FlowStyleRewriter(this.indentation);
@@ -242,7 +246,7 @@ export class YamlCodeActions {
const results: CodeAction[] = [];
for (const diagnostic of diagnostics) {
if (diagnostic?.code === 'mapKeyOrder') {
let node = getNodeforDiagnostic(document, diagnostic);
let node = getNodeForDiagnostic(document, diagnostic);
while (node && node.type !== 'object') {
node = node.parent;
}
@@ -292,8 +296,8 @@ export class YamlCodeActions {
item.value.end.splice(newLineIndex, 1);
}
} else if (item.value?.type === 'block-scalar') {
const nwline = item.value.props.find((p) => p.type === 'newline');
if (!nwline) {
const newline = item.value.props.find((p) => p.type === 'newline');
if (!newline) {
item.value.props.push({ type: 'newline', indent: 0, offset: item.value.offset, source: '\n' } as SourceToken);
}
}
@@ -312,9 +316,52 @@ export class YamlCodeActions {
}
return results;
}

/**
* Check if diagnostic contains info for quick fix
* Supports Enum/Const/Property mismatch
*/
private getPossibleQuickFixValues(diagnostic: Diagnostic): string[] | undefined {
if (typeof diagnostic.data !== 'object') {
return;
}
if (
diagnostic.code === ErrorCode.EnumValueMismatch &&
'values' in diagnostic.data &&
Array.isArray((diagnostic.data as YamlDiagnosticData).values)
) {
return (diagnostic.data as YamlDiagnosticData).values;
} else if (
diagnostic.code === ErrorCode.PropertyExpected &&
'properties' in diagnostic.data &&
Array.isArray((diagnostic.data as YamlDiagnosticData).properties)
) {
return (diagnostic.data as YamlDiagnosticData).properties;
}
}

private getQuickFixForPropertyOrValueMismatch(diagnostics: Diagnostic[], document: TextDocument): CodeAction[] {
const results: CodeAction[] = [];
for (const diagnostic of diagnostics) {
const values = this.getPossibleQuickFixValues(diagnostic);
if (!values?.length) {
continue;
}
for (const value of values) {
results.push(
CodeAction.create(
value,
createWorkspaceEdit(document.uri, [TextEdit.replace(diagnostic.range, value)]),
CodeActionKind.QuickFix
)
);
}
}
return results;
}
}

function getNodeforDiagnostic(document: TextDocument, diagnostic: Diagnostic): ASTNode {
function getNodeForDiagnostic(document: TextDocument, diagnostic: Diagnostic): ASTNode {
const yamlDocuments = yamlDocumentsCache.getYamlDocument(document);
const startOffset = document.offsetAt(diagnostic.range.start);
const yamlDoc = matchOffsetToDocument(startOffset, yamlDocuments);
5 changes: 4 additions & 1 deletion src/languageservice/services/yamlCodeLens.ts
Original file line number Diff line number Diff line change
@@ -15,7 +15,10 @@ import { convertErrorToTelemetryMsg } from '../utils/objects';
import { getSchemaTitle } from '../utils/schemaUtils';

export class YamlCodeLens {
constructor(private schemaService: YAMLSchemaService, private readonly telemetry?: Telemetry) {}
constructor(
private schemaService: YAMLSchemaService,
private readonly telemetry?: Telemetry
) {}

async getCodeLens(document: TextDocument): Promise<CodeLens[]> {
const result = [];
2 changes: 1 addition & 1 deletion src/languageservice/services/yamlCompletion.ts
Original file line number Diff line number Diff line change
@@ -293,7 +293,7 @@ export class YamlCompletion {
proposed,
};

if (this.customTags.length > 0) {
if (this.customTags && this.customTags.length > 0) {
this.getCustomTagValueCompletions(collector);
}

12 changes: 7 additions & 5 deletions src/languageservice/services/yamlFormatter.ts
Original file line number Diff line number Diff line change
@@ -6,9 +6,8 @@

import { Range, Position, TextEdit, FormattingOptions } from 'vscode-languageserver-types';
import { CustomFormatterOptions, LanguageSettings } from '../yamlLanguageService';
import * as prettier from 'prettier';
import { Options } from 'prettier';
import * as parser from 'prettier/parser-yaml';
import { format, Options } from 'prettier';
import * as parser from 'prettier/plugins/yaml';
import { TextDocument } from 'vscode-languageserver-textdocument';

export class YAMLFormatter {
@@ -20,7 +19,10 @@ export class YAMLFormatter {
}
}

public format(document: TextDocument, options: Partial<FormattingOptions> & CustomFormatterOptions = {}): TextEdit[] {
public async format(
document: TextDocument,
options: Partial<FormattingOptions> & CustomFormatterOptions = {}
): Promise<TextEdit[]> {
if (!this.formatterEnabled) {
return [];
}
@@ -43,7 +45,7 @@ export class YAMLFormatter {
printWidth: options.printWidth,
};

const formatted = prettier.format(text, prettierOptions);
const formatted = await format(text, prettierOptions);

return [TextEdit.replace(Range.create(Position.create(0, 0), document.positionAt(text.length)), formatted)];
} catch (error) {
5 changes: 4 additions & 1 deletion src/languageservice/services/yamlHover.ts
Original file line number Diff line number Diff line change
@@ -26,7 +26,10 @@ export class YAMLHover {
private indentation: string;
private schemaService: YAMLSchemaService;

constructor(schemaService: YAMLSchemaService, private readonly telemetry?: Telemetry) {
constructor(
schemaService: YAMLSchemaService,
private readonly telemetry?: Telemetry
) {
this.shouldHover = true;
this.schemaService = schemaService;
}
5 changes: 4 additions & 1 deletion src/languageservice/services/yamlValidation.ts
Original file line number Diff line number Diff line change
@@ -48,7 +48,10 @@ export class YAMLValidation {

private MATCHES_MULTIPLE = 'Matches multiple schemas when only one must validate.';

constructor(schemaService: YAMLSchemaService, private readonly telemetry?: Telemetry) {
constructor(
schemaService: YAMLSchemaService,
private readonly telemetry?: Telemetry
) {
this.validationEnabled = true;
this.jsonValidation = new JSONValidation(schemaService, Promise);
}
4 changes: 2 additions & 2 deletions src/languageservice/utils/schemaUtils.ts
Original file line number Diff line number Diff line change
@@ -16,8 +16,8 @@ export function getSchemaTypeName(schema: JSONSchema): string {
return Array.isArray(schema.type)
? schema.type.join(' | ')
: closestTitleWithType
? schema.type.concat('(', schema.closestTitle, ')')
: schema.type || schema.closestTitle; //object
? schema.type.concat('(', schema.closestTitle, ')')
: schema.type || schema.closestTitle; //object
}

/**
2 changes: 1 addition & 1 deletion src/languageservice/yamlLanguageService.ts
Original file line number Diff line number Diff line change
@@ -166,7 +166,7 @@ export interface LanguageService {
findDocumentSymbols2: (document: TextDocument, context?: DocumentSymbolsContext) => DocumentSymbol[];
findLinks: (document: TextDocument) => Promise<DocumentLink[]>;
resetSchema: (uri: string) => boolean;
doFormat: (document: TextDocument, options?: CustomFormatterOptions) => TextEdit[];
doFormat: (document: TextDocument, options?: CustomFormatterOptions) => Promise<TextEdit[]>;
doDefinition: (document: TextDocument, params: DefinitionParams) => DefinitionLink[] | undefined;
doDocumentOnTypeFormatting: (document: TextDocument, params: DocumentOnTypeFormattingParams) => TextEdit[] | undefined;
addSchema: (schemaID: string, schema: JSONSchema) => void;
5 changes: 5 additions & 0 deletions test/autoCompletion.test.ts
Original file line number Diff line number Diff line change
@@ -3126,5 +3126,10 @@ describe('Auto Completion Tests', () => {
expect(result.items.map((i) => i.label)).to.have.members(['fruit', 'vegetable']);
});
});
it('Should function when settings are undefined', async () => {
languageService.configure({ completion: true });
const content = '';
await parseSetup(content, 0);
});
});
});
27 changes: 14 additions & 13 deletions test/formatter.test.ts
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@ describe('Formatter Tests', () => {
describe('Formatter', function () {
describe('Test that formatter works with custom tags', function () {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function parseSetup(content: string, options: any = {}): TextEdit[] {
function parseSetup(content: string, options: any = {}): Promise<TextEdit[]> {
const testTextDocument = setupTextDocument(content);
yamlSettings.documents = new TextDocumentTestManager();
(yamlSettings.documents as TextDocumentTestManager).set(testTextDocument);
@@ -35,31 +35,32 @@ describe('Formatter Tests', () => {
});
}

it('Formatting works without custom tags', () => {
it('Formatting works without custom tags', async () => {
const content = 'cwd: test';
const edits = parseSetup(content);
const edits = await parseSetup(content);
console.dir({ edits });
assert.notEqual(edits.length, 0);
assert.equal(edits[0].newText, 'cwd: test\n');
});

it('Formatting works with custom tags', () => {
it('Formatting works with custom tags', async () => {
const content = 'cwd: !Test test';
const edits = parseSetup(content);
const edits = await parseSetup(content);
assert.notEqual(edits.length, 0);
assert.equal(edits[0].newText, 'cwd: !Test test\n');
});

it('Formatting wraps text', () => {
it('Formatting wraps text', async () => {
const content = `comments: >
test test test test test test test test test test test test`;
const edits = parseSetup(content, {
const edits = await parseSetup(content, {
printWidth: 20,
proseWrap: 'always',
});
assert.equal(edits[0].newText, 'comments: >\n test test test\n test test test\n test test test\n test test test\n');
});

it('Formatting uses tabSize', () => {
it('Formatting uses tabSize', async () => {
const content = `map:
k1: v1
k2: v2
@@ -68,7 +69,7 @@ list:
- item2
`;

const edits = parseSetup(content, {
const edits = await parseSetup(content, {
tabSize: 5,
});

@@ -82,7 +83,7 @@ list:
assert.equal(edits[0].newText, expected);
});

it('Formatting uses tabWidth', () => {
it('Formatting uses tabWidth', async () => {
const content = `map:
k1: v1
k2: v2
@@ -91,7 +92,7 @@ list:
- item2
`;

const edits = parseSetup(content, {
const edits = await parseSetup(content, {
tabWidth: 5,
});

@@ -105,7 +106,7 @@ list:
assert.equal(edits[0].newText, expected);
});

it('Formatting uses tabWidth over tabSize', () => {
it('Formatting uses tabWidth over tabSize', async () => {
const content = `map:
k1: v1
k2: v2
@@ -114,7 +115,7 @@ list:
- item2
`;

const edits = parseSetup(content, {
const edits = await parseSetup(content, {
tabSize: 3,
tabWidth: 5,
});
7 changes: 5 additions & 2 deletions test/schemaValidation.test.ts
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@ import { KUBERNETES_SCHEMA_URL } from '../src/languageservice/utils/schemaUrls';
import { IProblem } from '../src/languageservice/parser/jsonParser07';
import { JSONSchema } from '../src/languageservice/jsonSchema';
import { TestTelemetry } from './utils/testsTypes';
import { ErrorCode } from 'vscode-json-languageservice';

describe('Validation Tests', () => {
let languageSettingsSetup: ServiceSetup;
@@ -396,7 +397,8 @@ describe('Validation Tests', () => {
4,
DiagnosticSeverity.Error,
`yaml-schema: file:///${SCHEMA_ID}`,
`file:///${SCHEMA_ID}`
`file:///${SCHEMA_ID}`,
ErrorCode.PropertyExpected
)
);
})
@@ -1289,7 +1291,7 @@ obj:
4,
18,
DiagnosticSeverity.Error,
'yaml-schema: Package',
'yaml-schema: Composer Package',
'https://raw.githubusercontent.com/composer/composer/master/res/composer-schema.json'
)
);
@@ -1312,6 +1314,7 @@ obj:
DiagnosticSeverity.Error,
'yaml-schema: Drone CI configuration file',
'https://json.schemastore.org/drone',
ErrorCode.PropertyExpected,
{
properties: [
'type',
22 changes: 15 additions & 7 deletions test/utils/testsTypes.ts
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { Event, NotificationHandler, RequestHandler } from 'vscode-jsonrpc';
import { Disposable, Event, NotificationHandler, RequestHandler } from 'vscode-jsonrpc';
import {
ApplyWorkspaceEditParams,
WorkspaceEdit,
@@ -14,6 +14,8 @@ import {
CreateFilesParams,
RenameFilesParams,
DeleteFilesParams,
ClientCapabilities,
ServerCapabilities,
} from 'vscode-languageserver-protocol';
import { Connection, RemoteWorkspace } from 'vscode-languageserver';
import { TelemetryImpl } from '../../src/languageserver/telemetry';
@@ -27,6 +29,9 @@ export class TestWorkspace implements RemoteWorkspace {
applyEdit(paramOrEdit: ApplyWorkspaceEditParams | WorkspaceEdit): Promise<ApplyWorkspaceEditResponse> {
throw new Error('Method not implemented.');
}
fillServerCapabilities(capabilities: ServerCapabilities<any>): void {
throw new Error('Method not implemented.');
}
getConfiguration(): Promise<any>;
getConfiguration(section: string): Promise<any>;
getConfiguration(item: ConfigurationItem): Promise<any>;
@@ -37,23 +42,26 @@ export class TestWorkspace implements RemoteWorkspace {
getWorkspaceFolders(): Promise<WorkspaceFolder[]> {
throw new Error('Method not implemented.');
}
initialize(capabilities: ClientCapabilities): void {
throw new Error('Method not implemented.');
}
onDidChangeWorkspaceFolders: Event<WorkspaceFoldersChangeEvent>;
onDidCreateFiles(handler: NotificationHandler<CreateFilesParams>): void {
onDidCreateFiles(handler: NotificationHandler<CreateFilesParams>): Disposable {
throw new Error('Method not implemented.');
}
onDidRenameFiles(handler: NotificationHandler<RenameFilesParams>): void {
onDidRenameFiles(handler: NotificationHandler<RenameFilesParams>): Disposable {
throw new Error('Method not implemented.');
}
onDidDeleteFiles(handler: NotificationHandler<DeleteFilesParams>): void {
onDidDeleteFiles(handler: NotificationHandler<DeleteFilesParams>): Disposable {
throw new Error('Method not implemented.');
}
onWillCreateFiles(handler: RequestHandler<CreateFilesParams, WorkspaceEdit, never>): void {
onWillCreateFiles(handler: RequestHandler<CreateFilesParams, WorkspaceEdit, never>): Disposable {
throw new Error('Method not implemented.');
}
onWillRenameFiles(handler: RequestHandler<RenameFilesParams, WorkspaceEdit, never>): void {
onWillRenameFiles(handler: RequestHandler<RenameFilesParams, WorkspaceEdit, never>): Disposable {
throw new Error('Method not implemented.');
}
onWillDeleteFiles(handler: RequestHandler<DeleteFilesParams, WorkspaceEdit, never>): void {
onWillDeleteFiles(handler: RequestHandler<DeleteFilesParams, WorkspaceEdit, never>): Disposable {
throw new Error('Method not implemented.');
}
}
12 changes: 11 additions & 1 deletion test/utils/verifyError.ts
Original file line number Diff line number Diff line change
@@ -39,9 +39,19 @@ export function createDiagnosticWithData(
severity: DiagnosticSeverity = 1,
source = 'YAML',
schemaUri: string | string[],
code: string | number = ErrorCode.Undefined,
data: Record<string, unknown> = {}
): Diagnostic {
const diagnostic: Diagnostic = createExpectedError(message, startLine, startCharacter, endLine, endCharacter, severity, source);
const diagnostic: Diagnostic = createExpectedError(
message,
startLine,
startCharacter,
endLine,
endCharacter,
severity,
source,
code
);
diagnostic.data = { schemaUri: typeof schemaUri === 'string' ? [schemaUri] : schemaUri, ...data };
return diagnostic;
}
55 changes: 55 additions & 0 deletions test/yamlCodeActions.test.ts
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@ import { setupTextDocument, TEST_URI } from './utils/testHelper';
import { createDiagnosticWithData, createExpectedError, createUnusedAnchorDiagnostic } from './utils/verifyError';
import { YamlCommands } from '../src/commands';
import { LanguageSettings } from '../src';
import { ErrorCode } from 'vscode-json-languageservice';

const expect = chai.expect;
chai.use(sinonChai);
@@ -377,4 +378,58 @@ animals: [dog , cat , mouse] `;
]);
});
});

describe('Enum value or property mismatch quick fix', () => {
it('should generate proper action for enum mismatch', () => {
const doc = setupTextDocument('foo: value1');
const diagnostic = createDiagnosticWithData(
'message',
0,
5,
0,
11,
DiagnosticSeverity.Hint,
'YAML',
'schemaUri',
ErrorCode.EnumValueMismatch,
{ values: ['valueX', 'valueY'] }
);
const params: CodeActionParams = {
context: CodeActionContext.create([diagnostic]),
range: undefined,
textDocument: TextDocumentIdentifier.create(TEST_URI),
};
const actions = new YamlCodeActions(clientCapabilities);
const result = actions.getCodeAction(doc, params);
expect(result.map((r) => r.title)).deep.equal(['valueX', 'valueY']);
expect(result[0].edit.changes[TEST_URI]).deep.equal([TextEdit.replace(Range.create(0, 5, 0, 11), 'valueX')]);
});

it('should generate proper action for wrong property', () => {
const doc = setupTextDocument('foo: value1');
const diagnostic = createDiagnosticWithData(
'message',
0,
0,
0,
3,
DiagnosticSeverity.Hint,
'YAML',
'schemaUri',
ErrorCode.PropertyExpected,
{
properties: ['fooX', 'fooY'],
}
);
const params: CodeActionParams = {
context: CodeActionContext.create([diagnostic]),
range: undefined,
textDocument: TextDocumentIdentifier.create(TEST_URI),
};
const actions = new YamlCodeActions(clientCapabilities);
const result = actions.getCodeAction(doc, params);
expect(result.map((r) => r.title)).deep.equal(['fooX', 'fooY']);
expect(result[0].edit.changes[TEST_URI]).deep.equal([TextEdit.replace(Range.create(0, 0, 0, 3), 'fooX')]);
});
});
});
264 changes: 191 additions & 73 deletions yarn.lock

Large diffs are not rendered by default.

0 comments on commit 6ca861f

Please sign in to comment.