Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

class-validator-jsonschema

Package Overview
Dependencies
Maintainers
1
Versions
25
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

class-validator-jsonschema - npm Package Compare versions

Comparing version 1.0.0 to 1.1.0

__tests__/decorators.test.ts

1

build/index.d.ts
import { ValidationMetadata } from 'class-validator/metadata/ValidationMetadata';
import { SchemaObject } from 'openapi3-ts';
import { IOptions } from './options';
export { JSONSchema } from './decorators';
export declare function validationMetadatasToSchemas(metadatas: ValidationMetadata[], userOptions?: Partial<IOptions>): {
[key: string]: SchemaObject;
};

26

build/index.js

@@ -6,4 +6,7 @@ "use strict";

const debug = require('debug')('routing-controllers-openapi');
const decorators_1 = require("./decorators");
const defaultConverters_1 = require("./defaultConverters");
const options_1 = require("./options");
var decorators_2 = require("./decorators");
exports.JSONSchema = decorators_2.JSONSchema;
function validationMetadatasToSchemas(metadatas, userOptions) {

@@ -13,8 +16,12 @@ const options = Object.assign({}, options_1.defaultOptions, userOptions);

.groupBy('target.name')
.map((schemaMetas, schemaName) => {
.mapValues(schemaMetas => {
const target = schemaMetas[0].target;
const properties = _(schemaMetas)
.groupBy('propertyName')
.mapValues(propMetas => applySchemaConverters(propMetas, options))
.mapValues((propMetas, propKey) => {
const schema = applyConverters(propMetas, options);
return applyDecorators(schema, target, options, propKey);
})
.value();
const schema = {
const definitionSchema = {
properties,

@@ -24,5 +31,4 @@ required: getRequiredPropNames(schemaMetas, options),

};
return [schemaName, schema];
return applyDecorators(definitionSchema, target.constructor, options);
})
.fromPairs()
.value();

@@ -32,3 +38,3 @@ return schemas;

exports.validationMetadatasToSchemas = validationMetadatasToSchemas;
function applySchemaConverters(propertyMetadatas, options) {
function applyConverters(propertyMetadatas, options) {
const converters = Object.assign({}, defaultConverters_1.defaultConverters, options.additionalConverters);

@@ -46,2 +52,8 @@ const convert = (meta) => {

}
function applyDecorators(schema, target, options, propertyName) {
const additionalSchema = decorators_1.getMetadataSchema(target.prototype, propertyName);
return _.isFunction(additionalSchema)
? additionalSchema(schema, options)
: _.merge(schema, additionalSchema);
}
function getRequiredPropNames(metadatas, options) {

@@ -62,2 +74,2 @@ const optionalValidators = [

}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFDQSxxREFBaUQ7QUFFakQsNEJBQTJCO0FBRTNCLE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyw2QkFBNkIsQ0FBQyxDQUFBO0FBRTdELDJEQUF1RDtBQUN2RCx1Q0FBb0Q7QUFNcEQsc0NBQ0UsU0FBK0IsRUFDL0IsV0FBK0I7SUFFL0IsTUFBTSxPQUFPLHFCQUNSLHdCQUFjLEVBQ2QsV0FBVyxDQUNmLENBQUE7SUFFRCxNQUFNLE9BQU8sR0FBb0MsQ0FBQyxDQUFDLFNBQVMsQ0FBQztTQUMxRCxPQUFPLENBQUMsYUFBYSxDQUFDO1NBQ3RCLEdBQUcsQ0FBQyxDQUFDLFdBQVcsRUFBRSxVQUFVLEVBQUUsRUFBRTtRQUMvQixNQUFNLFVBQVUsR0FBRyxDQUFDLENBQUMsV0FBVyxDQUFDO2FBQzlCLE9BQU8sQ0FBQyxjQUFjLENBQUM7YUFDdkIsU0FBUyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMscUJBQXFCLENBQUMsU0FBUyxFQUFFLE9BQU8sQ0FBQyxDQUFDO2FBQ2pFLEtBQUssRUFBRSxDQUFBO1FBRVYsTUFBTSxNQUFNLEdBQUc7WUFDYixVQUFVO1lBQ1YsUUFBUSxFQUFFLG9CQUFvQixDQUFDLFdBQVcsRUFBRSxPQUFPLENBQUM7WUFDcEQsSUFBSSxFQUFFLFFBQVE7U0FDZixDQUFBO1FBRUQsTUFBTSxDQUFDLENBQUMsVUFBVSxFQUFFLE1BQU0sQ0FBQyxDQUFBO0lBQzdCLENBQUMsQ0FBQztTQUNELFNBQVMsRUFBRTtTQUNYLEtBQUssRUFBRSxDQUFBO0lBRVYsTUFBTSxDQUFDLE9BQU8sQ0FBQTtBQUNoQixDQUFDO0FBN0JELG9FQTZCQztBQUtELCtCQUNFLGlCQUF1QyxFQUN2QyxPQUFpQjtJQUVqQixNQUFNLFVBQVUscUJBQVEscUNBQWlCLEVBQUssT0FBTyxDQUFDLG9CQUFvQixDQUFFLENBQUE7SUFDNUUsTUFBTSxPQUFPLEdBQUcsQ0FBQyxJQUF3QixFQUFFLEVBQUU7UUFDM0MsTUFBTSxTQUFTLEdBQUcsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUN2QyxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7WUFDZixLQUFLLENBQUMsbURBQW1ELEVBQUUsSUFBSSxDQUFDLENBQUE7WUFDaEUsTUFBTSxDQUFDLEVBQUUsQ0FBQTtRQUNYLENBQUM7UUFFRCxNQUFNLEtBQUssR0FBRyxDQUFDLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUE7UUFDNUUsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFBO0lBQ3JELENBQUMsQ0FBQTtJQUdELE1BQU0sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUcsaUJBQWlCLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUE7QUFDbkQsQ0FBQztBQU1ELDhCQUNFLFNBQStCLEVBQy9CLE9BQWlCO0lBRWpCLE1BQU0sa0JBQWtCLEdBQUc7UUFDekIsaUNBQWUsQ0FBQyxzQkFBc0I7UUFDdEMsaUNBQWUsQ0FBQyxRQUFRO0tBQ3pCLENBQUE7SUFDRCxNQUFNLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztTQUNoQixPQUFPLENBQUMsY0FBYyxDQUFDO1NBQ3ZCLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRTtRQUNWLE1BQU0sQ0FBQyxPQUFPLENBQUMscUJBQXFCO1lBQ2xDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsRUFBRSxFQUFFLElBQUksRUFBRSxpQ0FBZSxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQ2pELENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxrQkFBa0IsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFBO0lBQ3BFLENBQUMsQ0FBQztTQUNELElBQUksRUFBRTtTQUNOLEtBQUssRUFBRSxDQUFBO0FBQ1osQ0FBQyJ9
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFDQSxxREFBaUQ7QUFFakQsNEJBQTJCO0FBRTNCLE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyw2QkFBNkIsQ0FBQyxDQUFBO0FBRTdELDZDQUFnRDtBQUNoRCwyREFBdUQ7QUFDdkQsdUNBQW9EO0FBRXBELDJDQUF5QztBQUFoQyxrQ0FBQSxVQUFVLENBQUE7QUFNbkIsc0NBQ0UsU0FBK0IsRUFDL0IsV0FBK0I7SUFFL0IsTUFBTSxPQUFPLHFCQUNSLHdCQUFjLEVBQ2QsV0FBVyxDQUNmLENBQUE7SUFFRCxNQUFNLE9BQU8sR0FBb0MsQ0FBQyxDQUFDLFNBQVMsQ0FBQztTQUMxRCxPQUFPLENBQUMsYUFBYSxDQUFDO1NBQ3RCLFNBQVMsQ0FBQyxXQUFXLENBQUMsRUFBRTtRQUN2QixNQUFNLE1BQU0sR0FBRyxXQUFXLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBa0IsQ0FBQTtRQUNoRCxNQUFNLFVBQVUsR0FBRyxDQUFDLENBQUMsV0FBVyxDQUFDO2FBQzlCLE9BQU8sQ0FBQyxjQUFjLENBQUM7YUFDdkIsU0FBUyxDQUFDLENBQUMsU0FBUyxFQUFFLE9BQU8sRUFBRSxFQUFFO1lBQ2hDLE1BQU0sTUFBTSxHQUFHLGVBQWUsQ0FBQyxTQUFTLEVBQUUsT0FBTyxDQUFDLENBQUE7WUFDbEQsTUFBTSxDQUFDLGVBQWUsQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxPQUFPLENBQUMsQ0FBQTtRQUMxRCxDQUFDLENBQUM7YUFDRCxLQUFLLEVBQUUsQ0FBQTtRQUVWLE1BQU0sZ0JBQWdCLEdBQUc7WUFDdkIsVUFBVTtZQUNWLFFBQVEsRUFBRSxvQkFBb0IsQ0FBQyxXQUFXLEVBQUUsT0FBTyxDQUFDO1lBQ3BELElBQUksRUFBRSxRQUFRO1NBQ2YsQ0FBQTtRQUVELE1BQU0sQ0FBQyxl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
{
"name": "class-validator-jsonschema",
"version": "1.0.0",
"version": "1.1.0",
"description": "Convert class-validator-decorated classes into JSON schema",

@@ -5,0 +5,0 @@ "keywords": [

# class-validator-jsonschema
[![Build Status](https://travis-ci.org/epiphone/class-validator-jsonschema.svg?branch=master)](https://travis-ci.org/epiphone/class-validator-jsonschema) [![codecov](https://codecov.io/gh/epiphone/class-validator-jsonschema/branch/master/graph/badge.svg)](https://codecov.io/gh/epiphone/class-validator-jsonschema)
[![Build Status](https://travis-ci.org/epiphone/class-validator-jsonschema.svg?branch=master)](https://travis-ci.org/epiphone/class-validator-jsonschema) [![codecov](https://codecov.io/gh/epiphone/class-validator-jsonschema/branch/master/graph/badge.svg)](https://codecov.io/gh/epiphone/class-validator-jsonschema) [![npm version](https://badge.fury.io/js/class-validator-jsonschema.svg)](https://badge.fury.io/js/class-validator-jsonschema)
Convert [class-validator](https://github.com/typestack/class-validator)-decorated classes into OpenAPI-compatible JSON Schema. The aim is to provide a best-effort conversion: since some of the `class-validator` decorators lack a direct JSON Schema counterpart, the conversion is bound to be somewhat opinionated. To account for this multiple extension points are available.
## Installation
**Work in progress!**
~~`yarn add class-validator-jsonschema`~~
`yarn add class-validator-jsonschema`

@@ -99,3 +97,2 @@ ## Usage

### Custom validation classes

@@ -147,8 +144,53 @@

### Decorating with additional properties
Validation classes can also be supplemented with the `JSONSchema` decorator. `JSONSchema` can be applied both to classes and individual properties; any given keywords are then [merged](https://lodash.com/docs/4.17.4#merge) into the JSON Schema derived from class-validator decorators:
```typescript
import { JSONSchema } from 'class-validator-jsonschema'
@JSONSchema({
description: 'A User object',
example: { id: '123' }
})
class BlogPost {
@IsString()
@JSONSchema({
description: 'User primary key',
format: 'custom-id'
})
id: string
}
```
Results in the following schema:
```json
{
"BlogPost": {
"description": "A User object",
"example": { "id": "123" },
"properties": {
"id": {
"description": "User primary key",
"format": "custom-id",
"type": "string"
}
},
"required": ["id"],
"type": "object"
}
}
```
Alternatively `JSONSchema` can take a function of type `(existingSchema: SchemaObject, options: IOptions) => SchemaObject`. The return value of this function is then **not** automatically merged into existing schema (i.e. the one derived from `class-validator` decorators). Instead you can handle merging yourself in whichever way is preferred, the idea being that removal of existing keywords and other more complex overwrite scenarios can be implemented here.
## Limitations
The OpenAPI spec doesn't currently support the new JSON Schema draft-06 keywords `const` and `contains`. This means that constant value decorators such as `@IsEqual()` and `@ArrayContains()` translate to quite [complicated schemas](https://github.com/sahava/gtm-datalayer-test/issues/4). Hopefully [in a not too distant future](https://github.com/OAI/OpenAPI-Specification/issues/1313#issuecomment-335893062) these keywords are adopted into the spec and we'll be able to provide neater conversion.
There's no handling for `class-validator`s **validation groups** or **conditional decorator** (`@ValidateIf`) out-of-the-box. The above-mentioned extension methods can be used to fill the gaps if necessary.
Handling null values is also tricky since OpenAPI doesn't support JSON Schema's `type: null`, providing its own `nullable` keyword instead. The default `@IsEmpty()` converter for example opts for `nullable` but you can use `type: null` instead via `options.additionalConverters`:
The OpenAPI spec doesn't currently support the new JSON Schema **draft-06 keywords** `const` and `contains`. This means that constant value decorators such as `@IsEqual()` and `@ArrayContains()` translate to quite [complicated schemas](https://github.com/sahava/gtm-datalayer-test/issues/4). Hopefully [in a not too distant future](https://github.com/OAI/OpenAPI-Specification/issues/1313#issuecomment-335893062) these keywords are adopted into the spec and we'll be able to provide neater conversion.
Handling **null values** is also tricky since OpenAPI doesn't support JSON Schema's `type: null`, providing its own `nullable` keyword instead. The default `@IsEmpty()` converter for example opts for `nullable` but you can use `type: null` instead via `options.additionalConverters`:
```typescript

@@ -169,7 +211,4 @@ // ...

- [x] handle `skipMissingProperties` and `@isDefined()`
- [ ] decorators for overwriting prop schemas
- [ ] property descriptions (e.g. `A Base64-encoded string`)
- [ ] conditional validation?
- [ ] option for enabling draft-06 keywords
- [ ] define limitations more thoroughly
- [ ] groups?
- [x] decorators for overwriting prop schemas
- [ ] optional property descriptions (e.g. `A Base64-encoded string`)
- [ ] optional draft-06 keywords

@@ -1,2 +0,2 @@

// tslint:disable:no-submodule-imports
// tslint:disable:no-submodule-imports ban-types
import { ValidationTypes } from 'class-validator'

@@ -8,5 +8,8 @@ import { ValidationMetadata } from 'class-validator/metadata/ValidationMetadata'

import { getMetadataSchema } from './decorators'
import { defaultConverters } from './defaultConverters'
import { defaultOptions, IOptions } from './options'
export { JSONSchema } from './decorators'
/**

@@ -27,9 +30,13 @@ * Convert class-validator metadata objects into JSON Schema definitions.

.groupBy('target.name')
.map((schemaMetas, schemaName) => {
.mapValues(schemaMetas => {
const target = schemaMetas[0].target as Function
const properties = _(schemaMetas)
.groupBy('propertyName')
.mapValues(propMetas => applySchemaConverters(propMetas, options))
.mapValues((propMetas, propKey) => {
const schema = applyConverters(propMetas, options)
return applyDecorators(schema, target, options, propKey)
})
.value()
const schema = {
const definitionSchema = {
properties,

@@ -40,5 +47,4 @@ required: getRequiredPropNames(schemaMetas, options),

return [schemaName, schema]
return applyDecorators(definitionSchema, target.constructor, options)
})
.fromPairs()
.value()

@@ -50,5 +56,5 @@

/**
* Convert a property's class-validator metadata into an OpenAPI Schema property.
* Convert a property's class-validator metadata into a JSON Schema property.
*/
function applySchemaConverters(
function applyConverters(
propertyMetadatas: ValidationMetadata[],

@@ -74,2 +80,18 @@ options: IOptions

/**
* Given a JSON Schema object, supplement it with additional schema properties
* defined by target object's @JSONSchema decorator.
*/
function applyDecorators(
schema: SchemaObject,
target: Function,
options: IOptions,
propertyName?: string
): SchemaObject {
const additionalSchema = getMetadataSchema(target.prototype, propertyName)
return _.isFunction(additionalSchema)
? additionalSchema(schema, options)
: _.merge(schema, additionalSchema)
}
/**
* Get the required property names of a validated class.

@@ -76,0 +98,0 @@ * @param metadatas Validation metadata objects of the validated class.

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc