@formatjs/intl-datetimeformat
Version:
Intl.DateTimeFormat polyfill
91 lines (90 loc) • 3.11 kB
JavaScript
import { invariant } from "@formatjs/ecma402-abstract";
import { DATE_TIME_PROPS, additionPenalty, removalPenalty, longMorePenalty, shortMorePenalty, shortLessPenalty, longLessPenalty, offsetPenalty } from "./utils.js";
/**
* https://tc39.es/ecma402/#sec-basicformatmatcher
* @param options
* @param formats
*/
export function BasicFormatMatcher(options, formats) {
let bestScore = -Infinity;
let bestFormat = formats[0];
invariant(Array.isArray(formats), "formats should be a list of things");
for (const format of formats) {
let score = 0;
for (const prop of DATE_TIME_PROPS) {
const optionsProp = options[prop];
const formatProp = format[prop];
if (optionsProp === undefined && formatProp !== undefined) {
score -= additionPenalty;
} else if (optionsProp !== undefined && formatProp === undefined) {
score -= removalPenalty;
} else if (prop === "timeZoneName") {
if (optionsProp === "short" || optionsProp === "shortGeneric") {
if (formatProp === "shortOffset") {
score -= offsetPenalty;
} else if (formatProp === "longOffset") {
score -= offsetPenalty + shortMorePenalty;
} else if (optionsProp === "short" && formatProp === "long") {
score -= shortMorePenalty;
} else if (optionsProp === "shortGeneric" && formatProp === "longGeneric") {
score -= shortMorePenalty;
} else if (optionsProp !== formatProp) {
score -= removalPenalty;
}
} else if (optionsProp === "shortOffset" && formatProp === "longOffset") {
score -= shortMorePenalty;
} else if (optionsProp === "long" || optionsProp === "longGeneric") {
if (formatProp === "longOffset") {
score -= offsetPenalty;
} else if (formatProp === "shortOffset") {
score -= offsetPenalty + longLessPenalty;
} else if (optionsProp === "long" && formatProp === "short") {
score -= longLessPenalty;
} else if (optionsProp === "longGeneric" && formatProp === "shortGeneric") {
score -= longLessPenalty;
} else if (optionsProp !== formatProp) {
score -= removalPenalty;
}
} else if (optionsProp === "longOffset" && formatProp === "shortOffset") {
score -= longLessPenalty;
} else if (optionsProp !== formatProp) {
score -= removalPenalty;
}
} else if (optionsProp !== formatProp) {
let values;
if (prop === "fractionalSecondDigits") {
values = [
1,
2,
3
];
} else {
values = [
"2-digit",
"numeric",
"narrow",
"short",
"long"
];
}
const optionsPropIndex = values.indexOf(optionsProp);
const formatPropIndex = values.indexOf(formatProp);
const delta = Math.max(-2, Math.min(formatPropIndex - optionsPropIndex, 2));
if (delta === 2) {
score -= longMorePenalty;
} else if (delta === 1) {
score -= shortMorePenalty;
} else if (delta === -1) {
score -= shortLessPenalty;
} else if (delta === -2) {
score -= longLessPenalty;
}
}
}
if (score > bestScore) {
bestScore = score;
bestFormat = format;
}
}
return { ...bestFormat };
}