@@ -32,4 +32,68 @@ local d = import 'github.com/jsonnet-libs/docsonnet/doc-util/main.libsonnet';
3232 [d.arg('str' , d.T.string)]
3333 ),
3434 isStringNumeric(str): std.all(std.map (self .isNumber, std.stringChars (str))),
35+
36+ '#isStringJSONNumeric' :: d.fn(
37+ '`isStringJSONNumeric` reports whether string `s` is a number as defined by [JSON](https://www.json.org/json-en.html).' ,
38+ [d.arg('str' , d.T.string)]
39+ ),
40+ isStringJSONNumeric(str):
41+ // "1" "9"
42+ local onenine(c) = (cp(c) >= 49 && cp(c) <= 57 );
43+
44+ // "0"
45+ local digit(c) = (cp(c) == 48 || onenine(c));
46+
47+ local digits(str) =
48+ std.length (str) > 0
49+ && std.all(
50+ std.foldl (
51+ function (acc, c)
52+ acc + [digit(c)],
53+ std.stringChars (str),
54+ [],
55+ )
56+ );
57+
58+ local fraction(str) = str == '' || (str[0 ] == '.' && digits(str[1 :]));
59+
60+ local sign(c) = (c == '-' || c == '+' );
61+
62+ local exponent(str) =
63+ str == ''
64+ || (str[0 ] == 'E' && digits(str[1 :]))
65+ || (str[0 ] == 'e' && digits(str[1 :]))
66+ || (std.length (str) > 1 && str[0 ] == 'E' && sign(str[1 ]) && digits(str[2 :]))
67+ || (std.length (str) > 1 && str[0 ] == 'e' && sign(str[1 ]) && digits(str[2 :]));
68+
69+
70+ local integer(str) =
71+ (std.length (str) == 1 && digit(str[0 ]))
72+ || (std.length (str) > 0 && onenine(str[0 ]) && digits(str[1 :]))
73+ || (std.length (str) > 1 && str[0 ] == '-' && digit(str[1 ]))
74+ || (std.length (str) > 1 && str[0 ] == '-' && onenine(str[1 ]) && digits(str[2 :]));
75+
76+ local expectInteger =
77+ if std.member(str, '.' )
78+ then std.split (str, '.' )[0 ]
79+ else if std.member(str, 'e' )
80+ then std.split (str, 'e' )[0 ]
81+ else if std.member(str, 'E' )
82+ then std.split (str, 'E' )[0 ]
83+ else str;
84+
85+ local expectFraction =
86+ if std.member(str, 'e' )
87+ then std.split (str[std.length (expectInteger):], 'e' )[0 ]
88+ else if std.member(str, 'E' )
89+ then std.split (str[std.length (expectInteger):], 'E' )[0 ]
90+ else str[std.length (expectInteger):];
91+
92+ local expectExponent = str[std.length (expectInteger) + std.length (expectFraction):];
93+
94+ std.all([
95+ integer(expectInteger),
96+ fraction(expectFraction),
97+ exponent(expectExponent),
98+ ]),
3599}
0 commit comments