| 'use strict'; | |
| 
 | |
| /*eslint-disable max-len*/ | |
| 
 | |
| var YAMLException = require('./exception'); | |
| var Type          = require('./type'); | |
| 
 | |
| 
 | |
| function compileList(schema, name) { | |
|   var result = []; | |
| 
 | |
|   schema[name].forEach(function (currentType) { | |
|     var newIndex = result.length; | |
| 
 | |
|     result.forEach(function (previousType, previousIndex) { | |
|       if (previousType.tag === currentType.tag && | |
|           previousType.kind === currentType.kind && | |
|           previousType.multi === currentType.multi) { | |
| 
 | |
|         newIndex = previousIndex; | |
|       } | |
|     }); | |
| 
 | |
|     result[newIndex] = currentType; | |
|   }); | |
| 
 | |
|   return result; | |
| } | |
| 
 | |
| 
 | |
| function compileMap(/* lists... */) { | |
|   var result = { | |
|         scalar: {}, | |
|         sequence: {}, | |
|         mapping: {}, | |
|         fallback: {}, | |
|         multi: { | |
|           scalar: [], | |
|           sequence: [], | |
|           mapping: [], | |
|           fallback: [] | |
|         } | |
|       }, index, length; | |
| 
 | |
|   function collectType(type) { | |
|     if (type.multi) { | |
|       result.multi[type.kind].push(type); | |
|       result.multi['fallback'].push(type); | |
|     } else { | |
|       result[type.kind][type.tag] = result['fallback'][type.tag] = type; | |
|     } | |
|   } | |
| 
 | |
|   for (index = 0, length = arguments.length; index < length; index += 1) { | |
|     arguments[index].forEach(collectType); | |
|   } | |
|   return result; | |
| } | |
| 
 | |
| 
 | |
| function Schema(definition) { | |
|   return this.extend(definition); | |
| } | |
| 
 | |
| 
 | |
| Schema.prototype.extend = function extend(definition) { | |
|   var implicit = []; | |
|   var explicit = []; | |
| 
 | |
|   if (definition instanceof Type) { | |
|     // Schema.extend(type) | |
|     explicit.push(definition); | |
| 
 | |
|   } else if (Array.isArray(definition)) { | |
|     // Schema.extend([ type1, type2, ... ]) | |
|     explicit = explicit.concat(definition); | |
| 
 | |
|   } else if (definition && (Array.isArray(definition.implicit) || Array.isArray(definition.explicit))) { | |
|     // Schema.extend({ explicit: [ type1, type2, ... ], implicit: [ type1, type2, ... ] }) | |
|     if (definition.implicit) implicit = implicit.concat(definition.implicit); | |
|     if (definition.explicit) explicit = explicit.concat(definition.explicit); | |
| 
 | |
|   } else { | |
|     throw new YAMLException('Schema.extend argument should be a Type, [ Type ], ' + | |
|       'or a schema definition ({ implicit: [...], explicit: [...] })'); | |
|   } | |
| 
 | |
|   implicit.forEach(function (type) { | |
|     if (!(type instanceof Type)) { | |
|       throw new YAMLException('Specified list of YAML types (or a single Type object) contains a non-Type object.'); | |
|     } | |
| 
 | |
|     if (type.loadKind && type.loadKind !== 'scalar') { | |
|       throw new YAMLException('There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.'); | |
|     } | |
| 
 | |
|     if (type.multi) { | |
|       throw new YAMLException('There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit.'); | |
|     } | |
|   }); | |
| 
 | |
|   explicit.forEach(function (type) { | |
|     if (!(type instanceof Type)) { | |
|       throw new YAMLException('Specified list of YAML types (or a single Type object) contains a non-Type object.'); | |
|     } | |
|   }); | |
| 
 | |
|   var result = Object.create(Schema.prototype); | |
| 
 | |
|   result.implicit = (this.implicit || []).concat(implicit); | |
|   result.explicit = (this.explicit || []).concat(explicit); | |
| 
 | |
|   result.compiledImplicit = compileList(result, 'implicit'); | |
|   result.compiledExplicit = compileList(result, 'explicit'); | |
|   result.compiledTypeMap  = compileMap(result.compiledImplicit, result.compiledExplicit); | |
| 
 | |
|   return result; | |
| }; | |
| 
 | |
| 
 | |
| module.exports = Schema;
 |