Skip to content

Commit 6767a56

Browse files
committed
add basic support for declaring schema with inline $schema
1 parent dfccc6f commit 6767a56

File tree

2 files changed

+64
-20
lines changed

2 files changed

+64
-20
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Red Hat, Inc. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { SingleYAMLDocument } from '../parser/yamlParser07';
7+
import { JSONDocument } from '../parser/jsonParser07';
8+
9+
/**
10+
* Retrieve schema if declared by `$schema`.
11+
* Public for testing purpose, not part of the API.
12+
* @param doc
13+
*/
14+
export function getDollarSchema(doc: SingleYAMLDocument | JSONDocument): string | undefined {
15+
if (doc instanceof SingleYAMLDocument && doc.root && doc.root.type === 'object') {
16+
let dollarSchema = doc.root.properties['$schema'];
17+
dollarSchema = typeof dollarSchema === 'string' ? dollarSchema.trim() : undefined;
18+
if (typeof dollarSchema === 'string') {
19+
return dollarSchema.trim();
20+
}
21+
if (dollarSchema) {
22+
console.log('The $schema attribute is not a string, and will be ignored');
23+
}
24+
}
25+
return undefined;
26+
}

src/languageservice/services/yamlSchemaService.ts

+38-20
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import { SchemaVersions } from '../yamlTypes';
2929

3030
import Ajv, { DefinedError } from 'ajv';
3131
import { getSchemaTitle } from '../utils/schemaUtils';
32+
import { getDollarSchema } from './dollarUtils';
3233

3334
const localize = nls.loadMessageBundle();
3435

@@ -343,33 +344,46 @@ export class YAMLSchemaService extends JSONSchemaService {
343344
}
344345

345346
public getSchemaForResource(resource: string, doc: JSONDocument): Promise<ResolvedSchema> {
347+
const normalizeSchemaRef = (schemaRef: string): string | undefined => {
348+
if (!schemaRef.startsWith('file:') && !schemaRef.startsWith('http')) {
349+
// If path contains a fragment and it is left intact, "#" will be
350+
// considered part of the filename and converted to "%23" by
351+
// path.resolve() -> take it out and add back after path.resolve
352+
let appendix = '';
353+
if (schemaRef.indexOf('#') > 0) {
354+
const segments = schemaRef.split('#', 2);
355+
schemaRef = segments[0];
356+
appendix = segments[1];
357+
}
358+
if (!path.isAbsolute(schemaRef)) {
359+
const resUri = URI.parse(resource);
360+
schemaRef = URI.file(path.resolve(path.parse(resUri.fsPath).dir, schemaRef)).toString();
361+
} else {
362+
schemaRef = URI.file(schemaRef).toString();
363+
}
364+
if (appendix.length > 0) {
365+
schemaRef += '#' + appendix;
366+
}
367+
}
368+
return schemaRef;
369+
};
370+
346371
const resolveModelineSchema = (): string | undefined => {
347372
let schemaFromModeline = getSchemaFromModeline(doc);
348373
if (schemaFromModeline !== undefined) {
349-
if (!schemaFromModeline.startsWith('file:') && !schemaFromModeline.startsWith('http')) {
350-
// If path contains a fragment and it is left intact, "#" will be
351-
// considered part of the filename and converted to "%23" by
352-
// path.resolve() -> take it out and add back after path.resolve
353-
let appendix = '';
354-
if (schemaFromModeline.indexOf('#') > 0) {
355-
const segments = schemaFromModeline.split('#', 2);
356-
schemaFromModeline = segments[0];
357-
appendix = segments[1];
358-
}
359-
if (!path.isAbsolute(schemaFromModeline)) {
360-
const resUri = URI.parse(resource);
361-
schemaFromModeline = URI.file(path.resolve(path.parse(resUri.fsPath).dir, schemaFromModeline)).toString();
362-
} else {
363-
schemaFromModeline = URI.file(schemaFromModeline).toString();
364-
}
365-
if (appendix.length > 0) {
366-
schemaFromModeline += '#' + appendix;
367-
}
368-
}
374+
schemaFromModeline = normalizeSchemaRef(schemaFromModeline);
369375
return schemaFromModeline;
370376
}
371377
};
372378

379+
const resolveDollarSchema = (): string | undefined => {
380+
let dollarSchema = getDollarSchema(doc);
381+
if (dollarSchema !== undefined) {
382+
dollarSchema = normalizeSchemaRef(dollarSchema);
383+
return dollarSchema;
384+
}
385+
};
386+
373387
const resolveSchemaForResource = (schemas: string[]): Promise<ResolvedSchema> => {
374388
const schemaHandle = super.createCombinedSchema(resource, schemas);
375389
return schemaHandle.getResolvedSchema().then((schema) => {
@@ -416,6 +430,10 @@ export class YAMLSchemaService extends JSONSchemaService {
416430
if (modelineSchema) {
417431
return resolveSchemaForResource([modelineSchema]);
418432
}
433+
const dollarSchema = resolveDollarSchema();
434+
if (dollarSchema) {
435+
return resolveSchemaForResource([dollarSchema]);
436+
}
419437
if (this.customSchemaProvider) {
420438
return this.customSchemaProvider(resource)
421439
.then((schemaUri) => {

0 commit comments

Comments
 (0)