-
Notifications
You must be signed in to change notification settings - Fork 572
/
float.ts
125 lines (108 loc) · 3.14 KB
/
float.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// Ported from js-yaml v3.13.1:
// https://github.com/nodeca/js-yaml/commit/665aadda42349dcae869f12040d9b10ef18d12da
// Copyright 2011-2015 by Vitaly Puzrin. All rights reserved. MIT license.
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
import { StyleVariant, Type } from "../type.ts";
import { Any, isNegativeZero } from "../utils.ts";
const YAML_FLOAT_PATTERN = new RegExp(
// 2.5e4, 2.5 and integers
"^(?:[-+]?(?:0|[1-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
"|\\.(?:nan|NaN|NAN))$",
);
function resolveYamlFloat(data: string): boolean {
if (
!YAML_FLOAT_PATTERN.test(data) ||
// Quick hack to not allow integers end with `_`
// Probably should update regexp & check speed
data[data.length - 1] === "_"
) {
return false;
}
return true;
}
function constructYamlFloat(data: string): number {
let value = data.replace(/_/g, "").toLowerCase();
const sign = value[0] === "-" ? -1 : 1;
const digits: number[] = [];
if ("+-".indexOf(value[0]) >= 0) {
value = value.slice(1);
}
if (value === ".inf") {
return sign === 1 ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY;
}
if (value === ".nan") {
return NaN;
}
if (value.indexOf(":") >= 0) {
value.split(":").forEach((v) => {
digits.unshift(parseFloat(v));
});
let valueNb = 0.0;
let base = 1;
digits.forEach((d) => {
valueNb += d * base;
base *= 60;
});
return sign * valueNb;
}
return sign * parseFloat(value);
}
const SCIENTIFIC_WITHOUT_DOT = /^[-+]?[0-9]+e/;
function representYamlFloat(object: Any, style?: StyleVariant): Any {
if (isNaN(object)) {
switch (style) {
case "lowercase":
return ".nan";
case "uppercase":
return ".NAN";
case "camelcase":
return ".NaN";
}
} else if (Number.POSITIVE_INFINITY === object) {
switch (style) {
case "lowercase":
return ".inf";
case "uppercase":
return ".INF";
case "camelcase":
return ".Inf";
}
} else if (Number.NEGATIVE_INFINITY === object) {
switch (style) {
case "lowercase":
return "-.inf";
case "uppercase":
return "-.INF";
case "camelcase":
return "-.Inf";
}
} else if (isNegativeZero(object)) {
return "-0.0";
}
const res = object.toString(10);
// JS stringifier can build scientific format without dots: 5e-100,
// while YAML requires dot: 5.e-100. Fix it with simple hack
return SCIENTIFIC_WITHOUT_DOT.test(res) ? res.replace("e", ".e") : res;
}
function isFloat(object: Any): boolean {
return (
Object.prototype.toString.call(object) === "[object Number]" &&
(object % 1 !== 0 || isNegativeZero(object))
);
}
export const float = new Type("tag:yaml.org,2002:float", {
construct: constructYamlFloat,
defaultStyle: "lowercase",
kind: "scalar",
predicate: isFloat,
represent: representYamlFloat,
resolve: resolveYamlFloat,
});