diff --git a/src/languageservice/services/yamlSchemaService.ts b/src/languageservice/services/yamlSchemaService.ts index cf39361e..a55704a8 100644 --- a/src/languageservice/services/yamlSchemaService.ts +++ b/src/languageservice/services/yamlSchemaService.ts @@ -295,21 +295,23 @@ export class YAMLSchemaService extends JSONSchemaService { } /** - * Retrieve schema if declared as modeline + * Retrieve schema if declared as modeline. + * Public for testing purpose, not part of the API. * @param doc */ - private getSchemaFromModeline(doc: any) : string{ + public getSchemaFromModeline(doc: any) : string{ if (doc instanceof SingleYAMLDocument) { - const modelineDeclaration = '# yaml-language-server:'; - const yamlLanguageServerModeline = doc.lineComments.find(lineComment => lineComment.startsWith(modelineDeclaration)); + const yamlLanguageServerModeline = doc.lineComments.find(lineComment => { + const matchModeline = lineComment.match(/^#\s+yaml-language-server\s*:/g); + return matchModeline !== null && matchModeline.length === 1; + }); if (yamlLanguageServerModeline != undefined) { - const schemaKey = '$schema='; - const indexOfJsonSchemaParameter = yamlLanguageServerModeline.indexOf(schemaKey); - if (indexOfJsonSchemaParameter !== -1) { - const startIndex = indexOfJsonSchemaParameter + schemaKey.length; - const indexOfNextSpace = yamlLanguageServerModeline.indexOf(' ', startIndex); - const endIndex = indexOfNextSpace !== -1 ? indexOfNextSpace : yamlLanguageServerModeline.length; - return yamlLanguageServerModeline.substring(startIndex, endIndex); + const schemaMatchs = yamlLanguageServerModeline.match(/\$schema=\S+/g); + if(schemaMatchs !== null && schemaMatchs.length >= 1) { + if (schemaMatchs.length >= 2) { + console.log('Several $schema attributes has been found on the yaml-language-server modeline. The first one will be picked.'); + } + return schemaMatchs[0].substring('$schema='.length); } } } diff --git a/test/schema.test.ts b/test/schema.test.ts index 3bc24a9d..d0961a79 100644 --- a/test/schema.test.ts +++ b/test/schema.test.ts @@ -1,6 +1,7 @@ 'use strict'; import assert = require('assert'); +import * as parser from '../src/languageservice/parser/yamlParser07'; import * as SchemaService from '../src/languageservice/services/yamlSchemaService'; import * as JsonSchema from '../src/languageservice/jsonSchema'; import url = require('url'); @@ -475,4 +476,59 @@ suite('JSON Schema', () => { const hello_world_schema = await service.getResolvedSchema('hello_world'); assert.equal(hello_world_schema, null); }); + + describe('Test getSchemaFromModeline', function () { + + test('simple case', async() => { + checkReturnSchemaUrl('# yaml-language-server: $schema=expectedUrl', 'expectedUrl'); + }); + + test('with several spaces between # and yaml-language-server', async() => { + checkReturnSchemaUrl('# yaml-language-server: $schema=expectedUrl', 'expectedUrl'); + }); + + test('with several spaces between yaml-language-server and :', async() => { + checkReturnSchemaUrl('# yaml-language-server : $schema=expectedUrl', 'expectedUrl'); + }); + + test('with several spaces between : and $schema', async() => { + checkReturnSchemaUrl('# yaml-language-server: $schema=expectedUrl', 'expectedUrl'); + }); + + test('with several spaces at the end', async() => { + checkReturnSchemaUrl('# yaml-language-server: $schema=expectedUrl ', 'expectedUrl'); + }); + + test('with several spaces at several places', async() => { + checkReturnSchemaUrl('# yaml-language-server : $schema=expectedUrl ', 'expectedUrl'); + }); + + test('with several attributes', async() => { + checkReturnSchemaUrl('# yaml-language-server: anotherAttribute=test $schema=expectedUrl aSecondAttribtute=avalue', 'expectedUrl'); + }); + + test('with tabs', async() => { + checkReturnSchemaUrl('#\tyaml-language-server:\t$schema=expectedUrl', 'expectedUrl'); + }); + + test('with several $schema - pick the first', async() => { + checkReturnSchemaUrl('# yaml-language-server: $schema=url1 $schema=url2', 'url1'); + }); + + test('no schema returned if not yaml-language-server', async() => { + checkReturnSchemaUrl('# somethingelse: $schema=url1', undefined); + }); + + test('no schema returned if not $schema', async() => { + checkReturnSchemaUrl('# yaml-language-server: $notschema=url1', undefined); + }); + + function checkReturnSchemaUrl(modeline: string, expectedResult: string) { + const service = new SchemaService.YAMLSchemaService(schemaRequestServiceForURL, workspaceContext); + const yamlDoc = new parser.SingleYAMLDocument([]); + yamlDoc.lineComments = [modeline]; + assert.equal(service.getSchemaFromModeline(yamlDoc), expectedResult); + } + }); }); +