d61aa9ae2adf685a785110ab58d2ff1d60660f64a47ec1e4c8968a93fbd22f2cec29e2af23a423d67134eae0ff56fb658d10c1156427c2372745a6edb7f4f7 2.8 KB

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