ddnet
Version:
A typescript npm package for interacting with data from ddnet.org
828 lines • 20.8 kB
JavaScript
/**
* Wrapper class for the {@link Error} built-in class, used as a catch all option and to also provide error context.
*/
export class DDNetError extends Error {
context;
/**
* Create a new instance of {@link DDNetError}
*/
constructor(
/**
* The reason for this error.
*/
reason,
/**
* Context for this error, usually an {@link Error} object, array or a string, ultimately unknown type.
*/
context) {
super(reason ?? 'No error message provided, see context.');
this.context = context;
}
}
/**
* Converts a number of seconds to a DDNet finish time string.
*
* @example "03:23"
*/
export function timeString(
/**
* The time in seconds to convert.
*/
totalSeconds) {
if (totalSeconds < 0)
return '--:--';
const pad = (s) => (s.length < 2 ? `0${s}` : s);
const hours = Math.floor(totalSeconds / 3600).toString();
const remainingSecondsAfterHours = totalSeconds % 3600;
const minutes = Math.floor(remainingSecondsAfterHours / 60).toString();
const seconds = Math.floor(remainingSecondsAfterHours % 60).toString();
return hours === '0' ? `${pad(minutes)}:${pad(seconds)}` : `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`;
}
/**
* Slugifies a name to safely use it in a url.
*
* @see
* https://github.com/ddnet/ddnet-scripts/blob/master/servers/scripts/ddnet.py#L185
*/
export function slugify(name) {
const x = '[\t !"#$%&\'()*\\-/<=>?@[\\]^_`{|},.:]+';
let string = '';
for (const c of name) {
if (c.match(x) || c.charCodeAt(0) >= 128) {
string += `-${c.charCodeAt(0)}-`;
}
else {
string += c;
}
}
return string;
}
/**
* Converts a python date time string or timestamp into a valid javascript timestamp.
*/
export function dePythonifyTime(
/**
* The time to convert.
*/
time) {
if (typeof time === 'string')
return new Date(time).getTime();
const d = new Date(time);
// hacky fix
if (d.getFullYear() < 2000)
return new Date(time * 1000).getTime();
return d.getTime();
}
/**
* Represents the different DDNet server types.
*/
export var Type;
(function (Type) {
Type["novice"] = "Novice";
Type["moderate"] = "Moderate";
Type["brutal"] = "Brutal";
Type["insane"] = "Insane";
Type["dummy"] = "Dummy";
Type["ddmaxEasy"] = "DDmaX.Easy";
Type["ddmaxNext"] = "DDmaX.Next";
Type["ddmaxPro"] = "DDmaX.Pro";
Type["ddmaxNut"] = "DDmaX.Nut";
Type["oldschool"] = "Oldschool";
Type["solo"] = "Solo";
Type["race"] = "Race";
Type["fun"] = "Fun";
Type["unknown"] = "UNKNOWN";
})(Type || (Type = {}));
/**
* Represents server regions.
*
* @see
* https://github.com/ddnet/ddnet-web/tree/master/www/countryflags
*/
export var ServerRegion;
(function (ServerRegion) {
ServerRegion["ARG"] = "ARG";
ServerRegion["AUS"] = "AUS";
ServerRegion["BRA"] = "BRA";
ServerRegion["CAN"] = "CAN";
ServerRegion["CHL"] = "CHL";
ServerRegion["CHN"] = "CHN";
ServerRegion["COL"] = "COL";
ServerRegion["CRI"] = "CRI";
ServerRegion["EUR"] = "EUR";
ServerRegion["GER"] = "GER";
ServerRegion["FIN"] = "FIN";
ServerRegion["IND"] = "IND";
ServerRegion["IRN"] = "IRN";
ServerRegion["JAP"] = "JAP";
ServerRegion["KOR"] = "KOR";
ServerRegion["KSA"] = "KSA";
ServerRegion["MEX"] = "MEX";
ServerRegion["NLD"] = "NLD";
ServerRegion["PER"] = "PER";
ServerRegion["POL"] = "POL";
ServerRegion["RUS"] = "RUS";
ServerRegion["SAU"] = "SAU";
ServerRegion["SGP"] = "SGP";
ServerRegion["TUR"] = "TUR";
ServerRegion["TWN"] = "TWN";
ServerRegion["UAE"] = "UAE";
ServerRegion["UKR"] = "UKR";
ServerRegion["UNK"] = "UNK";
ServerRegion["USA"] = "USA";
ServerRegion["ZAF"] = "ZAF";
})(ServerRegion || (ServerRegion = {}));
/**
* Represents server regions where ranks are available online.
*
* @remarks
* It's similar to {@link ServerRegion} but some are missing and some don't exist.
*
* @see
* https://github.com/ddnet/ddnet-scripts/blob/master/servers/scripts/maps.py#L178
*/
export var RankAvailableRegion;
(function (RankAvailableRegion) {
RankAvailableRegion["NLD"] = "NLD";
RankAvailableRegion["FRA"] = "FRA";
RankAvailableRegion["GER"] = "GER";
RankAvailableRegion["POL"] = "POL";
RankAvailableRegion["FIN"] = "FIN";
RankAvailableRegion["UKR"] = "UKR";
RankAvailableRegion["RUS"] = "RUS";
RankAvailableRegion["TUR"] = "TUR";
RankAvailableRegion["IRN"] = "IRN";
RankAvailableRegion["BHR"] = "BHR";
RankAvailableRegion["CHL"] = "CHL";
RankAvailableRegion["BRA"] = "BRA";
RankAvailableRegion["ARG"] = "ARG";
RankAvailableRegion["PER"] = "PER";
RankAvailableRegion["USA"] = "USA";
RankAvailableRegion["CHN"] = "CHN";
RankAvailableRegion["KOR"] = "KOR";
RankAvailableRegion["TWN"] = "TWN";
RankAvailableRegion["SGP"] = "SGP";
RankAvailableRegion["ZAF"] = "ZAF";
RankAvailableRegion["IND"] = "IND";
RankAvailableRegion["AUS"] = "AUS";
RankAvailableRegion["OLD"] = "OLD";
RankAvailableRegion["UNK"] = "UNK";
})(RankAvailableRegion || (RankAvailableRegion = {}));
/**
* Represents player countries.
*
* @see
* https://github.com/ddnet/ddnet/tree/master/data/countryflags
*/
export var Country;
(function (Country) {
Country["AD"] = "AD";
Country["AE"] = "AE";
Country["AF"] = "AF";
Country["AG"] = "AG";
Country["AI"] = "AI";
Country["AL"] = "AL";
Country["AM"] = "AM";
Country["AO"] = "AO";
Country["AQ"] = "AQ";
Country["AR"] = "AR";
Country["AS"] = "AS";
Country["AT"] = "AT";
Country["AU"] = "AU";
Country["AW"] = "AW";
Country["AX"] = "AX";
Country["AZ"] = "AZ";
Country["BA"] = "BA";
Country["BB"] = "BB";
Country["BD"] = "BD";
Country["BE"] = "BE";
Country["BF"] = "BF";
Country["BG"] = "BG";
Country["BH"] = "BH";
Country["BI"] = "BI";
Country["BJ"] = "BJ";
Country["BL"] = "BL";
Country["BM"] = "BM";
Country["BN"] = "BN";
Country["BO"] = "BO";
Country["BR"] = "BR";
Country["BS"] = "BS";
Country["BT"] = "BT";
Country["BW"] = "BW";
Country["BY"] = "BY";
Country["BZ"] = "BZ";
Country["CA"] = "CA";
Country["CC"] = "CC";
Country["CD"] = "CD";
Country["CF"] = "CF";
Country["CG"] = "CG";
Country["CH"] = "CH";
Country["CI"] = "CI";
Country["CK"] = "CK";
Country["CL"] = "CL";
Country["CM"] = "CM";
Country["CN"] = "CN";
Country["CO"] = "CO";
Country["CR"] = "CR";
Country["CU"] = "CU";
Country["CV"] = "CV";
Country["CW"] = "CW";
Country["CX"] = "CX";
Country["CY"] = "CY";
Country["CZ"] = "CZ";
Country["DE"] = "DE";
Country["DJ"] = "DJ";
Country["DK"] = "DK";
Country["DM"] = "DM";
Country["DO"] = "DO";
Country["DZ"] = "DZ";
Country["EC"] = "EC";
Country["EE"] = "EE";
Country["EG"] = "EG";
Country["EH"] = "EH";
Country["ER"] = "ER";
Country["ES-CT"] = "ES-CT";
Country["ES-GA"] = "ES-GA";
Country["ES"] = "ES";
Country["ET"] = "ET";
Country["EU"] = "EU";
Country["FI"] = "FI";
Country["FJ"] = "FJ";
Country["FK"] = "FK";
Country["FM"] = "FM";
Country["FO"] = "FO";
Country["FR"] = "FR";
Country["GA"] = "GA";
Country["GB-ENG"] = "GB-ENG";
Country["GB-NIR"] = "GB-NIR";
Country["GB-SCT"] = "GB-SCT";
Country["GB-WLS"] = "GB-WLS";
Country["GB"] = "GB";
Country["GD"] = "GD";
Country["GE"] = "GE";
Country["GF"] = "GF";
Country["GG"] = "GG";
Country["GH"] = "GH";
Country["GI"] = "GI";
Country["GL"] = "GL";
Country["GM"] = "GM";
Country["GN"] = "GN";
Country["GP"] = "GP";
Country["GQ"] = "GQ";
Country["GR"] = "GR";
Country["GS"] = "GS";
Country["GT"] = "GT";
Country["GU"] = "GU";
Country["GW"] = "GW";
Country["GY"] = "GY";
Country["HK"] = "HK";
Country["HN"] = "HN";
Country["HR"] = "HR";
Country["HT"] = "HT";
Country["HU"] = "HU";
Country["ID"] = "ID";
Country["IE"] = "IE";
Country["IL"] = "IL";
Country["IM"] = "IM";
Country["IN"] = "IN";
Country["IO"] = "IO";
Country["IQ"] = "IQ";
Country["IR"] = "IR";
Country["IS"] = "IS";
Country["IT"] = "IT";
Country["JE"] = "JE";
Country["JM"] = "JM";
Country["JO"] = "JO";
Country["JP"] = "JP";
Country["KE"] = "KE";
Country["KG"] = "KG";
Country["KH"] = "KH";
Country["KI"] = "KI";
Country["KM"] = "KM";
Country["KN"] = "KN";
Country["KP"] = "KP";
Country["KR"] = "KR";
Country["KW"] = "KW";
Country["KY"] = "KY";
Country["KZ"] = "KZ";
Country["LA"] = "LA";
Country["LB"] = "LB";
Country["LC"] = "LC";
Country["LI"] = "LI";
Country["LK"] = "LK";
Country["LR"] = "LR";
Country["LS"] = "LS";
Country["LT"] = "LT";
Country["LU"] = "LU";
Country["LV"] = "LV";
Country["LY"] = "LY";
Country["MA"] = "MA";
Country["MC"] = "MC";
Country["MD"] = "MD";
Country["ME"] = "ME";
Country["MF"] = "MF";
Country["MG"] = "MG";
Country["MH"] = "MH";
Country["MK"] = "MK";
Country["ML"] = "ML";
Country["MM"] = "MM";
Country["MN"] = "MN";
Country["MO"] = "MO";
Country["MP"] = "MP";
Country["MQ"] = "MQ";
Country["MR"] = "MR";
Country["MS"] = "MS";
Country["MT"] = "MT";
Country["MU"] = "MU";
Country["MV"] = "MV";
Country["MW"] = "MW";
Country["MX"] = "MX";
Country["MY"] = "MY";
Country["MZ"] = "MZ";
Country["NA"] = "NA";
Country["NC"] = "NC";
Country["NE"] = "NE";
Country["NF"] = "NF";
Country["NG"] = "NG";
Country["NI"] = "NI";
Country["NL"] = "NL";
Country["NO"] = "NO";
Country["NP"] = "NP";
Country["NR"] = "NR";
Country["NU"] = "NU";
Country["NZ"] = "NZ";
Country["OM"] = "OM";
Country["PA"] = "PA";
Country["PE"] = "PE";
Country["PF"] = "PF";
Country["PG"] = "PG";
Country["PH"] = "PH";
Country["PK"] = "PK";
Country["PL"] = "PL";
Country["PM"] = "PM";
Country["PN"] = "PN";
Country["PR"] = "PR";
Country["PS"] = "PS";
Country["PT"] = "PT";
Country["PW"] = "PW";
Country["PY"] = "PY";
Country["QA"] = "QA";
Country["RE"] = "RE";
Country["RO"] = "RO";
Country["RS"] = "RS";
Country["RU"] = "RU";
Country["RW"] = "RW";
Country["SA"] = "SA";
Country["SB"] = "SB";
Country["SC"] = "SC";
Country["SD"] = "SD";
Country["SE"] = "SE";
Country["SG"] = "SG";
Country["SH"] = "SH";
Country["SI"] = "SI";
Country["SK"] = "SK";
Country["SL"] = "SL";
Country["SM"] = "SM";
Country["SN"] = "SN";
Country["SO"] = "SO";
Country["SR"] = "SR";
Country["SS"] = "SS";
Country["ST"] = "ST";
Country["SV"] = "SV";
Country["SX"] = "SX";
Country["SY"] = "SY";
Country["SZ"] = "SZ";
Country["TC"] = "TC";
Country["TD"] = "TD";
Country["TF"] = "TF";
Country["TG"] = "TG";
Country["TH"] = "TH";
Country["TJ"] = "TJ";
Country["TK"] = "TK";
Country["TL"] = "TL";
Country["TM"] = "TM";
Country["TN"] = "TN";
Country["TO"] = "TO";
Country["TR"] = "TR";
Country["TT"] = "TT";
Country["TV"] = "TV";
Country["TW"] = "TW";
Country["TZ"] = "TZ";
Country["UA"] = "UA";
Country["UG"] = "UG";
Country["US"] = "US";
Country["UY"] = "UY";
Country["UZ"] = "UZ";
Country["VA"] = "VA";
Country["VC"] = "VC";
Country["VE"] = "VE";
Country["VG"] = "VG";
Country["VI"] = "VI";
Country["VN"] = "VN";
Country["VU"] = "VU";
Country["WF"] = "WF";
Country["WS"] = "WS";
Country["YE"] = "YE";
Country["ZA"] = "ZA";
Country["ZM"] = "ZM";
Country["ZW"] = "ZW";
Country["default"] = "default";
})(Country || (Country = {}));
// TODO: Merge this into Country directly
/**
* Map object which holds flag id's for {@link Country} enum members
*
* @see
* https://github.com/ddnet/ddnet/blob/master/data/countryflags/index.txt
*/
export const CountryFlagsMap = {
'default': -1,
'GB-ENG': 901,
'GB-NIR': 902,
'GB-SCT': 903,
'GB-WLS': 904,
'ES-CT': 906,
'ES-GA': 907,
'EU': 905,
'AF': 4,
'AX': 248,
'AL': 8,
'DZ': 12,
'AS': 16,
'AD': 20,
'AO': 24,
'AQ': 10,
'AI': 660,
'AG': 28,
'AR': 32,
'AM': 51,
'AW': 533,
'AU': 36,
'AT': 40,
'AZ': 31,
'BS': 44,
'BH': 48,
'BD': 50,
'BB': 52,
'BY': 112,
'BE': 56,
'BZ': 84,
'BJ': 204,
'BM': 60,
'BT': 64,
'BO': 68,
'BA': 70,
'BW': 72,
'BR': 76,
'IO': 86,
'BN': 96,
'BG': 100,
'BF': 854,
'BI': 108,
'KH': 116,
'CM': 120,
'CA': 124,
'CV': 132,
'KY': 136,
'CF': 140,
'TD': 148,
'CL': 152,
'CN': 156,
'CX': 162,
'CC': 166,
'CO': 170,
'KM': 174,
'CG': 178,
'CD': 180,
'CK': 184,
'CR': 188,
'CI': 384,
'HR': 191,
'CU': 192,
'CW': 531,
'CY': 196,
'CZ': 203,
'DK': 208,
'DJ': 262,
'DM': 212,
'DO': 214,
'EC': 218,
'EG': 818,
'SV': 222,
'GQ': 226,
'ER': 232,
'EE': 233,
'ET': 231,
'FK': 238,
'FO': 234,
'FJ': 242,
'FI': 246,
'FR': 250,
'GF': 254,
'PF': 258,
'TF': 260,
'GA': 266,
'GM': 270,
'GE': 268,
'DE': 276,
'GH': 288,
'GI': 292,
'GR': 300,
'GL': 304,
'GD': 308,
'GP': 312,
'GU': 316,
'GT': 320,
'GG': 831,
'GN': 324,
'GW': 624,
'GY': 328,
'HT': 332,
'VA': 336,
'HN': 340,
'HK': 344,
'HU': 348,
'IS': 352,
'IN': 356,
'ID': 360,
'IR': 364,
'IQ': 368,
'IE': 372,
'IM': 833,
'IL': 376,
'IT': 380,
'JM': 388,
'JP': 392,
'JE': 832,
'JO': 400,
'KZ': 398,
'KE': 404,
'KI': 296,
'KP': 408,
'KR': 410,
'KW': 414,
'KG': 417,
'LA': 418,
'LV': 428,
'LB': 422,
'LS': 426,
'LR': 430,
'LY': 434,
'LI': 438,
'LT': 440,
'LU': 442,
'MO': 446,
'MK': 807,
'MG': 450,
'MW': 454,
'MY': 458,
'MV': 462,
'ML': 466,
'MT': 470,
'MH': 584,
'MQ': 474,
'MR': 478,
'MU': 480,
'MX': 484,
'FM': 583,
'MD': 498,
'MC': 492,
'MN': 496,
'ME': 499,
'MS': 500,
'MA': 504,
'MZ': 508,
'MM': 104,
'NA': 516,
'NR': 520,
'NP': 524,
'NL': 528,
'NC': 540,
'NZ': 554,
'NI': 558,
'NE': 562,
'NG': 566,
'NU': 570,
'NF': 574,
'MP': 580,
'NO': 578,
'OM': 512,
'PK': 586,
'PW': 585,
'PA': 591,
'PG': 598,
'PY': 600,
'PE': 604,
'PH': 608,
'PN': 612,
'PL': 616,
'PT': 620,
'PR': 630,
'PS': 275,
'QA': 634,
'RE': 638,
'RO': 642,
'RU': 643,
'RW': 646,
'BL': 652,
'SH': 654,
'KN': 659,
'LC': 662,
'MF': 663,
'PM': 666,
'VC': 670,
'WS': 882,
'SM': 674,
'ST': 678,
'SA': 682,
'SN': 686,
'RS': 688,
'SC': 690,
'SL': 694,
'SG': 702,
'SX': 534,
'SK': 703,
'SI': 705,
'SB': 90,
'SO': 706,
'SS': 737,
'ZA': 710,
'GS': 239,
'ES': 724,
'LK': 144,
'SD': 736,
'SR': 740,
'SZ': 748,
'SE': 752,
'CH': 756,
'SY': 760,
'TW': 158,
'TJ': 762,
'TZ': 834,
'TH': 764,
'TL': 626,
'TG': 768,
'TK': 772,
'TO': 776,
'TT': 780,
'TN': 788,
'TR': 792,
'TM': 795,
'TC': 796,
'TV': 798,
'UG': 800,
'UA': 804,
'AE': 784,
'GB': 826,
'US': 840,
'UY': 858,
'UZ': 860,
'VU': 548,
'VE': 862,
'VN': 704,
'VG': 92,
'VI': 850,
'WF': 876,
'EH': 732,
'YE': 887,
'ZM': 894,
'ZW': 716
};
/**
* Helper function to translate {@link Country} enum member keys to country id's and vice-versa
*/
export function getCountryOrId(identifier) {
if (typeof identifier === 'number') {
const n = Object.entries(CountryFlagsMap).find(entry => entry[1] === identifier)?.[0];
if (!n)
return Country.default;
return Country[n];
}
return CountryFlagsMap[identifier];
}
/**
* Represents map tiles.
*
* @see
* https://github.com/ddnet/ddnet-web/tree/master/www/tiles
*/
export var Tile;
(function (Tile) {
Tile["BONUS"] = "BONUS";
Tile["BOOST"] = "BOOST";
Tile["CHECKPOINT_FIRST"] = "CHECKPOINT_FIRST";
Tile["CRAZY_SHOTGUN"] = "CRAZY_SHOTGUN";
Tile["DEATH"] = "DEATH";
Tile["DFREEZE"] = "DFREEZE";
Tile["DOOR"] = "DOOR";
Tile["DRAGGER"] = "DRAGGER";
Tile["EHOOK_START"] = "EHOOK_START";
Tile["HIT_END"] = "HIT_END";
Tile["JETPACK_START"] = "JETPACK_START";
Tile["JUMP"] = "JUMP";
Tile["LASER_STOP"] = "LASER_STOP";
Tile["NPC_START"] = "NPC_START";
Tile["NPH_START"] = "NPH_START";
Tile["OLDLASER"] = "OLDLASER";
Tile["PLASMAE"] = "PLASMAE";
Tile["PLASMAF"] = "PLASMAF";
Tile["PLASMAU"] = "PLASMAU";
Tile["POWERUP_NINJA"] = "POWERUP_NINJA";
Tile["SOLO_START"] = "SOLO_START";
Tile["STOP"] = "STOP";
Tile["SUPER_START"] = "SUPER_START";
Tile["SWITCH"] = "SWITCH";
Tile["SWITCH_TIMED"] = "SWITCH_TIMED";
Tile["TELECHECK"] = "TELECHECK";
Tile["TELECHECKIN"] = "TELECHECKIN";
Tile["TELEIN"] = "TELEIN";
Tile["TELEINEVIL"] = "TELEINEVIL";
Tile["TELEINHOOK"] = "TELEINHOOK";
Tile["TELEINWEAPON"] = "TELEINWEAPON";
Tile["TELE_GRENADE"] = "TELE_GRENADE";
Tile["TELE_GUN"] = "TELE_GUN";
Tile["TELE_LASER"] = "TELE_LASER";
Tile["THROUGH"] = "THROUGH";
Tile["THROUGH_ALL"] = "THROUGH_ALL";
Tile["TUNE"] = "TUNE";
Tile["WALLJUMP"] = "WALLJUMP";
Tile["WEAPON_GRENADE"] = "WEAPON_GRENADE";
Tile["WEAPON_RIFLE"] = "WEAPON_RIFLE";
Tile["WEAPON_SHOTGUN"] = "WEAPON_SHOTGUN";
Tile["UNKNOWN_TILE"] = "UNKNOWN_TILE";
})(Tile || (Tile = {}));
/**
* @param kind The kind of image wanted, this is used at run-time to determine which url gets returned for overlapping members.
* @typeParam T Used in combination with the {@link kind} param to also determine the kind of image wanted at compile-time.
*/
export function getImageUrl(eMem, kind) {
if (kind === 'country')
return `https://raw.githubusercontent.com/ddnet/ddnet/master/data/countryflags/${eMem}.png`;
if (kind === 'region')
return `https://raw.githubusercontent.com/ddnet/ddnet-web/master/www/countryflags/${eMem}.png`;
if (kind === 'tile')
return `https://raw.githubusercontent.com/ddnet/ddnet-web/master/www/tiles/${eMem}.png`;
throw new DDNetError(`Unknown error.`);
}
/**
* Splits a mapper name string into an array of mapper names.
*
* @see
* https://github.com/ddnet/ddnet-scripts/blob/8e0909edbeb5d7a6446349dc66a3beb0f5ddccc7/servers/scripts/ddnet.py#L213
*/
export function splitMappers(mapperNames) {
let names = mapperNames.split(', ');
if (names.length) {
names = names.slice(0, -1).concat(names[names.length - 1].split(' & '));
}
return names;
}
/**
* Calculates map points reward based on difficulty (server type) and star count.
*
* @see
* https://ddnet.org/ranks/fun/#points
*/
export function calculatePoints(type, stars) {
// [multiplier, offset]
const multiplierAndOffsetMap = {
[Type.novice]: [1, 0],
[Type.moderate]: [2, 5],
[Type.brutal]: [3, 15],
[Type.insane]: [4, 30],
[Type.dummy]: [5, 5],
[Type.ddmaxEasy]: [4, 0],
[Type.ddmaxNext]: [4, 0],
[Type.ddmaxPro]: [4, 0],
[Type.ddmaxNut]: [4, 0],
[Type.oldschool]: [6, 0],
[Type.solo]: [4, 0],
[Type.race]: [2, 0],
[Type.fun]: [0, 0],
[Type.unknown]: [-1, -1]
};
const [multiplier, offset] = multiplierAndOffsetMap[type];
return stars * multiplier + offset;
}
/**
* Formats an array of strings into a list.
*
* @example
* ```ts
* const authors = ["Sans3108", "urg"];
* console.log(formatStringList(authors)); // 'Sans3108 & urg'
*
* const authors = ["Sans3108", "urg", "Meloƞ"];
* console.log(formatStringList(authors)); // 'Sans3108, urg & Meloƞ'
* ```
*/
export function formatStringList(strings) {
if (strings.length === 0)
return '';
if (strings.length === 1)
return strings[0];
if (strings.length === 2)
return `${strings[0]} & ${strings[1]}`;
return `${strings.slice(0, strings.length - 1).join(', ')} & ${strings[strings.length - 1]}`;
}
//# sourceMappingURL=util.js.map