import Field from './Field' ; import { isCollectionOf } from './utility' ; /** An instance of {@linkcode Schema} defines a set of parameters by name and _fieldtype_ (see {@linkcode Field}). */ export default class Schema { /** An object whose values are all instances of {@linkcode Field} (herein _fieldset_). */ fields : object ; /** The error message produced by the last call to {@linkcode Schema.validate|Schema.prototype.validate}, if it was unsuccessful. */ lastError : object ; param fields constructor ( fields = { } ) { isCollectionOf ( Field , fields , true ) ; this . fields = fields ; } /** Returns a copy of the {@linkcode Schema} instance. */ clone ( ) { const fields = { } ; Object . keys ( this . fields ) . forEach ( ( name ) => { fields [ name ] = this . fields [ name ] . clone ( ) ; } ) ; return new Schema ( fields ) ; } param fields returns extend ( fields ) { if ( fields instanceof Schema ) { fields = fields . clone ( ) . fields ; } isCollectionOf ( Field , fields , true ) ; return new Schema ( { ... this . fields , ... fields } ) ; } param keys return select ( fields = null , ... keys ) { if ( typeof fields === 'string' ) { keys . unshift ( fields ) ; } const result = { } ; keys . forEach ( ( key ) => { if ( this . fields [ key ] ) { result [ key ] = this . fields [ key ] . clone ( ) ; } } ) ; return new Schema ( result ) ; } param keys return exclude ( ... keys ) { const result = this . clone ( ) ; keys . forEach ( ( key ) => { delete result . fields [ key ] ; } ) ; return result ; } param values return default ( values ) { const result = this . clone ( ) ; Object . keys ( result . fields ) . forEach ( ( name ) => { result . fields [ name ] . default = values [ name ] ; } ) ; return result ; } param values return flags ( values ) { const result = this . clone ( ) ; Object . keys ( result . fields ) . forEach ( ( name ) => { result . fields [ name ] . flags = values [ name ] || 0 ; } ) ; return result ; } param data returns async validate ( data ) { if ( ! data || typeof data !== 'object' ) { return undefined ; } const keys = Object . keys ( this . fields ) ; const parsed = await Promise . all ( keys . map ( ( key ) => this . fields [ key ] . parse ( data [ key ] ) ) ) ; let output = { } ; this . lastError = null ; parsed . forEach ( ( value , i ) => { const key = keys [ i ] ; if ( value === undefined ) { if ( ! this . lastError ) { this . lastError = { } ; output = undefined ; } this . lastError [ key ] = this . fields [ key ] . lastError ; } else if ( output ) { output [ key ] = value ; } } ) ; return output ; } }