Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added function to register and clear external schema in the language service Interface #187

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
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), []);

});

});