Skip to content

Commit

Permalink
Parse numbers according to YAML 1.2 instead of YAML 1.1
Browse files Browse the repository at this point in the history
  • Loading branch information
rlidwka committed Dec 4, 2020
1 parent d1692b9 commit 1918519
Show file tree
Hide file tree
Showing 9 changed files with 73 additions and 66 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `yaml.Schema.create(schema, tags)` is removed, use `schema.extend(tags)` instead.
- `!!binary` now always mapped to `Uint8Array` on load.
- Reduced nesting of `/lib` folder.
- Parse numbers according to YAML 1.2 instead of YAML 1.1 (`01234` is now decimal,
`0o1234` is octal, `1:23` is parsed as string instead of base60).

### Added
- Added `.mjs` (es modules) support.
Expand Down
23 changes: 2 additions & 21 deletions lib/type/float.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@ var Type = require('../type');

var YAML_FLOAT_PATTERN = new RegExp(
// 2.5e4, 2.5 and integers
'^(?:[-+]?(?:0|[1-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?' +
'^(?:[-+]?(?:[0-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?' +
// .2e4, .2
// special case, seems not from spec
'|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?' +
// 20:59
'|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*' +
// .inf
'|[-+]?\\.(?:inf|Inf|INF)' +
// .nan
Expand All @@ -30,11 +28,10 @@ function resolveYamlFloat(data) {
}

function constructYamlFloat(data) {
var value, sign, base, digits;
var value, sign;

value = data.replace(/_/g, '').toLowerCase();
sign = value[0] === '-' ? -1 : 1;
digits = [];

if ('+-'.indexOf(value[0]) >= 0) {
value = value.slice(1);
Expand All @@ -45,22 +42,6 @@ function constructYamlFloat(data) {

} else if (value === '.nan') {
return NaN;

} else if (value.indexOf(':') >= 0) {
value.split(':').forEach(function (v) {
digits.unshift(parseFloat(v, 10));
});

value = 0.0;
base = 1;

digits.forEach(function (d) {
value += d * base;
base *= 60;
});

return sign * value;

}
return sign * parseFloat(value, 10);
}
Expand Down
53 changes: 18 additions & 35 deletions lib/type/int.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,25 +68,29 @@ function resolveYamlInteger(data) {
return hasDigits && ch !== '_';
}

// base 8
for (; index < max; index++) {
ch = data[index];
if (ch === '_') continue;
if (!isOctCode(data.charCodeAt(index))) return false;
hasDigits = true;

if (ch === 'o') {
// base 8
index++;

for (; index < max; index++) {
ch = data[index];
if (ch === '_') continue;
if (!isOctCode(data.charCodeAt(index))) return false;
hasDigits = true;
}
return hasDigits && ch !== '_';
}
return hasDigits && ch !== '_';
}

// base 10 (except 0) or base 60
// base 10 (except 0)

// value should not start with `_`;
if (ch === '_') return false;

for (; index < max; index++) {
ch = data[index];
if (ch === '_') continue;
if (ch === ':') break;
if (!isDecCode(data.charCodeAt(index))) {
return false;
}
Expand All @@ -96,15 +100,11 @@ function resolveYamlInteger(data) {
// Should have digits and should not end with `_`
if (!hasDigits || ch === '_') return false;

// if !base60 - done;
if (ch !== ':') return true;

// base60 almost not used, no needs to optimize
return /^(:[0-5]?[0-9])+$/.test(data.slice(index));
return true;
}

function constructYamlInteger(data) {
var value = data, sign = 1, ch, base, digits = [];
var value = data, sign = 1, ch;

if (value.indexOf('_') !== -1) {
value = value.replace(/_/g, '');
Expand All @@ -122,25 +122,8 @@ function constructYamlInteger(data) {

if (ch === '0') {
if (value[1] === 'b') return sign * parseInt(value.slice(2), 2);
if (value[1] === 'x') return sign * parseInt(value, 16);
return sign * parseInt(value, 8);
}

if (value.indexOf(':') !== -1) {
value.split(':').forEach(function (v) {
digits.unshift(parseInt(v, 10));
});

value = 0;
base = 1;

digits.forEach(function (d) {
value += (d * base);
base *= 60;
});

return sign * value;

if (value[1] === 'x') return sign * parseInt(value.slice(2), 16);
if (value[1] === 'o') return sign * parseInt(value.slice(2), 8);
}

return sign * parseInt(value, 10);
Expand All @@ -158,7 +141,7 @@ module.exports = new Type('tag:yaml.org,2002:int', {
predicate: isInteger,
represent: {
binary: function (obj) { return obj >= 0 ? '0b' + obj.toString(2) : '-0b' + obj.toString(2).slice(1); },
octal: function (obj) { return obj >= 0 ? '0' + obj.toString(8) : '-0' + obj.toString(8).slice(1); },
octal: function (obj) { return obj >= 0 ? '0o' + obj.toString(8) : '-0o' + obj.toString(8).slice(1); },
decimal: function (obj) { return obj.toString(10); },
/* eslint-disable max-len */
hexadecimal: function (obj) { return obj >= 0 ? '0x' + obj.toString(16).toUpperCase() : '-0x' + obj.toString(16).toUpperCase().slice(1); }
Expand Down
4 changes: 1 addition & 3 deletions support/demo_template/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ <h4 class="subheader"><a href="#" id="permalink">permalink</a> Edit source here:
canonical: 6.8523015e+5
exponentioal: 685.230_15e+03
fixed: 685_230.15
sexagesimal: 190:20:30.15
negative infinity: -.inf
not a number: .NaN

Expand All @@ -127,10 +126,9 @@ <h4 class="subheader"><a href="#" id="permalink">permalink</a> Edit source here:
int:
canonical: 685230
decimal: +685_230
octal: 02472256
octal: 0o2472256
hexadecimal: 0x_0A_74_AE
binary: 0b1010_0111_0100_1010_1110
sexagesimal: 190:20:30

# http://yaml.org/type/merge.html ---------------------------------------------#

Expand Down
48 changes: 48 additions & 0 deletions test/issues/0027.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
'use strict';


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


describe('Should load numbers in YAML 1.2 format', function () {
it('should not parse base60', function () {
// previously parsed as int
assert.strictEqual(yaml.load('1:23'), '1:23');
// previously parsed as float
assert.strictEqual(yaml.load('1:23.45'), '1:23.45');
});

it('should allow leading zero in int and float', function () {
assert.strictEqual(yaml.load('01234'), 1234);
assert.strictEqual(yaml.load('00999'), 999);
assert.strictEqual(yaml.load('-00999'), -999);
assert.strictEqual(yaml.load('001234.56'), 1234.56);
assert.strictEqual(yaml.load('001234e4'), 12340000);
assert.strictEqual(yaml.load('-001234.56'), -1234.56);
assert.strictEqual(yaml.load('-001234e4'), -12340000);
});

it('should parse 0o prefix as octal', function () {
assert.strictEqual(yaml.load('0o1234'), 668);
// not valid octal
assert.strictEqual(yaml.load('0o1289'), '0o1289');
});
});


describe('Should dump numbers in YAML 1.2 format', function () {
it('should dump in different styles', function () {
assert.strictEqual(yaml.dump(123, { styles: { '!!int': 'binary' } }), '0b1111011\n');
assert.strictEqual(yaml.dump(123, { styles: { '!!int': 'octal' } }), '0o173\n');
assert.strictEqual(yaml.dump(123, { styles: { '!!int': 'hex' } }), '0x7B\n');
});

it('should quote all potential numbers', function () {
var tests = '1:23 1:23.45 01234 0999 -01234 01234e4 01234.56 -01234.56 0x123 0o123';

tests.split(' ').forEach(function (sample) {
assert.strictEqual(yaml.dump(sample, { noCompatMode: false }), "'" + sample + "'\n");
});
});
});
2 changes: 0 additions & 2 deletions test/samples-common/construct-float.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ var expected = {
canonical: 685230.15,
exponential: 685230.15,
fixed: 685230.15,
sexagesimal: 685230.15,
'negative infinity': Number.NEGATIVE_INFINITY,
'not a number': NaN
};
Expand All @@ -18,7 +17,6 @@ function testHandler(actual) {
assert.strictEqual(actual['canonical'], expected['canonical']);
assert.strictEqual(actual['exponential'], expected['exponential']);
assert.strictEqual(actual['fixed'], expected['fixed']);
assert.strictEqual(actual['sexagesimal'], expected['sexagesimal']);
assert.strictEqual(actual['negative infinity'], expected['negative infinity']);

assert(Number.isNaN(actual['not a number']));
Expand Down
1 change: 0 additions & 1 deletion test/samples-common/construct-float.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
canonical: 6.8523015e+5
exponential: 685.230_15e+03
fixed: 685_230.15
sexagesimal: 190:20:30.15
negative infinity: -.inf
not a number: .NaN
3 changes: 1 addition & 2 deletions test/samples-common/construct-int.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@ module.exports = {
decimal: 685230,
octal: 685230,
hexadecimal: 685230,
binary: 685230,
sexagesimal: 685230
binary: 685230
};
3 changes: 1 addition & 2 deletions test/samples-common/construct-int.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
canonical: 685230
decimal: +685_230
octal: 02472256
octal: 0o2472256
hexadecimal: 0x_0A_74_AE
binary: 0b1010_0111_0100_1010_1110
sexagesimal: 190:20:30

0 comments on commit 1918519

Please sign in to comment.