forked from jenkinsci/pipeline-graph-view-plugin
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathchoice-formatter.ts
More file actions
69 lines (65 loc) · 2.46 KB
/
choice-formatter.ts
File metadata and controls
69 lines (65 loc) · 2.46 KB
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
// The library @messageformat/core supports all the Java MessageFormat
// implementation apart from ChoiceFormat which it states is deprecated,
// this is a simple attempt at implementing this without any of the required
// validation as it is expected that this
// would already have happened to be used within Jelly
import { CustomFormatter } from "@messageformat/core";
function nextUp(current: number): number {
if (isNaN(current) || current === Number.POSITIVE_INFINITY) {
return current;
}
if (current === 0) {
return Number.MIN_VALUE;
}
const next = current + Number.EPSILON;
// The final multiplication (current * (1 + Number.EPSILON)) is needed to handle cases where adding
// Number.EPSILON to current does not result in a larger number due to floating-point precision limitations.
// This ensures that the next representable floating-point number greater than current is returned,
// even when current + Number.EPSILON equals current.
return next === current ? current * (1 + Number.EPSILON) : next;
}
type Choice = {
value: string;
limit: number;
};
function choice(value: unknown, locale: string, arg: string | null): string {
const parts = arg!.split("|");
const _value = Number(value);
const choices: Choice[] = [];
// a simple attempt to copy java.text.ChoiceFormat.applyPattern
// we can assume that these are correctly parsed formats as otherwise java code would have complained
// so a part is made up of a number and operator and a value
// the valid operators are <, ≤, # (which means equal)
for (let part of parts) {
// let's iterate through the part until we reach an operator
for (let i = 0; i < part.length; i++) {
const char = part.charAt(i);
if (char === "<" || char === "\u2264" || char === "#") {
const operator = char;
const number = Number(part.substring(0, i));
choices.push({
value: part.substring(i + 1),
limit: operator === "<" ? nextUp(number) : number,
});
break;
}
}
}
// now we copy java.text.ChoiceFormat.format(double, java.lang.StringBuffer, java.text.FieldPosition)
let i = 0;
for (i = 0; i < choices.length; ++i) {
if (!(_value >= choices[i].limit)) {
// same as number < choiceLimits, except catches NaN
break;
}
}
--i;
if (i < 0) {
i = 0;
}
return choices[i].value;
}
export const choiceFormatter: { arg: "string"; formatter: CustomFormatter } = {
arg: "string",
formatter: choice,
};