'use strict' const YAMLException = require('./exception') const Type = require('./type') function compileList (schema, name) { const result = [] schema[name].forEach(function (currentType) { let 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... */) { const result = { scalar: {}, sequence: {}, mapping: {}, fallback: {}, multi: { scalar: [], sequence: [], mapping: [], fallback: [] } } 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 (let 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) { let implicit = [] let 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.') } }) const 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