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 language setting option to skip runtime schema compilation #980

Closed
wants to merge 1 commit into from
Closed
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
30 changes: 25 additions & 5 deletions src/languageservice/services/yamlSchemaService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*--------------------------------------------------------------------------------------------*/

import { JSONSchema, JSONSchemaMap, JSONSchemaRef } from '../jsonSchema';
import { SchemaPriority, SchemaRequestService, WorkspaceContextService } from '../yamlLanguageService';
import { LanguageSettings, SchemaPriority, SchemaRequestService, WorkspaceContextService } from '../yamlLanguageService';
import {
UnresolvedSchema,
ResolvedSchema,
Expand All @@ -27,7 +27,7 @@ import { getSchemaFromModeline } from './modelineUtil';
import { JSONSchemaDescriptionExt } from '../../requestTypes';
import { SchemaVersions } from '../yamlTypes';

import Ajv, { DefinedError } from 'ajv';
import Ajv, { DefinedError, ValidateFunction } from 'ajv';
import { getSchemaTitle } from '../utils/schemaUtils';

const localize = nls.loadMessageBundle();
Expand All @@ -37,7 +37,8 @@ const ajv = new Ajv();
// load JSON Schema 07 def to validate loaded schemas
// eslint-disable-next-line @typescript-eslint/no-var-requires
const jsonSchema07 = require('ajv/dist/refs/json-schema-draft-07.json');
const schema07Validator = ajv.compile(jsonSchema07);

var schema07Validator: ValidateFunction;

export declare type CustomSchemaProvider = (uri: string) => Promise<string | string[]>;

Expand Down Expand Up @@ -111,6 +112,7 @@ export class YAMLSchemaService extends JSONSchemaService {
public schemaPriorityMapping: Map<string, Set<SchemaPriority>>;

private schemaUriToNameAndDescription = new Map<string, SchemaStoreSchema>();
private skipSchemaValidation: boolean;

constructor(
requestService: SchemaRequestService,
Expand All @@ -121,6 +123,13 @@ export class YAMLSchemaService extends JSONSchemaService {
this.customSchemaProvider = undefined;
this.requestService = requestService;
this.schemaPriorityMapping = new Map();
this.skipSchemaValidation = false;
}

configure(languageSettings: LanguageSettings): void {
if (languageSettings) {
this.skipSchemaValidation = languageSettings.skipSchemaValidation;
}
}

registerCustomSchemaProvider(customSchemaProvider: CustomSchemaProvider): void {
Expand Down Expand Up @@ -155,6 +164,16 @@ export class YAMLSchemaService extends JSONSchemaService {
return result;
}

private getSchemaValidator(): ValidateFunction | undefined {
if (this.skipSchemaValidation) {
return undefined;
}
if (!schema07Validator) {
schema07Validator = ajv.compile(jsonSchema07);
}
return schema07Validator;
}

async resolveSchemaContent(
schemaToResolve: UnresolvedSchema,
schemaURL: string,
Expand All @@ -164,9 +183,10 @@ export class YAMLSchemaService extends JSONSchemaService {
let schema: JSONSchema = schemaToResolve.schema;
const contextService = this.contextService;

if (!schema07Validator(schema)) {
const schemaValidator = this.getSchemaValidator();
if (schemaValidator && !schemaValidator(schema)) {
const errs: string[] = [];
for (const err of schema07Validator.errors as DefinedError[]) {
for (const err of schemaValidator.errors as DefinedError[]) {
errs.push(`${err.instancePath} : ${err.message}`);
}
resolveErrors.push(`Schema '${getSchemaTitle(schemaToResolve.schema, schemaURL)}' is not valid:\n${errs.join('\n')}`);
Expand Down
5 changes: 5 additions & 0 deletions src/languageservice/yamlLanguageService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ export interface LanguageSettings {
* If set enforce alphabetical ordering of keys in mappings.
*/
keyOrdering?: boolean;
/**
* If set skip json schema validation. Allows to not use unsafe-eval rule
*/
skipSchemaValidation?: boolean;
}

export interface WorkspaceContextService {
Expand Down Expand Up @@ -204,6 +208,7 @@ export function getLanguageService(params: {

return {
configure: (settings) => {
schemaService.configure(settings);
schemaService.clearExternalSchemas();
if (settings.schemas) {
schemaService.schemaPriorityMapping = new Map();
Expand Down
18 changes: 18 additions & 0 deletions test/schemaValidation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1847,6 +1847,24 @@ obj:
});
});

describe('Skip json schema validation with enabled skipSchemaValidation', () => {
before(() => {
languageSettingsSetup.languageSettings.skipSchemaValidation = true;
languageService.configure(languageSettingsSetup.languageSettings);
});
after(() => {
languageSettingsSetup.languageSettings.skipSchemaValidation = false;
});
it('should handle not valid schema object', async () => {
const schema = 'Foo';
schemaProvider.addSchema(SCHEMA_ID, schema as JSONSchema);
const content = `foo: bar`;
const result = await parseSetup(content);
expect(result).to.be.empty;
expect(telemetry.messages).to.be.empty;
});
})

describe('Enum tests', () => {
afterEach(() => {
schemaProvider.deleteSchema(SCHEMA_ID);
Expand Down
1 change: 1 addition & 0 deletions test/utils/serviceSetup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export class ServiceSetup {
yamlVersion: '1.2',
flowMapping: 'allow',
flowSequence: 'allow',
skipSchemaValidation: false
};

withValidate(): ServiceSetup {
Expand Down
Loading