Skip to content

Commit

Permalink
feat(json-schema): add support for uniqueItems (#1812)
Browse files Browse the repository at this point in the history
  • Loading branch information
aitboudad committed Sep 29, 2019
1 parent 6258cf8 commit 9164c74
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 9 deletions.
1 change: 1 addition & 0 deletions demo/src/app/examples/advanced/json-schema/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export function exclusiveMaximumValidationMessage(err, field: FormlyFieldConfig)
{ name: 'exclusiveMaximum', message: exclusiveMaximumValidationMessage },
{ name: 'minItems', message: minItemsValidationMessage },
{ name: 'maxItems', message: maxItemsValidationMessage },
{ name: 'uniqueItems', message: 'should NOT have duplicate items' },
],
types: [
{ name: 'string', extends: 'input' },
Expand Down
24 changes: 21 additions & 3 deletions src/core/json-schema/src/formly-json-schema.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ describe('Service: FormlyJsonschema', () => {
});
});

// TODO: Add support for uniqueItems, contains
// TODO: Add support for contains
// https://json-schema.org/latest/json-schema-validation.html#rfc.section.6.4
describe('array validation keywords', () => {
it('supports array items keyword as object', () => {
Expand Down Expand Up @@ -250,6 +250,24 @@ describe('Service: FormlyJsonschema', () => {
expect(maxItemsValidator(new FormControl([1, 2]))).toBeTruthy();
expect(maxItemsValidator(new FormControl([]))).toBeTruthy();
});

it('should support uniqueItems', () => {
const numSchema: JSONSchema7 = {
type: 'array',
uniqueItems: true,
};
const config = formlyJsonschema.toFieldConfig(numSchema);
expect(config.templateOptions.uniqueItems).toBeTruthy();

const uniqueItemsValidator = config.validators.uniqueItems;
expect(uniqueItemsValidator).toBeDefined();
expect(uniqueItemsValidator(new FormControl(null))).toBeTruthy();
expect(uniqueItemsValidator(new FormControl([1, 2, 3]))).toBeTruthy();
expect(uniqueItemsValidator(new FormControl([1, 2, 2]))).toBeFalsy();

expect(uniqueItemsValidator(new FormControl([{ a: 2 }, { a: 1 }]))).toBeTruthy();
expect(uniqueItemsValidator(new FormControl([{ a: 1 }, { a: 1 }]))).toBeFalsy();
});
});

// TODO: complete support for Object validation keywords
Expand Down Expand Up @@ -774,9 +792,9 @@ describe('Service: FormlyJsonschema', () => {
});

describe('merges conflict', () => {
xit('uniqueItems', () => {
it('uniqueItems', () => {
const schema: JSONSchema7 = {
type: 'string',
type: 'array',
allOf: [
{ uniqueItems: false },
{ uniqueItems: true },
Expand Down
26 changes: 20 additions & 6 deletions src/core/json-schema/src/formly-json-schema.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export class FormlyJsonschema {

switch (field.type) {
case 'null': {
this.addValidator(field, 'null', c => c.value === null);
this.addValidator(field, 'null', ({ value }) => value === null);
break;
}
case 'number':
Expand All @@ -58,17 +58,17 @@ export class FormlyJsonschema {

if (schema.hasOwnProperty('exclusiveMinimum')) {
field.templateOptions.exclusiveMinimum = schema.exclusiveMinimum;
this.addValidator(field, 'exclusiveMinimum', c => isEmpty(c.value) || (c.value > schema.exclusiveMinimum));
this.addValidator(field, 'exclusiveMinimum', ({ value }) => isEmpty(value) || (value > schema.exclusiveMinimum));
}

if (schema.hasOwnProperty('exclusiveMaximum')) {
field.templateOptions.exclusiveMaximum = schema.exclusiveMaximum;
this.addValidator(field, 'exclusiveMaximum', c => isEmpty(c.value) || (c.value < schema.exclusiveMaximum));
this.addValidator(field, 'exclusiveMaximum', ({ value }) => isEmpty(value) || (value < schema.exclusiveMaximum));
}

if (schema.hasOwnProperty('multipleOf')) {
field.templateOptions.step = schema.multipleOf;
this.addValidator(field, 'multipleOf', c => isEmpty(c.value) || (c.value % schema.multipleOf === 0));
this.addValidator(field, 'multipleOf', ({ value }) => isEmpty(value) || (value % schema.multipleOf === 0));
}
break;
}
Expand Down Expand Up @@ -116,11 +116,25 @@ export class FormlyJsonschema {

if (schema.hasOwnProperty('minItems')) {
field.templateOptions.minItems = schema.minItems;
this.addValidator(field, 'minItems', c => isEmpty(c.value) || (c.value.length >= schema.minItems));
this.addValidator(field, 'minItems', ({ value }) => isEmpty(value) || (value.length >= schema.minItems));
}
if (schema.hasOwnProperty('maxItems')) {
field.templateOptions.maxItems = schema.maxItems;
this.addValidator(field, 'maxItems', c => isEmpty(c.value) || (c.value.length <= schema.maxItems));
this.addValidator(field, 'maxItems', ({ value }) => isEmpty(value) || (value.length <= schema.maxItems));
}
if (schema.hasOwnProperty('uniqueItems')) {
field.templateOptions.uniqueItems = schema.uniqueItems;
this.addValidator(field, 'uniqueItems', ({ value }) => {
if (isEmpty(value) || !schema.uniqueItems) {
return true;
}

const uniqueItems = Array.from(
new Set(value.map((v: any) => JSON.stringify(v))),
);

return uniqueItems.length === value.length;
});
}

Object.defineProperty(field, 'fieldArray', {
Expand Down

0 comments on commit 9164c74

Please sign in to comment.