1 | 'use strict';
|
2 |
|
3 |
|
4 |
|
5 | var YAMLException = require('./exception');
|
6 | var Type = require('./type');
|
7 |
|
8 |
|
9 | function compileList(schema, name) {
|
10 | var result = [];
|
11 |
|
12 | schema[name].forEach(function (currentType) {
|
13 | var newIndex = result.length;
|
14 |
|
15 | result.forEach(function (previousType, previousIndex) {
|
16 | if (previousType.tag === currentType.tag &&
|
17 | previousType.kind === currentType.kind &&
|
18 | previousType.multi === currentType.multi) {
|
19 |
|
20 | newIndex = previousIndex;
|
21 | }
|
22 | });
|
23 |
|
24 | result[newIndex] = currentType;
|
25 | });
|
26 |
|
27 | return result;
|
28 | }
|
29 |
|
30 |
|
31 | function compileMap(/* lists... */) {
|
32 | var result = {
|
33 | scalar: {},
|
34 | sequence: {},
|
35 | mapping: {},
|
36 | fallback: {},
|
37 | multi: {
|
38 | scalar: [],
|
39 | sequence: [],
|
40 | mapping: [],
|
41 | fallback: []
|
42 | }
|
43 | }, index, length;
|
44 |
|
45 | function collectType(type) {
|
46 | if (type.multi) {
|
47 | result.multi[type.kind].push(type);
|
48 | result.multi['fallback'].push(type);
|
49 | } else {
|
50 | result[type.kind][type.tag] = result['fallback'][type.tag] = type;
|
51 | }
|
52 | }
|
53 |
|
54 | for (index = 0, length = arguments.length; index < length; index += 1) {
|
55 | arguments[index].forEach(collectType);
|
56 | }
|
57 | return result;
|
58 | }
|
59 |
|
60 |
|
61 | function Schema(definition) {
|
62 | return this.extend(definition);
|
63 | }
|
64 |
|
65 |
|
66 | Schema.prototype.extend = function extend(definition) {
|
67 | var implicit = [];
|
68 | var explicit = [];
|
69 |
|
70 | if (definition instanceof Type) {
|
71 |
|
72 | explicit.push(definition);
|
73 |
|
74 | } else if (Array.isArray(definition)) {
|
75 |
|
76 | explicit = explicit.concat(definition);
|
77 |
|
78 | } else if (definition && (Array.isArray(definition.implicit) || Array.isArray(definition.explicit))) {
|
79 |
|
80 | if (definition.implicit) implicit = implicit.concat(definition.implicit);
|
81 | if (definition.explicit) explicit = explicit.concat(definition.explicit);
|
82 |
|
83 | } else {
|
84 | throw new YAMLException('Schema.extend argument should be a Type, [ Type ], ' +
|
85 | 'or a schema definition ({ implicit: [...], explicit: [...] })');
|
86 | }
|
87 |
|
88 | implicit.forEach(function (type) {
|
89 | if (!(type instanceof Type)) {
|
90 | throw new YAMLException('Specified list of YAML types (or a single Type object) contains a non-Type object.');
|
91 | }
|
92 |
|
93 | if (type.loadKind && type.loadKind !== 'scalar') {
|
94 | throw new YAMLException('There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.');
|
95 | }
|
96 |
|
97 | if (type.multi) {
|
98 | throw new YAMLException('There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit.');
|
99 | }
|
100 | });
|
101 |
|
102 | explicit.forEach(function (type) {
|
103 | if (!(type instanceof Type)) {
|
104 | throw new YAMLException('Specified list of YAML types (or a single Type object) contains a non-Type object.');
|
105 | }
|
106 | });
|
107 |
|
108 | var result = Object.create(Schema.prototype);
|
109 |
|
110 | result.implicit = (this.implicit || []).concat(implicit);
|
111 | result.explicit = (this.explicit || []).concat(explicit);
|
112 |
|
113 | result.compiledImplicit = compileList(result, 'implicit');
|
114 | result.compiledExplicit = compileList(result, 'explicit');
|
115 | result.compiledTypeMap = compileMap(result.compiledImplicit, result.compiledExplicit);
|
116 |
|
117 | return result;
|
118 | };
|
119 |
|
120 |
|
121 | module.exports = Schema;
|