@naturalcycles/nodejs-lib
Advanced tools
Comparing version 5.3.0 to 6.0.0
@@ -0,1 +1,13 @@ | ||
# [6.0.0](https://github.com/NaturalCycles/nodejs-lib/compare/v5.3.0...v6.0.0) (2019-05-18) | ||
### Features | ||
* joi typed schemas ([5145082](https://github.com/NaturalCycles/nodejs-lib/commit/5145082)) | ||
### BREAKING CHANGES | ||
* arraySchema is a function now (was: a variable) | ||
# [5.3.0](https://github.com/NaturalCycles/nodejs-lib/compare/v5.2.0...v5.3.0) (2019-05-17) | ||
@@ -2,0 +14,0 @@ |
@@ -0,2 +1,6 @@ | ||
import { NumberSchema, StringSchema } from '@hapi/joi'; | ||
import * as JoiLib from '@hapi/joi'; | ||
import { DateStringExtension } from './dateString.extension'; | ||
import { DividableExtension } from './dividable.extension'; | ||
import { AnySchemaT } from './joi.model'; | ||
export declare const Joi: ExtendedJoi; | ||
@@ -7,7 +11,5 @@ export interface ExtendedJoi extends JoiLib.Root { | ||
} | ||
export interface ExtendedStringSchema extends JoiLib.StringSchema { | ||
dateString(min?: string, max?: string): this; | ||
export interface ExtendedStringSchema extends StringSchema, DateStringExtension, AnySchemaT<string> { | ||
} | ||
export interface ExtendedNumberSchema extends JoiLib.NumberSchema { | ||
dividable(q: number): this; | ||
export interface ExtendedNumberSchema extends NumberSchema, DividableExtension, AnySchemaT<number> { | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const JoiLib = require("@hapi/joi"); | ||
const luxon_1 = require("luxon"); | ||
const time_util_1 = require("../../util/time.util"); | ||
const dateString_extension_1 = require("./dateString.extension"); | ||
const dividable_extension_1 = require("./dividable.extension"); | ||
exports.Joi = JoiLib.defaults(schema => { | ||
// hack to prevent infinite recursion due to .empty('') where '' is a stringSchema itself | ||
if (schema.schemaType === 'string') { | ||
// trim all strings by default! | ||
return schema.trim(); | ||
return schema | ||
.trim() // trim all strings by default | ||
.empty([schema.valid('')]); // treat '' as empty (undefined, will be stripped out) | ||
} | ||
return schema; | ||
// Treat `null` as undefined for all schema types | ||
// undefined values will be stripped by default from object values | ||
return schema.empty(null); | ||
}) | ||
.extend((joi) => dateStringExtension(joi)) | ||
.extend((joi) => dividableExtension(joi)); | ||
function dateStringExtension(joi) { | ||
return { | ||
base: joi.string(), | ||
name: 'string', | ||
language: { | ||
dateString: 'needs to be a date string (yyyy-mm-dd)', | ||
dateStringMin: 'needs to be not earlier than {{min}}', | ||
dateStringMax: 'needs to be not later than {{max}}', | ||
dateStringCalendarAccuracy: 'needs to be a calendar accurate date', | ||
}, | ||
rules: [ | ||
{ | ||
name: 'dateString', | ||
params: { | ||
min: joi.string().optional(), | ||
max: joi.string().optional(), | ||
}, | ||
validate(params, v, state, options) { | ||
let err; | ||
let min = params.min; | ||
let max = params.max; | ||
// Today allows +-14 hours gap to account for different timezones | ||
if (max === 'today') { | ||
max = luxon_1.DateTime.utc() | ||
.plus({ hours: 14 }) | ||
.toFormat(time_util_1.LUXON_ISO_DATE_FORMAT); | ||
} | ||
if (min === 'today') { | ||
min = luxon_1.DateTime.utc() | ||
.minus({ hours: 14 }) | ||
.toFormat(time_util_1.LUXON_ISO_DATE_FORMAT); | ||
} | ||
// console.log('min/max', min, max) | ||
const m = v.match(/^(\d{4})-(\d{2})-(\d{2})$/); | ||
if (!m || m.length <= 1) { | ||
err = 'string.dateString'; | ||
} | ||
else if (min && v < min) { | ||
err = 'string.dateStringMin'; | ||
} | ||
else if (max && v > max) { | ||
err = 'string.dateStringMax'; | ||
} | ||
else if (!luxon_1.DateTime.fromFormat(v, time_util_1.LUXON_ISO_DATE_FORMAT).isValid) { | ||
err = 'string.dateStringCalendarAccuracy'; | ||
} | ||
if (err) { | ||
// tslint:disable-next-line:no-invalid-this | ||
return this.createError(err, { | ||
v, | ||
min, | ||
max, | ||
}, state, options); | ||
} | ||
return v; // validation passed | ||
}, | ||
}, | ||
], | ||
}; | ||
} | ||
function dividableExtension(joi) { | ||
return { | ||
base: joi.number(), | ||
name: 'number', | ||
language: { | ||
dividable: 'needs to be dividable by {{q}}', | ||
}, | ||
rules: [ | ||
{ | ||
name: 'dividable', | ||
params: { | ||
q: joi | ||
.number() | ||
.integer() | ||
.positive(), | ||
}, | ||
validate(params, v, state, options) { | ||
if (v % params.q !== 0) { | ||
// tslint:disable-next-line:no-invalid-this | ||
return this.createError('number.dividable', { | ||
v, | ||
q: params.q, | ||
}, state, options); | ||
} | ||
return v; | ||
}, | ||
}, | ||
], | ||
}; | ||
} | ||
.extend((joi) => dateString_extension_1.dateStringExtension(joi)) | ||
.extend((joi) => dividable_extension_1.dividableExtension(joi)); | ||
//# sourceMappingURL=joi.extensions.js.map |
@@ -1,3 +0,3 @@ | ||
import { SchemaMap } from '@hapi/joi'; | ||
export declare const booleanSchema: import("@hapi/joi").BooleanSchema; | ||
import { AnySchemaT, ArraySchemaTyped, BooleanSchemaTyped, ObjectSchemaTyped } from './joi.model'; | ||
export declare const booleanSchema: BooleanSchemaTyped; | ||
export declare const stringSchema: import("./joi.extensions").ExtendedStringSchema; | ||
@@ -7,5 +7,7 @@ export declare const numberSchema: import("./joi.extensions").ExtendedNumberSchema; | ||
export declare const dateStringSchema: import("./joi.extensions").ExtendedStringSchema; | ||
export declare const arraySchema: import("@hapi/joi").ArraySchema; | ||
export declare const binarySchema: import("@hapi/joi").BinarySchema; | ||
export declare const objectSchema: (schema?: SchemaMap | undefined) => import("@hapi/joi").ObjectSchema; | ||
export declare function arraySchema<T>(items?: AnySchemaT<T>): ArraySchemaTyped<T>; | ||
export declare function objectSchema<T>(schema?: { | ||
[key in keyof T]: AnySchemaT<T[key]>; | ||
}): ObjectSchemaTyped<T>; | ||
export declare const anySchema: import("@hapi/joi").AnySchema; | ||
@@ -12,0 +14,0 @@ export declare const anyObjectSchema: import("@hapi/joi").ObjectSchema; |
@@ -10,5 +10,11 @@ "use strict"; | ||
exports.dateStringSchema = exports.stringSchema.dateString(); | ||
exports.arraySchema = joi_extensions_1.Joi.array(); | ||
exports.binarySchema = joi_extensions_1.Joi.binary(); | ||
exports.objectSchema = (schema) => joi_extensions_1.Joi.object(schema); | ||
function arraySchema(items) { | ||
return items ? joi_extensions_1.Joi.array().items(items) : joi_extensions_1.Joi.array(); | ||
} | ||
exports.arraySchema = arraySchema; | ||
function objectSchema(schema) { | ||
return joi_extensions_1.Joi.object(schema); | ||
} | ||
exports.objectSchema = objectSchema; | ||
exports.anySchema = joi_extensions_1.Joi.any(); | ||
@@ -15,0 +21,0 @@ exports.anyObjectSchema = joi_extensions_1.Joi.object().options({ stripUnknown: false }); |
@@ -1,2 +0,3 @@ | ||
import { AnySchema, ValidationOptions } from '@hapi/joi'; | ||
import { ValidationOptions } from '@hapi/joi'; | ||
import { AnySchemaT } from './joi.model'; | ||
import { JoiValidationError } from './joi.validation.error'; | ||
@@ -14,3 +15,3 @@ export interface JoiValidationResult<T = any> { | ||
*/ | ||
export declare function validate<T>(value: T, schema?: AnySchema, objectName?: string, options?: ValidationOptions): T; | ||
export declare function validate<T>(value: T, schema?: AnySchemaT<T>, objectName?: string, options?: ValidationOptions): T; | ||
/** | ||
@@ -23,2 +24,2 @@ * Validates with Joi. | ||
*/ | ||
export declare function getValidationResult<T>(value: T, schema?: AnySchema, objectName?: string, options?: ValidationOptions): JoiValidationResult<T>; | ||
export declare function getValidationResult<T>(value: T, schema?: AnySchemaT<T>, objectName?: string, options?: ValidationOptions): JoiValidationResult<T>; |
{ | ||
"name": "@naturalcycles/nodejs-lib", | ||
"version": "5.3.0", | ||
"version": "6.0.0", | ||
"dependencies": { | ||
@@ -5,0 +5,0 @@ "@naturalcycles/js-lib": "^6.0.0", |
@@ -1,13 +0,18 @@ | ||
import { Extension, State, StringSchema, ValidationOptions } from '@hapi/joi' | ||
import { NumberSchema, StringSchema } from '@hapi/joi' | ||
import * as JoiLib from '@hapi/joi' | ||
import { DateTime } from 'luxon' | ||
import { LUXON_ISO_DATE_FORMAT } from '../../util/time.util' | ||
import { DateStringExtension, dateStringExtension } from './dateString.extension' | ||
import { DividableExtension, dividableExtension } from './dividable.extension' | ||
import { AnySchemaT } from './joi.model' | ||
export const Joi: ExtendedJoi = JoiLib.defaults(schema => { | ||
// hack to prevent infinite recursion due to .empty('') where '' is a stringSchema itself | ||
if (schema.schemaType === 'string') { | ||
// trim all strings by default! | ||
return (schema as StringSchema).trim() | ||
return (schema as StringSchema) | ||
.trim() // trim all strings by default | ||
.empty([schema.valid('')]) // treat '' as empty (undefined, will be stripped out) | ||
} | ||
return schema | ||
// Treat `null` as undefined for all schema types | ||
// undefined values will be stripped by default from object values | ||
return schema.empty(null) | ||
}) | ||
@@ -22,121 +27,10 @@ .extend((joi: typeof JoiLib) => dateStringExtension(joi)) | ||
export interface ExtendedStringSchema extends JoiLib.StringSchema { | ||
dateString (min?: string, max?: string): this | ||
} | ||
export interface ExtendedStringSchema | ||
extends StringSchema, | ||
DateStringExtension, | ||
AnySchemaT<string> {} | ||
export interface ExtendedNumberSchema extends JoiLib.NumberSchema { | ||
dividable (q: number): this | ||
} | ||
interface DateStringParams { | ||
min?: string | ||
max?: string | ||
} | ||
function dateStringExtension (joi: typeof JoiLib): Extension { | ||
return { | ||
base: joi.string(), | ||
name: 'string', | ||
language: { | ||
dateString: 'needs to be a date string (yyyy-mm-dd)', | ||
dateStringMin: 'needs to be not earlier than {{min}}', | ||
dateStringMax: 'needs to be not later than {{max}}', | ||
dateStringCalendarAccuracy: 'needs to be a calendar accurate date', | ||
}, | ||
rules: [ | ||
{ | ||
name: 'dateString', | ||
params: { | ||
min: joi.string().optional(), | ||
max: joi.string().optional(), | ||
}, | ||
validate (params: DateStringParams, v: any, state: State, options: ValidationOptions) { | ||
let err: string | undefined | ||
let min = params.min | ||
let max = params.max | ||
// Today allows +-14 hours gap to account for different timezones | ||
if (max === 'today') { | ||
max = DateTime.utc() | ||
.plus({ hours: 14 }) | ||
.toFormat(LUXON_ISO_DATE_FORMAT) | ||
} | ||
if (min === 'today') { | ||
min = DateTime.utc() | ||
.minus({ hours: 14 }) | ||
.toFormat(LUXON_ISO_DATE_FORMAT) | ||
} | ||
// console.log('min/max', min, max) | ||
const m = v.match(/^(\d{4})-(\d{2})-(\d{2})$/) | ||
if (!m || m.length <= 1) { | ||
err = 'string.dateString' | ||
} else if (min && v < min) { | ||
err = 'string.dateStringMin' | ||
} else if (max && v > max) { | ||
err = 'string.dateStringMax' | ||
} else if (!DateTime.fromFormat(v, LUXON_ISO_DATE_FORMAT).isValid) { | ||
err = 'string.dateStringCalendarAccuracy' | ||
} | ||
if (err) { | ||
// tslint:disable-next-line:no-invalid-this | ||
return this.createError( | ||
err, | ||
{ | ||
v, | ||
min, | ||
max, | ||
}, | ||
state, | ||
options, | ||
) | ||
} | ||
return v // validation passed | ||
}, | ||
}, | ||
], | ||
} | ||
} | ||
interface DividableParams { | ||
q: number | ||
} | ||
function dividableExtension (joi: typeof JoiLib): Extension { | ||
return { | ||
base: joi.number(), | ||
name: 'number', | ||
language: { | ||
dividable: 'needs to be dividable by {{q}}', | ||
}, | ||
rules: [ | ||
{ | ||
name: 'dividable', | ||
params: { | ||
q: joi | ||
.number() | ||
.integer() | ||
.positive(), | ||
}, | ||
validate (params: DividableParams, v: any, state: State, options: ValidationOptions) { | ||
if (v % params.q !== 0) { | ||
// tslint:disable-next-line:no-invalid-this | ||
return this.createError( | ||
'number.dividable', | ||
{ | ||
v, | ||
q: params.q, | ||
}, | ||
state, | ||
options, | ||
) | ||
} | ||
return v | ||
}, | ||
}, | ||
], | ||
} | ||
} | ||
export interface ExtendedNumberSchema | ||
extends NumberSchema, | ||
DividableExtension, | ||
AnySchemaT<number> {} |
@@ -1,6 +0,6 @@ | ||
import { SchemaMap } from '@hapi/joi' | ||
import { Joi } from './joi.extensions' | ||
import { AnySchemaT, ArraySchemaTyped, BooleanSchemaTyped, ObjectSchemaTyped } from './joi.model' | ||
// Should all booleans be optional as a convention? So undefined will be just treated as false? | ||
export const booleanSchema = Joi.boolean() | ||
export const booleanSchema = Joi.boolean() as BooleanSchemaTyped | ||
export const stringSchema = Joi.string() | ||
@@ -10,6 +10,14 @@ export const numberSchema = Joi.number() | ||
export const dateStringSchema = stringSchema.dateString() | ||
export const arraySchema = Joi.array() | ||
export const binarySchema = Joi.binary() | ||
export const objectSchema = (schema?: SchemaMap) => Joi.object(schema) | ||
export function arraySchema<T> (items?: AnySchemaT<T>): ArraySchemaTyped<T> { | ||
return items ? Joi.array().items(items) : Joi.array() | ||
} | ||
export function objectSchema<T> ( | ||
schema?: { [key in keyof T]: AnySchemaT<T[key]> }, | ||
): ObjectSchemaTyped<T> { | ||
return Joi.object(schema) | ||
} | ||
export const anySchema = Joi.any() | ||
@@ -16,0 +24,0 @@ export const anyObjectSchema = Joi.object().options({ stripUnknown: false }) |
@@ -9,5 +9,6 @@ /* | ||
import { AnySchema, ValidationError, ValidationOptions } from '@hapi/joi' | ||
import { ValidationError, ValidationOptions } from '@hapi/joi' | ||
import { isObject } from '@naturalcycles/js-lib' | ||
import { Joi } from './joi.extensions' | ||
import { AnySchemaT } from './joi.model' | ||
import { JoiValidationError } from './joi.validation.error' | ||
@@ -46,3 +47,3 @@ | ||
value: T, | ||
schema?: AnySchema, | ||
schema?: AnySchemaT<T>, | ||
objectName?: string, | ||
@@ -69,3 +70,3 @@ options: ValidationOptions = {}, | ||
value: T, | ||
schema?: AnySchema, | ||
schema?: AnySchemaT<T>, | ||
objectName?: string, | ||
@@ -72,0 +73,0 @@ options: ValidationOptions = {}, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
67816
55
1296