Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/jsonLanguageService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { JSONValidation } from './services/jsonValidation';
import { JSONDocumentSymbols } from './services/jsonDocumentSymbols';
import { parse as parseJSON, newJSONDocument } from './parser/jsonParser';
import { schemaContributions } from './services/configuration';
import { JSONSchemaService } from './services/jsonSchemaService';
import { ISchemaHandle, JSONSchemaService } from './services/jsonSchemaService';
import { getFoldingRanges } from './services/jsonFolding';
import { getSelectionRanges } from './services/jsonSelectionRanges';
import { sort } from './utils/sort';
Expand All @@ -24,7 +24,7 @@ import {
FoldingRange, JSONSchema, SelectionRange, FoldingRangesContext, DocumentSymbolsContext, ColorInformationContext as DocumentColorsContext,
TextDocument,
Position, CompletionItem, CompletionList, Hover, Range, SymbolInformation, Diagnostic,
TextEdit, FormattingOptions, DocumentSymbol, DefinitionLink, MatchingSchema, JSONLanguageStatus, SortOptions
TextEdit, FormattingOptions, DocumentSymbol, DefinitionLink, MatchingSchema, JSONLanguageStatus, SortOptions, SchemaConfiguration
} from './jsonLanguageTypes';
import { findLinks } from './services/jsonLinks';
import { DocumentLink } from 'vscode-languageserver-types';
Expand All @@ -41,6 +41,8 @@ export interface LanguageService {
parseJSONDocument(document: TextDocument): JSONDocument;
newJSONDocument(rootNode: ASTNode, syntaxDiagnostics?: Diagnostic[]): JSONDocument;
resetSchema(uri: string): boolean;
registerExternalSchema(config: SchemaConfiguration): ISchemaHandle;
clearExternalSchema(uri:string): void;
getMatchingSchemas(document: TextDocument, jsonDocument: JSONDocument, schema?: JSONSchema): Thenable<MatchingSchema[]>;
getLanguageStatus(document: TextDocument, jsonDocument: JSONDocument): JSONLanguageStatus;
doResolve(item: CompletionItem): Thenable<CompletionItem>;
Expand Down Expand Up @@ -77,6 +79,8 @@ export function getLanguageService(params: LanguageServiceParams): LanguageServi
jsonValidation.configure(settings);
},
resetSchema: (uri: string) => jsonSchemaService.onResourceChange(uri),
registerExternalSchema: jsonSchemaService.registerExternalSchema.bind(jsonSchemaService),
clearExternalSchema: jsonSchemaService.clearExternalSchema.bind(jsonSchemaService),
doValidation: jsonValidation.doValidation.bind(jsonValidation),
getLanguageStatus: jsonValidation.getLanguageStatus.bind(jsonValidation),
parseJSONDocument: (document: TextDocument) => parseJSON(document, { collectComments: true }),
Expand Down
17 changes: 17 additions & 0 deletions src/services/jsonSchemaService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ export interface IJSONSchemaService {
*/
registerExternalSchema(config: SchemaConfiguration): ISchemaHandle;

/**
* Clear a secific schema
*/
clearExternalSchema(uri:string): void;

/**
* Clears all cached schema files
*/
Expand Down Expand Up @@ -361,6 +366,18 @@ export class JSONSchemaService implements IJSONSchemaService {
return config.schema ? this.addSchemaHandle(id, config.schema) : this.getOrAddSchemaHandle(id);
}

public clearExternalSchema(uri: string): void {
const normalizedUri = normalizeId(uri);
if (this.schemasById[normalizedUri] && this.registeredSchemasIds[normalizedUri]) {
delete this.schemasById[normalizedUri];
delete this.registeredSchemasIds[normalizedUri];
this.filePatternAssociations = this.filePatternAssociations.filter(
(association) => !association.getURIs().includes(normalizedUri)
);
this.cachedSchemaForResource = undefined;
}
}

public clearExternalSchemas(): void {
this.schemasById = {};
this.filePatternAssociations = [];
Expand Down
105 changes: 105 additions & 0 deletions src/test/schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1037,6 +1037,53 @@ suite('JSON Schema', () => {

});

test('Clear specific Schema',async function(){
const service = new SchemaService.JSONSchemaService(newMockRequestService(), workspaceContext);
const id1 = 'http://myschemastore/test1';
const schema1: JSONSchema = {
type: 'object',
properties: {
child: {
type: 'number'
}
}
};

const id2 = 'http://myschemastore/test2';
const schema2: JSONSchema = {
type: 'object',
properties: {
child: {
type: 'string'
}
}
};

const id3 = 'http://myschemastore/test3';
const schema3: JSONSchema = {
type: 'object',
properties: {
child: {
type: 'boolean'
}
}
};

service.registerExternalSchema({ uri: id1, schema: schema1,fileMatch:['*.json'] });
service.registerExternalSchema({ uri: id2, schema: schema2,fileMatch:['*.json'] });
service.registerExternalSchema({ uri: id3, schema: schema3,fileMatch:['*.json'] });

let resolvedSchema = await service.getSchemaForResource('main.json');
assert.deepStrictEqual(resolvedSchema?.errors, []);
assert.strictEqual(3, resolvedSchema?.schema.allOf?.length);
service.clearExternalSchema(id1);

resolvedSchema = await service.getSchemaForResource('main.json');
assert.deepStrictEqual(resolvedSchema?.errors, []);
assert.strictEqual(2, resolvedSchema?.schema.allOf?.length);

});

test('Schema contributions', async function () {
const service = new SchemaService.JSONSchemaService(newMockRequestService(), workspaceContext);

Expand Down Expand Up @@ -1976,4 +2023,62 @@ suite('JSON Schema', () => {

});

test('Validation on Multiple Schemas',async function(){
const id1 = 'http://myschemastore/test1';
const schema1: JSONSchema = {
type: 'object',
properties: {
foo: {
type: 'number'
}
},
required:['foo']
};

const id2 = 'http://myschemastore/test2';
const schema2: JSONSchema = {
type: 'object',
properties: {
bar: {
type: 'number'
}
},
required:['bar']
};

const id3 = 'http://myschemastore/test3';
const schema3: JSONSchema = {
type: 'object',
properties: {
foobar: {
type: 'number'
}
},
required:['foobar']
};

const testDoc = toDocument(JSON.stringify({}),{},'main.json');

const ls = getLanguageService({ workspaceContext });
ls.registerExternalSchema({ uri: id1, schema: schema1,fileMatch:['*.json'] });
ls.registerExternalSchema({ uri: id2, schema: schema2,fileMatch:['*.json'] });
ls.registerExternalSchema({ uri: id3, schema: schema3,fileMatch:['*.json'] });

let validation = await ls.doValidation(testDoc.textDoc, testDoc.jsonDoc);
assert.deepStrictEqual(validation.length, 3);
assert.deepStrictEqual(validation.map(v => v.message), ['Missing property "foo".','Missing property "bar".','Missing property "foobar".']);

ls.clearExternalSchema(id1);
validation = await ls.doValidation(testDoc.textDoc, testDoc.jsonDoc);
assert.deepStrictEqual(validation.length, 2);
assert.deepStrictEqual(validation.map(v => v.message), ['Missing property "bar".','Missing property "foobar".']);

ls.clearExternalSchema(id2);
ls.clearExternalSchema(id3);
validation = await ls.doValidation(testDoc.textDoc, testDoc.jsonDoc);
assert.deepStrictEqual(validation.length, 0);
assert.deepStrictEqual(validation.map(v => v.message), []);

});

});