Skip to content

Commit

Permalink
Merge branch 'master' of github.com:redhat-developer/yaml-language-se…
Browse files Browse the repository at this point in the history
…rver into fix-i412

Signed-off-by: Yevhen Vydolob <[email protected]>
  • Loading branch information
evidolob committed Mar 19, 2021
2 parents 184e8f9 + 30001e5 commit 230e8f8
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 22 deletions.
43 changes: 30 additions & 13 deletions src/languageserver/handlers/settingsHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { xhr, configure as configureHttpRequests } from 'request-light';
import { DidChangeConfigurationParams, DocumentFormattingRequest, Connection } from 'vscode-languageserver';
import { isRelativePath, relativeToAbsolutePath } from '../../languageservice/utils/paths';
import { checkSchemaURI, JSON_SCHEMASTORE_URL, KUBERNETES_SCHEMA_URL } from '../../languageservice/utils/schemaUrls';
import { LanguageService, LanguageSettings } from '../../languageservice/yamlLanguageService';
import { LanguageService, LanguageSettings, SchemaPriority } from '../../languageservice/yamlLanguageService';
import { Settings, SettingsState } from '../../yamlSettings';
import { ValidationHandler } from './validationHandlers';

Expand Down Expand Up @@ -158,6 +158,7 @@ export class SettingsHandler {
uri: schema.url,
// this is workaround to fix file matcher, adding '/' force to match full file name instead of just file name ends
fileMatch: [currFileMatch.indexOf('/') === -1 ? '/' + currFileMatch : currFileMatch],
priority: SchemaPriority.SchemaStore,
});
}
}
Expand Down Expand Up @@ -185,15 +186,19 @@ export class SettingsHandler {

if (this.yamlSettings.schemaAssociations) {
if (Array.isArray(this.yamlSettings.schemaAssociations)) {
Array.prototype.push.apply(languageSettings.schemas, this.yamlSettings.schemaAssociations);
this.yamlSettings.schemaAssociations.forEach((association) => {
languageSettings = this.configureSchemas(
association.uri,
association.fileMatch,
association.schema,
languageSettings,
SchemaPriority.SchemaAssociation
);
});
} else {
for (const pattern in this.yamlSettings.schemaAssociations) {
const association = this.yamlSettings.schemaAssociations[pattern];
if (Array.isArray(association)) {
association.forEach((uri) => {
languageSettings = this.configureSchemas(uri, [pattern], null, languageSettings);
});
}
for (const uri in this.yamlSettings.schemaAssociations) {
const fileMatch = this.yamlSettings.schemaAssociations[uri];
languageSettings = this.configureSchemas(uri, fileMatch, null, languageSettings, SchemaPriority.SchemaAssociation);
}
}
}
Expand All @@ -212,7 +217,13 @@ export class SettingsHandler {
uri = relativeToAbsolutePath(this.yamlSettings.workspaceFolders, this.yamlSettings.workspaceRoot, uri);
}

languageSettings = this.configureSchemas(uri, schema.fileMatch, schema.schema, languageSettings);
languageSettings = this.configureSchemas(
uri,
schema.fileMatch,
schema.schema,
languageSettings,
SchemaPriority.Settings
);
}
});
}
Expand All @@ -235,13 +246,19 @@ export class SettingsHandler {
* @param languageSettings current server settings
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private configureSchemas(uri: string, fileMatch: string[], schema: any, languageSettings: LanguageSettings): LanguageSettings {
private configureSchemas(
uri: string,
fileMatch: string[],
schema: any,
languageSettings: LanguageSettings,
priorityLevel: number
): LanguageSettings {
uri = checkSchemaURI(this.yamlSettings.workspaceFolders, this.yamlSettings.workspaceRoot, uri);

if (schema === null) {
languageSettings.schemas.push({ uri, fileMatch: fileMatch });
languageSettings.schemas.push({ uri, fileMatch: fileMatch, priority: priorityLevel });
} else {
languageSettings.schemas.push({ uri, fileMatch: fileMatch, schema: schema });
languageSettings.schemas.push({ uri, fileMatch: fileMatch, schema: schema, priority: priorityLevel });
}

if (fileMatch.constructor === Array && uri === KUBERNETES_SCHEMA_URL) {
Expand Down
5 changes: 0 additions & 5 deletions src/languageserver/handlers/validationHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,6 @@ export class ValidationHandler {
return;
}

if (textDocument.getText().length === 0) {
this.connection.sendDiagnostics({ uri: textDocument.uri, diagnostics: [] });
return;
}

return this.languageService
.doValidation(textDocument, isKubernetesAssociatedDocument(textDocument, this.yamlSettings.specificValidatorPaths))
.then(
Expand Down
7 changes: 6 additions & 1 deletion src/languageservice/parser/yaml-documents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,12 @@ export class YamlDocuments {
}

if (this.cache.get(key).version !== document.version) {
const doc = parseYAML(document.getText(), customTags);
let text = document.getText();
// if text is contains only whitespace wrap all text in object to force schema selection
if (!/\S/.test(text)) {
text = `{${text}}`;
}
const doc = parseYAML(text, customTags);
this.cache.get(key).document = doc;
this.cache.get(key).version = document.version;
}
Expand Down
3 changes: 2 additions & 1 deletion src/yamlServerInit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ export class YAMLServerInit {
},
documentRangeFormattingProvider: false,
documentLinkProvider: {},
foldingRangeProvider: true,
// disabled until we not get parser which parse comments as separate nodes
foldingRangeProvider: false,
codeActionProvider: true,
codeLensProvider: {
resolveProvider: false,
Expand Down
58 changes: 58 additions & 0 deletions test/schemaValidation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
BlockMappingEntryError,
DuplicateKeyError,
propertyIsNotAllowed,
MissingRequiredPropWarning,
} from './utils/errorMessages';
import * as assert from 'assert';
import * as path from 'path';
Expand Down Expand Up @@ -1198,4 +1199,61 @@ describe('Validation Tests', () => {
]);
});
});

describe('Empty document validation', () => {
it('should provide validation for empty document', async () => {
languageService.addSchema(SCHEMA_ID, {
type: 'object',
properties: {
scripts: {
type: 'string',
},
},
required: ['scripts'],
});
const content = '';
const result = await parseSetup(content);
assert.strictEqual(result.length, 1);
assert.deepStrictEqual(
result[0],
createDiagnosticWithData(
MissingRequiredPropWarning.replace('{0}', 'scripts'),
0,
0,
0,
0,
DiagnosticSeverity.Error,
`yaml-schema: file:///${SCHEMA_ID}`,
`file:///${SCHEMA_ID}`
)
);
});

it('should provide validation for document which contains only whitespaces', async () => {
languageService.addSchema(SCHEMA_ID, {
type: 'object',
properties: {
scripts: {
type: 'string',
},
},
required: ['scripts'],
});
const content = ' \n \n';
const result = await parseSetup(content);
assert.deepStrictEqual(
result[0],
createDiagnosticWithData(
MissingRequiredPropWarning.replace('{0}', 'scripts'),
0,
0,
0,
1,
DiagnosticSeverity.Error,
`yaml-schema: file:///${SCHEMA_ID}`,
`file:///${SCHEMA_ID}`
)
);
});
});
});
80 changes: 78 additions & 2 deletions test/settingsHandlers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ import * as sinonChai from 'sinon-chai';
import { Connection } from 'vscode-languageserver';
import { SettingsState } from '../src/yamlSettings';
import { ValidationHandler } from '../src/languageserver/handlers/validationHandlers';
import { LanguageService } from '../src';
import { LanguageService, LanguageSettings, SchemaConfiguration, SchemaPriority } from '../src';
import * as request from 'request-light';
import { setupLanguageService } from './utils/testHelper';

const expect = chai.expect;
chai.use(sinonChai);
Expand All @@ -36,7 +37,7 @@ describe('Settings Handlers Tests', () => {
sandbox.restore();
});

it('SettingsHandler should modify file match patters', async () => {
it('SettingsHandler should modify file match patterns', async () => {
xhrStub.resolves({
responseText: `{"schemas": [
{
Expand All @@ -62,6 +63,81 @@ describe('Settings Handlers Tests', () => {
expect(settingsState.schemaStoreSettings).deep.include({
uri: 'https://raw.githubusercontent.com/adonisjs/application/master/adonisrc.schema.json',
fileMatch: ['/.adonisrc.yaml'],
priority: SchemaPriority.SchemaStore,
});
});

describe('Test that schema priorities are available', () => {
const testSchemaFileMatch = ['foo/*.yml'];
const testSchemaURI = 'file://foo.json';

function configureSchemaPriorityTest(): LanguageSettings {
const languageServerSetup = setupLanguageService({});

const languageService = languageServerSetup.languageService;
const settingsHandler = new SettingsHandler(
(connectionStub as unknown) as Connection,
languageService,
settingsState,
(validationHandler as unknown) as ValidationHandler
);

const configureSpy = sinon.spy(languageService, 'configure');
settingsHandler.updateConfiguration();

// Check things here
configureSpy.restore();
return configureSpy.args[0][0];
}

it('Schema Settings should have a priority', async () => {
settingsState.schemaConfigurationSettings = [
{
fileMatch: testSchemaFileMatch,
uri: testSchemaURI,
},
];

const configureSpy = configureSchemaPriorityTest();

expect(configureSpy.schemas).deep.include({
uri: testSchemaURI,
fileMatch: testSchemaFileMatch,
schema: undefined,
priority: SchemaPriority.Settings,
});
});

it('Schema Associations should have a priority when schema association is an array', async () => {
settingsState.schemaAssociations = [
{
fileMatch: testSchemaFileMatch,
uri: testSchemaURI,
},
] as SchemaConfiguration[];

const configureSpy = configureSchemaPriorityTest();

expect(configureSpy.schemas).deep.include({
uri: testSchemaURI,
fileMatch: testSchemaFileMatch,
schema: undefined,
priority: SchemaPriority.SchemaAssociation,
});
});

it('Schema Associations should have a priority when schema association is a record', async () => {
settingsState.schemaAssociations = {
[testSchemaURI]: testSchemaFileMatch,
} as Record<string, string[]>;

const configureSpy = configureSchemaPriorityTest();

expect(configureSpy.schemas).deep.include({
uri: testSchemaURI,
fileMatch: testSchemaFileMatch,
priority: SchemaPriority.SchemaAssociation,
});
});
});
});

0 comments on commit 230e8f8

Please sign in to comment.