0
# Schema System
1
2
js-yaml uses a powerful schema system to control which YAML types are supported during parsing and serialization. The schema system is extensible, allowing for custom type definitions while providing several built-in schemas for common use cases.
3
4
## Core Classes
5
6
### Schema
7
8
The Schema class serves as a container for YAML type definitions and provides methods for extending schemas with additional types.
9
10
```javascript { .api }
11
class Schema {
12
constructor(definition);
13
extend(definition);
14
}
15
```
16
17
**Usage Examples:**
18
19
```javascript
20
const yaml = require('js-yaml');
21
22
// Create custom schema extending existing one
23
const customSchema = yaml.DEFAULT_SCHEMA.extend([
24
new yaml.Type('!custom', {
25
kind: 'scalar',
26
construct: data => `custom:${data}`
27
})
28
]);
29
30
// Use custom schema
31
const doc = yaml.load('value: !custom hello', { schema: customSchema });
32
console.log(doc.value); // "custom:hello"
33
```
34
35
### Type
36
37
The Type class defines individual YAML type handlers with their tag, parsing logic, and serialization behavior.
38
39
```javascript { .api }
40
class Type {
41
constructor(tag, options);
42
}
43
```
44
45
**Constructor Options:**
46
47
```javascript { .api }
48
interface TypeOptions {
49
kind: 'scalar' | 'sequence' | 'mapping';
50
multi?: boolean;
51
resolve?: (data: string) => boolean;
52
construct?: (data: string) => any;
53
instanceOf?: Function;
54
predicate?: (object: any) => boolean;
55
represent?: Function | { [style: string]: Function };
56
representName?: string;
57
defaultStyle?: string;
58
styleAliases?: { [alias: string]: string };
59
}
60
```
61
62
## Built-in Schemas
63
64
### FAILSAFE_SCHEMA
65
66
The most basic schema supporting only fundamental YAML constructs.
67
68
```javascript { .api }
69
const FAILSAFE_SCHEMA;
70
```
71
72
**Supported Types:**
73
- `!!str` - String values
74
- `!!seq` - Sequences (arrays)
75
- `!!map` - Mappings (objects)
76
77
**Usage:**
78
79
```javascript
80
const doc = yaml.load('items: [a, b, c]', {
81
schema: yaml.FAILSAFE_SCHEMA
82
});
83
// All values are strings: { items: ["a", "b", "c"] }
84
```
85
86
### JSON_SCHEMA
87
88
Extends FAILSAFE_SCHEMA with JSON-compatible types.
89
90
```javascript { .api }
91
const JSON_SCHEMA;
92
```
93
94
**Additional Types:**
95
- `!!null` - Null values (`null`, `~`, empty)
96
- `!!bool` - Boolean values (`true`/`false`, `yes`/`no`, `on`/`off`)
97
- `!!int` - Integer values (decimal, binary, octal, hex)
98
- `!!float` - Floating point values (including `.inf`, `.nan`)
99
100
**Usage:**
101
102
```javascript
103
const yamlContent = `
104
name: John
105
age: 30
106
active: true
107
score: null
108
`;
109
110
const doc = yaml.load(yamlContent, { schema: yaml.JSON_SCHEMA });
111
// { name: "John", age: 30, active: true, score: null }
112
```
113
114
### CORE_SCHEMA
115
116
Alias for JSON_SCHEMA - identical implementation.
117
118
```javascript { .api }
119
const CORE_SCHEMA;
120
```
121
122
### DEFAULT_SCHEMA
123
124
The complete schema with all supported YAML types including extended types.
125
126
```javascript { .api }
127
const DEFAULT_SCHEMA;
128
```
129
130
**Additional Types beyond JSON_SCHEMA:**
131
- `!!timestamp` - Date/time values
132
- `!!merge` - Merge keys for inheritance
133
- `!!binary` - Base64-encoded binary data
134
- `!!omap` - Ordered mappings
135
- `!!pairs` - Key-value pairs
136
- `!!set` - Sets (unique values)
137
138
**Usage:**
139
140
```javascript
141
const fullYaml = `
142
created: 2023-01-15T10:30:00Z
143
data: !!binary |
144
R0lGODlhDAAMAIQAAP//9/X
145
17unp5WZmZgAAAOfn515eXv
146
config: &default
147
timeout: 30
148
retries: 3
149
150
environments:
151
- <<: *default
152
name: dev
153
- <<: *default
154
name: prod
155
timeout: 60
156
`;
157
158
const doc = yaml.load(fullYaml); // Uses DEFAULT_SCHEMA by default
159
```
160
161
## Built-in Types Collection
162
163
All built-in types are available in the `types` object for custom schema creation:
164
165
```javascript { .api }
166
const types: {
167
binary: Type;
168
float: Type;
169
map: Type;
170
null: Type;
171
pairs: Type;
172
set: Type;
173
timestamp: Type;
174
bool: Type;
175
int: Type;
176
merge: Type;
177
omap: Type;
178
seq: Type;
179
str: Type;
180
};
181
```
182
183
**Usage Example:**
184
185
```javascript
186
// Create schema with only specific types
187
const customSchema = new yaml.Schema({
188
explicit: [
189
yaml.types.str,
190
yaml.types.int,
191
yaml.types.seq,
192
yaml.types.map
193
]
194
});
195
```
196
197
## Creating Custom Types
198
199
### Scalar Types
200
201
Define custom scalar (single value) types:
202
203
```javascript
204
const uuidType = new yaml.Type('!uuid', {
205
kind: 'scalar',
206
resolve: (data) => {
207
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(data);
208
},
209
construct: (data) => {
210
return data.toLowerCase();
211
},
212
predicate: (object) => {
213
return typeof object === 'string' &&
214
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(object);
215
},
216
represent: (object) => {
217
return object.toUpperCase();
218
}
219
});
220
221
const schema = yaml.DEFAULT_SCHEMA.extend([uuidType]);
222
```
223
224
### Sequence Types
225
226
Define custom sequence (array-like) types:
227
228
```javascript
229
const setType = new yaml.Type('!set', {
230
kind: 'sequence',
231
construct: (data) => {
232
return new Set(data);
233
},
234
predicate: (object) => {
235
return object instanceof Set;
236
},
237
represent: (object) => {
238
return Array.from(object);
239
}
240
});
241
```
242
243
### Mapping Types
244
245
Define custom mapping (object-like) types:
246
247
```javascript
248
const classType = new yaml.Type('!class', {
249
kind: 'mapping',
250
construct: (data) => {
251
const instance = Object.create(null);
252
instance.__class__ = data.name;
253
Object.assign(instance, data.properties || {});
254
return instance;
255
},
256
predicate: (object) => {
257
return object && typeof object === 'object' && '__class__' in object;
258
},
259
represent: (object) => {
260
return {
261
name: object.__class__,
262
properties: Object.keys(object)
263
.filter(key => key !== '__class__')
264
.reduce((props, key) => {
265
props[key] = object[key];
266
return props;
267
}, {})
268
};
269
}
270
});
271
```
272
273
## Schema Extension
274
275
### Extending Existing Schemas
276
277
Add types to existing schemas using the `extend` method:
278
279
```javascript
280
// Add single type
281
const extendedSchema = yaml.DEFAULT_SCHEMA.extend(customType);
282
283
// Add multiple types
284
const multiSchema = yaml.DEFAULT_SCHEMA.extend([type1, type2, type3]);
285
286
// Add with explicit/implicit categorization
287
const categorizedSchema = yaml.DEFAULT_SCHEMA.extend({
288
implicit: [implicitType1, implicitType2],
289
explicit: [explicitType1, explicitType2]
290
});
291
```
292
293
### Implicit vs Explicit Types
294
295
**Implicit types** are resolved automatically based on the data format:
296
297
```javascript
298
const implicitDateType = new yaml.Type('!date', {
299
kind: 'scalar',
300
resolve: (data) => /^\d{4}-\d{2}-\d{2}$/.test(data),
301
construct: (data) => new Date(data + 'T00:00:00Z')
302
});
303
304
// Automatically converts date-like strings
305
// date_field: 2023-01-15 # Becomes Date object
306
```
307
308
**Explicit types** require explicit tagging:
309
310
```javascript
311
const explicitDateType = new yaml.Type('!date', {
312
kind: 'scalar',
313
construct: (data) => new Date(data)
314
});
315
316
// Requires explicit tag
317
// date_field: !date 2023-01-15T10:30:00Z
318
```
319
320
## Advanced Type Features
321
322
### Multi-representation Types
323
324
Types can have multiple representation styles:
325
326
```javascript
327
const colorType = new yaml.Type('!color', {
328
kind: 'scalar',
329
construct: (data) => {
330
if (data.startsWith('#')) {
331
return { hex: data };
332
} else if (data.startsWith('rgb(')) {
333
const match = data.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
334
return { r: +match[1], g: +match[2], b: +match[3] };
335
}
336
return { name: data };
337
},
338
represent: {
339
hex: (color) => color.hex,
340
rgb: (color) => `rgb(${color.r}, ${color.g}, ${color.b})`,
341
name: (color) => color.name
342
},
343
defaultStyle: 'hex'
344
});
345
```
346
347
### Type Validation
348
349
Use `instanceOf` and `predicate` for robust type checking:
350
351
```javascript
352
const urlType = new yaml.Type('!url', {
353
kind: 'scalar',
354
instanceOf: URL,
355
construct: (data) => new URL(data),
356
predicate: (object) => object instanceof URL,
357
represent: (object) => object.toString()
358
});
359
```
360
361
## Common Schema Patterns
362
363
### Restricted Schema
364
365
Create schemas with only safe types:
366
367
```javascript
368
const safeSchema = new yaml.Schema({
369
explicit: [
370
yaml.types.str,
371
yaml.types.int,
372
yaml.types.float,
373
yaml.types.bool,
374
yaml.types.null,
375
yaml.types.seq,
376
yaml.types.map
377
]
378
});
379
```
380
381
### Configuration Schema
382
383
Schema designed for configuration files:
384
385
```javascript
386
const configSchema = yaml.DEFAULT_SCHEMA.extend([
387
new yaml.Type('!env', {
388
kind: 'scalar',
389
construct: (data) => process.env[data] || null
390
}),
391
new yaml.Type('!require', {
392
kind: 'scalar',
393
construct: (data) => require(data)
394
})
395
]);
396
397
// Usage in YAML:
398
// database_url: !env DATABASE_URL
399
// handler: !require ./handlers/auth
400
```