float.js (2840B)
1 'use strict'; 2 3 var common = require('../common'); 4 var Type = require('../type'); 5 6 var YAML_FLOAT_PATTERN = new RegExp( 7 // 2.5e4, 2.5 and integers 8 '^(?:[-+]?(?:0|[1-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?' + 9 // .2e4, .2 10 // special case, seems not from spec 11 '|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?' + 12 // 20:59 13 '|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*' + 14 // .inf 15 '|[-+]?\\.(?:inf|Inf|INF)' + 16 // .nan 17 '|\\.(?:nan|NaN|NAN))$'); 18 19 function resolveYamlFloat(data) { 20 if (data === null) return false; 21 22 if (!YAML_FLOAT_PATTERN.test(data) || 23 // Quick hack to not allow integers end with `_` 24 // Probably should update regexp & check speed 25 data[data.length - 1] === '_') { 26 return false; 27 } 28 29 return true; 30 } 31 32 function constructYamlFloat(data) { 33 var value, sign, base, digits; 34 35 value = data.replace(/_/g, '').toLowerCase(); 36 sign = value[0] === '-' ? -1 : 1; 37 digits = []; 38 39 if ('+-'.indexOf(value[0]) >= 0) { 40 value = value.slice(1); 41 } 42 43 if (value === '.inf') { 44 return (sign === 1) ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY; 45 46 } else if (value === '.nan') { 47 return NaN; 48 49 } else if (value.indexOf(':') >= 0) { 50 value.split(':').forEach(function (v) { 51 digits.unshift(parseFloat(v, 10)); 52 }); 53 54 value = 0.0; 55 base = 1; 56 57 digits.forEach(function (d) { 58 value += d * base; 59 base *= 60; 60 }); 61 62 return sign * value; 63 64 } 65 return sign * parseFloat(value, 10); 66 } 67 68 69 var SCIENTIFIC_WITHOUT_DOT = /^[-+]?[0-9]+e/; 70 71 function representYamlFloat(object, style) { 72 var res; 73 74 if (isNaN(object)) { 75 switch (style) { 76 case 'lowercase': return '.nan'; 77 case 'uppercase': return '.NAN'; 78 case 'camelcase': return '.NaN'; 79 } 80 } else if (Number.POSITIVE_INFINITY === object) { 81 switch (style) { 82 case 'lowercase': return '.inf'; 83 case 'uppercase': return '.INF'; 84 case 'camelcase': return '.Inf'; 85 } 86 } else if (Number.NEGATIVE_INFINITY === object) { 87 switch (style) { 88 case 'lowercase': return '-.inf'; 89 case 'uppercase': return '-.INF'; 90 case 'camelcase': return '-.Inf'; 91 } 92 } else if (common.isNegativeZero(object)) { 93 return '-0.0'; 94 } 95 96 res = object.toString(10); 97 98 // JS stringifier can build scientific format without dots: 5e-100, 99 // while YAML requres dot: 5.e-100. Fix it with simple hack 100 101 return SCIENTIFIC_WITHOUT_DOT.test(res) ? res.replace('e', '.e') : res; 102 } 103 104 function isFloat(object) { 105 return (Object.prototype.toString.call(object) === '[object Number]') && 106 (object % 1 !== 0 || common.isNegativeZero(object)); 107 } 108 109 module.exports = new Type('tag:yaml.org,2002:float', { 110 kind: 'scalar', 111 resolve: resolveYamlFloat, 112 construct: constructYamlFloat, 113 predicate: isFloat, 114 represent: representYamlFloat, 115 defaultStyle: 'lowercase' 116 });