diff --git a/README.md b/README.md
index bcf2be5..24afc89 100644
--- a/README.md
+++ b/README.md
@@ -118,3 +118,23 @@ isSubset(
```
You can find more examples in the unit tests.
+
+### Options
+#### noAdditionalProperties
+Add `additionalProperties=false` to all object types
+```ts
+import { createSchema } from 'genson-js';
+const schema = createSchema({ one: 1, two: 'second' }, { noAdditionalProperties: true });
+```
+The following schema will be created:
+```ts
+{
+ type: 'object',
+ additionalProperties: false,
+ properties: { one: { type: 'integer' }, two: { type: 'string' } },
+ required: [
+ "one",
+ "two",
+ ]
+}
+```
\ No newline at end of file
diff --git a/src/schema-builder.ts b/src/schema-builder.ts
index 6510d3b..e92fb56 100644
--- a/src/schema-builder.ts
+++ b/src/schema-builder.ts
@@ -28,6 +28,9 @@ function createSchemaForArray(arr: Array, options?: SchemaGenOptions): Sche
}
const elementSchemas = arr.map((value) => createSchemaFor(value, options));
const items = combineSchemas(elementSchemas);
+ if(options?.noAdditionalProperties){
+ addNoAddtionalProperties(items);
+ }
return { type: ValueType.Array, items };
}
@@ -47,6 +50,9 @@ function createSchemaForObject(obj: Object, options?: SchemaGenOptions): Schema
if (!options?.noRequired) {
schema.required = keys;
}
+ if(options?.noAdditionalProperties){
+ addNoAddtionalProperties(schema);
+ }
return schema;
}
@@ -251,3 +257,18 @@ export function createCompoundSchema(values: any[], options?: SchemaGenOptions):
const schemas = values.map((value) => createSchema(value, options));
return mergeSchemas(schemas, options);
}
+
+
+function addNoAddtionalProperties(schema: Schema) {
+ if (schema.type == 'object') {
+ schema.additionalProperties = false;
+ const keys = Object.keys(schema.properties);
+ schema.properties = keys.reduce((properties, key) => {
+ properties[key] = addNoAddtionalProperties(schema.properties[key]);
+ return properties;
+ }, schema.properties);
+ } else if (schema.type == 'array') {
+ schema.items = addNoAddtionalProperties(schema.items);
+ }
+ return schema;
+}
diff --git a/src/types.ts b/src/types.ts
index 0e82179..792e8a3 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -14,10 +14,12 @@ export type Schema = {
properties?: Record;
required?: string[];
anyOf?: Array;
+ additionalProperties?: boolean;
};
export type SchemaGenOptions = {
- noRequired: boolean;
+ noRequired?: boolean;
+ noAdditionalProperties?: boolean;
};
export type SchemaComparisonOptions = {
diff --git a/tests/schema-builder.spec.ts b/tests/schema-builder.spec.ts
index bfd2425..bda5e58 100644
--- a/tests/schema-builder.spec.ts
+++ b/tests/schema-builder.spec.ts
@@ -93,6 +93,18 @@ describe('SchemaBuilder', () => {
properties: { one: { type: 'integer' }, two: { type: 'string' } },
});
});
+ it('it should generate schema for object with additionalProperties=false ', () => {
+ const schema = createSchema({ one: 1, two: 'second' }, { noAdditionalProperties: true });
+ expect(schema).toEqual({
+ type: 'object',
+ additionalProperties: false,
+ properties: { one: { type: 'integer' }, two: { type: 'string' } },
+ required: [
+ "one",
+ "two",
+ ]
+ });
+ });
});
describe('nested array', () => {
@@ -254,6 +266,54 @@ describe('SchemaBuilder', () => {
});
});
+ it('should consider value with additionalProperties=false in all objects', async () => {
+ const val = [
+ {
+ arr: [
+ {
+ prop1: 'test string',
+ },
+ {
+ prop2: 'test string',
+ },
+ ],
+ },
+ {
+ arr: [
+ {
+ prop1: 'test',
+ },
+ ],
+ },
+ ];
+ const schema = createSchema(val, { noAdditionalProperties: true });
+ expect(schema).toEqual({
+ type: 'array',
+ items: {
+ type: 'object',
+ additionalProperties: false,
+ properties: {
+ arr: {
+ type: 'array',
+ items: {
+ type: 'object',
+ additionalProperties: false,
+ properties: {
+ prop1: {
+ type: 'string',
+ },
+ prop2: {
+ type: 'string',
+ },
+ },
+ },
+ },
+ },
+ required: ['arr'],
+ },
+ });
+ });
+
it('should generate schema for array of objects w/o required', () => {
const schema = createSchema(
[