Skip to content

Commit ae5acdb

Browse files
committed
add support and tests for dependentSchemas, dependentRequired, and dependencies for backward compatibility
Signed-off-by: Morgan Chang <[email protected]>
1 parent 73e0464 commit ae5acdb

File tree

2 files changed

+178
-1
lines changed

2 files changed

+178
-1
lines changed

src/languageservice/parser/schemaValidation/draft04Validator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { BaseValidator } from './baseValidator';
99

1010
/**
1111
* Keyword: exclusiveMinimum/exclusiveMaximum
12-
*
12+
*
1313
* Booleans that make minimum/maximum exclusive.
1414
*/
1515
export class Draft04Validator extends BaseValidator {

test/schema2019Validation.test.ts

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,4 +324,181 @@ describe('Validation Tests', () => {
324324
expect(result[0].message).to.include('Expected 1 or more.');
325325
});
326326
});
327+
328+
describe('keyword: dependentRequired', () => {
329+
beforeEach(() => {
330+
schemaProvider.addSchema(SCHEMA_ID, {
331+
$schema: 'https://json-schema.org/draft/2019-09/schema',
332+
type: 'object',
333+
properties: {
334+
billing_address: { type: 'string' },
335+
credit_card: { type: 'string' },
336+
},
337+
dependentRequired: {
338+
billing_address: ['credit_card'],
339+
},
340+
} as JSONSchema);
341+
});
342+
it('requires dependent properties when the trigger property is present', async () => {
343+
const content = `billing_address: "123 King St"`;
344+
const result = await parseSetup(content);
345+
346+
expect(result).to.have.length(1);
347+
expect(result[0].message).to.include('Object is missing property credit_card required by property billing_address.');
348+
});
349+
it('passes when required dependent properties are present', async () => {
350+
const content = `billing_address: "123 King St"\ncredit_card: "4111-1111"`;
351+
const result = await parseSetup(content);
352+
353+
expect(result).to.be.empty;
354+
});
355+
});
356+
357+
describe('keyword: dependentSchemas', () => {
358+
it('does not apply when the trigger property is absent', async () => {
359+
schemaProvider.addSchema(SCHEMA_ID, {
360+
$schema: 'https://json-schema.org/draft/2019-09/schema',
361+
type: 'object',
362+
properties: {
363+
kind: { type: 'string' },
364+
port: { type: 'number' },
365+
},
366+
dependentSchemas: {
367+
kind: { required: ['port'] },
368+
},
369+
} as JSONSchema);
370+
const content = `port: 8080`;
371+
const result = await parseSetup(content);
372+
expect(result).to.be.empty;
373+
});
374+
it('applies dependent schema when the trigger property is present', async () => {
375+
schemaProvider.addSchema(SCHEMA_ID, {
376+
$schema: 'https://json-schema.org/draft/2019-09/schema',
377+
type: 'object',
378+
properties: {
379+
kind: { type: 'string' },
380+
port: { type: 'number' },
381+
},
382+
dependentSchemas: {
383+
kind: { required: ['port'] },
384+
},
385+
} as JSONSchema);
386+
const content = `kind: service`;
387+
const result = await parseSetup(content);
388+
expect(result).to.have.length(1);
389+
expect(result[0].message).to.include('Missing property');
390+
expect(result[0].message).to.include('port');
391+
});
392+
it('can enforce additional constraints from the dependent schema', async () => {
393+
schemaProvider.addSchema(SCHEMA_ID, {
394+
$schema: 'https://json-schema.org/draft/2019-09/schema',
395+
type: 'object',
396+
properties: {
397+
tls: { type: 'boolean' },
398+
port: { type: 'number' },
399+
},
400+
dependentSchemas: {
401+
tls: {
402+
required: ['port'],
403+
properties: {
404+
port: { minimum: 1024 },
405+
},
406+
},
407+
},
408+
} as JSONSchema);
409+
const content = `tls: true\nport: 80`;
410+
const result = await parseSetup(content);
411+
expect(result).to.have.length(1);
412+
expect(result[0].message).to.include('Value is below the minimum of 1024.');
413+
});
414+
it('applies multiple dependentSchemas when multiple triggers are present', async () => {
415+
schemaProvider.addSchema(SCHEMA_ID, {
416+
$schema: 'https://json-schema.org/draft/2019-09/schema',
417+
type: 'object',
418+
properties: {
419+
kind: { type: 'string' },
420+
tls: { type: 'boolean' },
421+
port: { type: 'number' },
422+
},
423+
dependentSchemas: {
424+
kind: { required: ['port'] },
425+
tls: {
426+
required: ['port'],
427+
properties: { port: { minimum: 1024 } },
428+
},
429+
},
430+
} as JSONSchema);
431+
const content = `kind: service\ntls: true\nport: 80`;
432+
const result = await parseSetup(content);
433+
expect(result).to.have.length(1);
434+
expect(result[0].message).to.include('Value is below the minimum of 1024.');
435+
});
436+
});
437+
438+
describe('keyword: dependencies (backward compatibility)', () => {
439+
describe('property dependencies tests', () => {
440+
beforeEach(() => {
441+
schemaProvider.addSchema(SCHEMA_ID, {
442+
$schema: 'http://json-schema.org/draft-07/schema#',
443+
type: 'object',
444+
properties: {
445+
credit_card: { type: 'string' },
446+
billing_address: { type: 'string' },
447+
},
448+
dependencies: {
449+
credit_card: ['billing_address'],
450+
},
451+
} as JSONSchema);
452+
});
453+
it('requires dependent properties when the trigger property is present', async () => {
454+
const content = `credit_card: "4111-1111-1111-1111"`;
455+
const result = await parseSetup(content);
456+
expect(result).to.have.length(1);
457+
expect(result[0].message).to.include('Object is missing property billing_address required by property credit_card.');
458+
});
459+
it('does not apply when the trigger property is absent', async () => {
460+
const content = `billing_address: "123 Main St"`;
461+
const result = await parseSetup(content);
462+
expect(result).to.be.empty;
463+
});
464+
});
465+
});
466+
describe('schema dependencies tests', () => {
467+
beforeEach(() => {
468+
schemaProvider.addSchema(SCHEMA_ID, {
469+
$schema: 'http://json-schema.org/draft-07/schema#',
470+
type: 'object',
471+
properties: {
472+
mode: { type: 'string' },
473+
port: { type: 'number' },
474+
},
475+
dependencies: {
476+
mode: {
477+
required: ['port'],
478+
properties: {
479+
port: { minimum: 1024 },
480+
},
481+
},
482+
},
483+
} as JSONSchema);
484+
});
485+
it('enforces dependent schema constraints when trigger property is present', async () => {
486+
const content = `mode: "server"\nport: 80`;
487+
const result = await parseSetup(content);
488+
expect(result).to.have.length(1);
489+
expect(result[0].message).to.include('Value is below the minimum of 1024.');
490+
});
491+
it('enforces dependent schema required properties when trigger property is present', async () => {
492+
const content = `mode: "server"`;
493+
const result = await parseSetup(content);
494+
expect(result).to.have.length(1);
495+
expect(result[0].message).to.include('Missing property');
496+
expect(result[0].message).to.include('port');
497+
});
498+
it('does not apply the dependent schema when trigger property is absent', async () => {
499+
const content = `port: 80`;
500+
const result = await parseSetup(content);
501+
expect(result).to.be.empty;
502+
});
503+
});
327504
});

0 commit comments

Comments
 (0)