From fd140bfa3182c9beedc8c7ce3423e596a2528cfa Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Sun, 22 Sep 2019 02:14:18 +0300 Subject: [PATCH] Self-validation --- ServerPropTypes.js | 33 +++++++++++++++++++++++++++------ test.js | 3 +++ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/ServerPropTypes.js b/ServerPropTypes.js index bb2b0b6..4d8f59c 100644 --- a/ServerPropTypes.js +++ b/ServerPropTypes.js @@ -5,8 +5,9 @@ * - Uses literal definitions (unlike, for example, Joi) * - Simpler than JSON schema, but convertible to it * - Supports comments and convenient user-readable validation errors - * - Coerces decimal strings to numbers - * - Coerces scalars to single-element arrays + * - Converts strings to numbers if possible + * - Converts scalars to single-element arrays + * - Validates its own meta-type * * (c) Vitaliy Filippov 2019+ * @@ -100,7 +101,7 @@ class ServerPropTypes { bad = { path: [ i, ...(st.error.path||[]) ], - name: '№'+i + (st.error.name ? ' - '+st.error.name : ''), + name: '№'+(i+1) + (st.error.name ? ' - '+st.error.name : ''), }; break; } @@ -128,7 +129,7 @@ class ServerPropTypes { bad = { path: [ i, ...(st.error.path||[]) ], - name: '№'+i + (st.error.name ? ' - '+st.error.name : ''), + name: '№'+(i+1) + (st.error.name ? ' - '+st.error.name : ''), }; break; } @@ -148,7 +149,7 @@ class ServerPropTypes } break; case 'object': - if (typeof v != 'object' || v instanceof Array || type.required && !v) + if (v != null && typeof v != 'object' || v instanceof Array || type.required && !v) { bad = true; } @@ -366,12 +367,21 @@ ServerPropTypes.metaType = { spt: { type: 'one', of: [ + { comment: 'Reference to another type', type: 'object', items: { + type: { type: 'enum', of: [ 'ref' ] }, + refs: { type: 'object', of: { type: 'ref', ref: 'anytype' } }, + required: { type: 'bool', comment: 'Item is required' }, + comment: { type: 'string', comment: 'Item comment' }, + ref: { type: 'string', comment: 'Type reference', required: true }, + } }, { comment: 'Any type', type: 'object', items: { type: { type: 'enum', of: [ 'any' ] }, + refs: { type: 'object', of: { type: 'ref', ref: 'anytype' } }, comment: { type: 'string', comment: 'Item comment' }, } }, { comment: 'String', type: 'object', items: { type: { type: 'enum', of: [ 'string' ] }, + refs: { type: 'object', of: { type: 'ref', ref: 'anytype' } }, required: { type: 'bool', comment: 'Item is required' }, comment: { type: 'string', comment: 'Item comment' }, regex: { type: 'string', comment: 'Regular expression' }, @@ -379,12 +389,14 @@ ServerPropTypes.metaType = { } }, { comment: 'String-coded decimal', type: 'object', items: { type: { type: 'enum', of: [ 'decimal' ] }, + refs: { type: 'object', of: { type: 'ref', ref: 'anytype' } }, required: { type: 'bool', comment: 'Item is required' }, comment: { type: 'string', comment: 'Item comment' }, decimals: { type: 'int', comment: 'Allowed decimal places' }, } }, { comment: 'Number', type: 'object', items: { type: { type: 'enum', of: [ 'num' ] }, + refs: { type: 'object', of: { type: 'ref', ref: 'anytype' } }, required: { type: 'bool', comment: 'Item is required' }, comment: { type: 'string', comment: 'Item comment' }, min: { type: 'num', comment: 'Minimum value' }, @@ -392,6 +404,7 @@ ServerPropTypes.metaType = { } }, { comment: 'Integer', type: 'object', items: { type: { type: 'enum', of: [ 'int' ] }, + refs: { type: 'object', of: { type: 'ref', ref: 'anytype' } }, required: { type: 'bool', comment: 'Item is required' }, comment: { type: 'string', comment: 'Item comment' }, min: { type: 'int', comment: 'Minimum value' }, @@ -399,16 +412,19 @@ ServerPropTypes.metaType = { } }, { comment: 'ID (positive integer or NULL)', type: 'object', items: { type: { type: 'enum', of: [ 'id' ] }, + refs: { type: 'object', of: { type: 'ref', ref: 'anytype' } }, required: { type: 'bool', comment: 'Item is required' }, comment: { type: 'string', comment: 'Item comment' }, } }, { comment: 'Boolean', type: 'object', items: { type: { type: 'enum', of: [ 'bool' ] }, + refs: { type: 'object', of: { type: 'ref', ref: 'anytype' } }, required: { type: 'bool', comment: 'Item is required' }, comment: { type: 'string', comment: 'Item comment' }, } }, { comment: 'Array', type: 'object', items: { type: { type: 'enum', of: [ 'array' ] }, + refs: { type: 'object', of: { type: 'ref', ref: 'anytype' } }, required: { type: 'bool', comment: 'Item is required' }, comment: { type: 'string', comment: 'Item comment' }, of: { type: 'ref', ref: 'anytype', required: true, comment: 'Array item type' }, @@ -417,12 +433,14 @@ ServerPropTypes.metaType = { } }, { comment: 'Tuple (fixed-length array)', type: 'object', items: { type: { type: 'enum', of: [ 'array' ] }, + refs: { type: 'object', of: { type: 'ref', ref: 'anytype' } }, required: { type: 'bool', comment: 'Item is required' }, comment: { type: 'string', comment: 'Item comment' }, items: { type: 'array', of: { type: 'ref', ref: 'anytype' }, required: true, comment: 'Tuple item types' }, } }, { comment: 'Unstructured hash', type: 'object', items: { type: { type: 'enum', of: [ 'object' ] }, + refs: { type: 'object', of: { type: 'ref', ref: 'anytype' } }, required: { type: 'bool', comment: 'Item is required' }, comment: { type: 'string', comment: 'Item comment' }, of: { type: 'ref', ref: 'anytype', required: true, comment: 'Hash item type' }, @@ -431,18 +449,21 @@ ServerPropTypes.metaType = { } }, { comment: 'Structured object', type: 'object', items: { type: { type: 'enum', of: [ 'object' ] }, + refs: { type: 'object', of: { type: 'ref', ref: 'anytype' } }, required: { type: 'bool', comment: 'Item is required' }, comment: { type: 'string', comment: 'Item comment' }, items: { type: 'object', of: { type: 'ref', ref: 'anytype' }, required: true, comment: 'Field types' }, } }, { comment: 'Enum of constants', type: 'object', items: { type: { type: 'enum', of: [ 'enum' ] }, + refs: { type: 'object', of: { type: 'ref', ref: 'anytype' } }, required: { type: 'bool', comment: 'Item is required' }, comment: { type: 'string', comment: 'Item comment' }, - of: { type: 'array', minLength: 1, required: true, comment: 'Constants' }, + of: { type: 'array', of: 'any', minLength: 1, required: true, comment: 'Constants' }, } }, { comment: 'One of types', type: 'object', items: { type: { type: 'enum', of: [ 'one' ] }, + refs: { type: 'object', of: { type: 'ref', ref: 'anytype' } }, required: { type: 'bool', comment: 'Item is required' }, comment: { type: 'string', comment: 'Item comment' }, of: { type: 'array', of: { type: 'ref', ref: 'anytype' }, minLength: 1, required: true, comment: 'Type options' }, diff --git a/test.js b/test.js index c72bfe7..0cdc49e 100644 --- a/test.js +++ b/test.js @@ -11,3 +11,6 @@ const type = { }; console.log(JSON.stringify(spt.check({ type: 'object', items: type }, spt.metaType, { return_error: true }), null, 2)); + +// Self-validate! +console.log(JSON.stringify(spt.check(spt.metaType, spt.metaType, { return_error: true }), null, 2));