YAML 1.2 parser and serializer for JavaScript environments with complete specification support
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
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.
The Schema class serves as a container for YAML type definitions and provides methods for extending schemas with additional types.
class Schema {
constructor(definition);
extend(definition);
}Usage Examples:
const yaml = require('js-yaml');
// Create custom schema extending existing one
const customSchema = yaml.DEFAULT_SCHEMA.extend([
new yaml.Type('!custom', {
kind: 'scalar',
construct: data => `custom:${data}`
})
]);
// Use custom schema
const doc = yaml.load('value: !custom hello', { schema: customSchema });
console.log(doc.value); // "custom:hello"The Type class defines individual YAML type handlers with their tag, parsing logic, and serialization behavior.
class Type {
constructor(tag, options);
}Constructor Options:
interface TypeOptions {
kind: 'scalar' | 'sequence' | 'mapping';
multi?: boolean;
resolve?: (data: string) => boolean;
construct?: (data: string) => any;
instanceOf?: Function;
predicate?: (object: any) => boolean;
represent?: Function | { [style: string]: Function };
representName?: string;
defaultStyle?: string;
styleAliases?: { [alias: string]: string };
}The most basic schema supporting only fundamental YAML constructs.
const FAILSAFE_SCHEMA;Supported Types:
!!str - String values!!seq - Sequences (arrays)!!map - Mappings (objects)Usage:
const doc = yaml.load('items: [a, b, c]', {
schema: yaml.FAILSAFE_SCHEMA
});
// All values are strings: { items: ["a", "b", "c"] }Extends FAILSAFE_SCHEMA with JSON-compatible types.
const JSON_SCHEMA;Additional Types:
!!null - Null values (null, ~, empty)!!bool - Boolean values (true/false, yes/no, on/off)!!int - Integer values (decimal, binary, octal, hex)!!float - Floating point values (including .inf, .nan)Usage:
const yamlContent = `
name: John
age: 30
active: true
score: null
`;
const doc = yaml.load(yamlContent, { schema: yaml.JSON_SCHEMA });
// { name: "John", age: 30, active: true, score: null }Alias for JSON_SCHEMA - identical implementation.
const CORE_SCHEMA;The complete schema with all supported YAML types including extended types.
const DEFAULT_SCHEMA;Additional Types beyond JSON_SCHEMA:
!!timestamp - Date/time values!!merge - Merge keys for inheritance!!binary - Base64-encoded binary data!!omap - Ordered mappings!!pairs - Key-value pairs!!set - Sets (unique values)Usage:
const fullYaml = `
created: 2023-01-15T10:30:00Z
data: !!binary |
R0lGODlhDAAMAIQAAP//9/X
17unp5WZmZgAAAOfn515eXv
config: &default
timeout: 30
retries: 3
environments:
- <<: *default
name: dev
- <<: *default
name: prod
timeout: 60
`;
const doc = yaml.load(fullYaml); // Uses DEFAULT_SCHEMA by defaultAll built-in types are available in the types object for custom schema creation:
const types: {
binary: Type;
float: Type;
map: Type;
null: Type;
pairs: Type;
set: Type;
timestamp: Type;
bool: Type;
int: Type;
merge: Type;
omap: Type;
seq: Type;
str: Type;
};Usage Example:
// Create schema with only specific types
const customSchema = new yaml.Schema({
explicit: [
yaml.types.str,
yaml.types.int,
yaml.types.seq,
yaml.types.map
]
});Define custom scalar (single value) types:
const uuidType = new yaml.Type('!uuid', {
kind: 'scalar',
resolve: (data) => {
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(data);
},
construct: (data) => {
return data.toLowerCase();
},
predicate: (object) => {
return typeof object === 'string' &&
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(object);
},
represent: (object) => {
return object.toUpperCase();
}
});
const schema = yaml.DEFAULT_SCHEMA.extend([uuidType]);Define custom sequence (array-like) types:
const setType = new yaml.Type('!set', {
kind: 'sequence',
construct: (data) => {
return new Set(data);
},
predicate: (object) => {
return object instanceof Set;
},
represent: (object) => {
return Array.from(object);
}
});Define custom mapping (object-like) types:
const classType = new yaml.Type('!class', {
kind: 'mapping',
construct: (data) => {
const instance = Object.create(null);
instance.__class__ = data.name;
Object.assign(instance, data.properties || {});
return instance;
},
predicate: (object) => {
return object && typeof object === 'object' && '__class__' in object;
},
represent: (object) => {
return {
name: object.__class__,
properties: Object.keys(object)
.filter(key => key !== '__class__')
.reduce((props, key) => {
props[key] = object[key];
return props;
}, {})
};
}
});Add types to existing schemas using the extend method:
// Add single type
const extendedSchema = yaml.DEFAULT_SCHEMA.extend(customType);
// Add multiple types
const multiSchema = yaml.DEFAULT_SCHEMA.extend([type1, type2, type3]);
// Add with explicit/implicit categorization
const categorizedSchema = yaml.DEFAULT_SCHEMA.extend({
implicit: [implicitType1, implicitType2],
explicit: [explicitType1, explicitType2]
});Implicit types are resolved automatically based on the data format:
const implicitDateType = new yaml.Type('!date', {
kind: 'scalar',
resolve: (data) => /^\d{4}-\d{2}-\d{2}$/.test(data),
construct: (data) => new Date(data + 'T00:00:00Z')
});
// Automatically converts date-like strings
// date_field: 2023-01-15 # Becomes Date objectExplicit types require explicit tagging:
const explicitDateType = new yaml.Type('!date', {
kind: 'scalar',
construct: (data) => new Date(data)
});
// Requires explicit tag
// date_field: !date 2023-01-15T10:30:00ZTypes can have multiple representation styles:
const colorType = new yaml.Type('!color', {
kind: 'scalar',
construct: (data) => {
if (data.startsWith('#')) {
return { hex: data };
} else if (data.startsWith('rgb(')) {
const match = data.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
return { r: +match[1], g: +match[2], b: +match[3] };
}
return { name: data };
},
represent: {
hex: (color) => color.hex,
rgb: (color) => `rgb(${color.r}, ${color.g}, ${color.b})`,
name: (color) => color.name
},
defaultStyle: 'hex'
});Use instanceOf and predicate for robust type checking:
const urlType = new yaml.Type('!url', {
kind: 'scalar',
instanceOf: URL,
construct: (data) => new URL(data),
predicate: (object) => object instanceof URL,
represent: (object) => object.toString()
});Create schemas with only safe types:
const safeSchema = new yaml.Schema({
explicit: [
yaml.types.str,
yaml.types.int,
yaml.types.float,
yaml.types.bool,
yaml.types.null,
yaml.types.seq,
yaml.types.map
]
});Schema designed for configuration files:
const configSchema = yaml.DEFAULT_SCHEMA.extend([
new yaml.Type('!env', {
kind: 'scalar',
construct: (data) => process.env[data] || null
}),
new yaml.Type('!require', {
kind: 'scalar',
construct: (data) => require(data)
})
]);
// Usage in YAML:
// database_url: !env DATABASE_URL
// handler: !require ./handlers/auth