Skip to content

Commit

Permalink
Export built-in types, type override now preserves order
Browse files Browse the repository at this point in the history
  • Loading branch information
rlidwka committed Apr 14, 2021
1 parent ab31bba commit 2b5620e
Show file tree
Hide file tree
Showing 9 changed files with 196 additions and 11 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).


## [4.1.0] - WIP
### Added
- Types are now exported as `yaml.types.XXX`.
- Every type now has options object with original arguments kept as they were
(see `yaml.types.int.options` as an example).

### Changed
- Schema.extend now keeps old type order in case of conflicts
(e.g. Schema.extend([ a, b, c ]).extend([ b, a, d ]) is now ordered as `abcd` instead of `cbad`).


## [4.0.0] - 2021-01-03
### Changed
- Check [migration guide](migrate_v3_to_v4.md) to see details for all breaking changes.
Expand Down
2 changes: 1 addition & 1 deletion examples/.eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ env:
es6: true

parserOptions:
ecmaVersion: 2017
ecmaVersion: 2020
59 changes: 59 additions & 0 deletions examples/int_type_override.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// This example overrides built-in !!int type to return BigInt instead of a Number
//

'use strict';

/*global BigInt*/
/*eslint-disable no-console*/

const util = require('util');
const yaml = require('../');


// keep most of the original `int` options as is
let options = Object.assign({}, yaml.types.int.options);

options.construct = data => {
let value = data, sign = 1n, ch;

if (value.indexOf('_') !== -1) {
value = value.replace(/_/g, '');
}

ch = value[0];

if (ch === '-' || ch === '+') {
if (ch === '-') sign = -1n;
value = value.slice(1);
ch = value[0];
}

return sign * BigInt(value);
};


options.predicate = object => {
return Object.prototype.toString.call(object) === '[object BigInt]' ||
yaml.types.int.options.predicate(object);
};


let BigIntType = new yaml.Type('tag:yaml.org,2002:int', options);

const SCHEMA = yaml.DEFAULT_SCHEMA.extend({ implicit: [ BigIntType ] });

const data = `
bigint: -12_345_678_901_234_567_890
`;

const loaded = yaml.load(data, { schema: SCHEMA });

console.log('Parsed as:');
console.log('-'.repeat(70));
console.log(util.inspect(loaded, false, 20, true));

console.log('');
console.log('');
console.log('Dumped as:');
console.log('-'.repeat(70));
console.log(yaml.dump(loaded, { schema: SCHEMA }));
17 changes: 17 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,23 @@ module.exports.loadAll = loader.loadAll;
module.exports.dump = dumper.dump;
module.exports.YAMLException = require('./lib/exception');

// Re-export all types in case user wants to create custom schema
module.exports.types = {
binary: require('./lib/type/binary'),
float: require('./lib/type/float'),
map: require('./lib/type/map'),
null: require('./lib/type/null'),
pairs: require('./lib/type/pairs'),
set: require('./lib/type/set'),
timestamp: require('./lib/type/timestamp'),
bool: require('./lib/type/bool'),
int: require('./lib/type/int'),
merge: require('./lib/type/merge'),
omap: require('./lib/type/omap'),
seq: require('./lib/type/seq'),
str: require('./lib/type/str')
};

// Removed functions from JS-YAML 3.0.x
module.exports.safeLoad = renamed('safeLoad', 'load');
module.exports.safeLoadAll = renamed('safeLoadAll', 'loadAll');
Expand Down
18 changes: 9 additions & 9 deletions lib/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,25 @@ var YAMLException = require('./exception');
var Type = require('./type');


function compileList(schema, name, result) {
var exclude = [];
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) {

exclude.push(previousIndex);
newIndex = previousIndex;
}
});

result.push(currentType);
result[newIndex] = currentType;
});

return result.filter(function (type, index) {
return exclude.indexOf(index) === -1;
});
return result;
}


Expand Down Expand Up @@ -110,8 +110,8 @@ Schema.prototype.extend = function extend(definition) {
result.implicit = (this.implicit || []).concat(implicit);
result.explicit = (this.explicit || []).concat(explicit);

result.compiledImplicit = compileList(result, 'implicit', []);
result.compiledExplicit = compileList(result, 'explicit', []);
result.compiledImplicit = compileList(result, 'implicit');
result.compiledExplicit = compileList(result, 'explicit');
result.compiledTypeMap = compileMap(result.compiledImplicit, result.compiledExplicit);

return result;
Expand Down
1 change: 1 addition & 0 deletions lib/type.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ function Type(tag, options) {
});

// TODO: Add tag format check.
this.options = options; // keep original options in case user wants to extend this type later
this.tag = tag;
this.kind = options['kind'] || null;
this.resolve = options['resolve'] || function () { return true; };
Expand Down
2 changes: 1 addition & 1 deletion test/.eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ env:
es6: true

parserOptions:
ecmaVersion: 2017
ecmaVersion: 2020

rules:
no-undefined: 0
49 changes: 49 additions & 0 deletions test/issues/0586.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use strict';

/* eslint-disable no-use-before-define, new-cap */


const assert = require('assert');
const yaml = require('../../');


it('Should allow custom formatting through implicit custom tags', function () {
function CustomDump(data, opts) {
if (!(this instanceof CustomDump)) return new CustomDump(data, opts);
this.data = data;
this.opts = opts;
}

CustomDump.prototype.represent = function () {
let result = yaml.dump(this.data, Object.assign({ replacer, schema }, this.opts));
result = result.trim();
if (result.includes('\n')) result = '\n' + result;
return result;
};


let CustomDumpType = new yaml.Type('!format', {
kind: 'scalar',
resolve: () => false,
instanceOf: CustomDump,
represent: d => d.represent()
});


let schema = yaml.DEFAULT_SCHEMA.extend({ implicit: [ CustomDumpType ] });

function replacer(key, value) {
if (key === '') return value; // top-level, don't change this
if (key === 'flow_choices') return CustomDump(value, { flowLevel: 0 });
if (key === 'block_choices') return CustomDump(value, { flowLevel: Infinity });
return value; // default
}

let result = CustomDump({ flow_choices : [ 1, 2 ], block_choices: [ 4, 5 ] }).represent().trim();

assert.strictEqual(result, `
flow_choices: [1, 2]
block_choices:
- 4
- 5`.replace(/^\n/, ''));
});
47 changes: 47 additions & 0 deletions test/issues/0614.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
'use strict';

/* global BigInt */


const assert = require('assert');
const yaml = require('../../');


it('Should allow int override', function () {
let options = Object.assign({}, yaml.types.int.options);

options.construct = data => {
let value = data, sign = 1n, ch;

if (value.indexOf('_') !== -1) {
value = value.replace(/_/g, '');
}

ch = value[0];

if (ch === '-' || ch === '+') {
if (ch === '-') sign = -1n;
value = value.slice(1);
ch = value[0];
}

return sign * BigInt(value);
};


let BigIntType = new yaml.Type('tag:yaml.org,2002:int', options);

const SCHEMA = yaml.DEFAULT_SCHEMA.extend({ implicit: [ BigIntType ] });

const data = `
int: -123_456_789
bigint: -12_345_678_901_234_567_890
float: -12_345_678_901_234_567_890.1234
`;

assert.deepStrictEqual(yaml.load(data, { schema: SCHEMA }), {
int: -123456789n,
bigint: -12345678901234567890n,
float: -12345678901234567000 // precision loss expected
});
});

0 comments on commit 2b5620e

Please sign in to comment.