Refactoring: split 'Utils' into multiple files; fix some stray uppercase-method names

This commit is contained in:
Pieter Vander Vennet 2025-08-01 04:02:09 +02:00
parent 81be4db044
commit 3ec89826e4
97 changed files with 884 additions and 921 deletions

View file

@ -1,4 +1,6 @@
import DOMPurify from "dompurify"
import { Lists } from "./Utils/Lists"
import { Strings } from "./Utils/Strings"
export class Utils {
/**
@ -109,7 +111,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
return <T>parsed
}
static EncodeXmlValue(str) {
static encodeXmlValue(str) {
if (typeof str !== "string") {
str = "" + str
}
@ -122,26 +124,11 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
.replace(/'/g, "&apos;")
}
/**
* Gives a clean float, or undefined if parsing fails
* @param str
*/
static asFloat(str): number {
if (str) {
const i = parseFloat(str)
if (isNaN(i)) {
return undefined
}
return i
}
return undefined
public static upper(str: string) {
return str.substring(0, 1).toUpperCase() + str.substring(1)
}
public static Upper(str: string) {
return str.substr(0, 1).toUpperCase() + str.substr(1)
}
public static TwoDigits(i: number) {
public static twoDigits(i: number) {
if (i < 10) {
return "0" + i
}
@ -151,16 +138,16 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
/**
* Converts a number to a number with precisely 7 decimals
*
* Utils.Round7(12.123456789) // => 12.1234568
* Utils.round7(12.123456789) // => 12.1234568
*/
public static Round7(i: number): number {
public static round7(i: number): number {
if (i == undefined) {
return undefined
}
return Math.round(i * 10000000) / 10000000
}
public static Times(f: (i: number) => string, count: number): string {
public static times(f: (i: number) => string, count: number): string {
let res = ""
for (let i = 0; i < count; i++) {
res += f(i)
@ -168,7 +155,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
return res
}
public static TimesT<T>(count: number, f: (i: number) => T): T[] {
public static timesT<T>(count: number, f: (i: number) => T): T[] {
const res: T[] = []
for (let i = 0; i < count; i++) {
res.push(f(i))
@ -176,16 +163,8 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
return res
}
/**
* Creates a shallow copy of the array. All elements that are not undefined/null will be in the new list
* @param array
* @constructor
*/
public static NoNull<T>(array: ReadonlyArray<T> | undefined): T[] | undefined
public static NoNull(array: undefined): undefined
public static NoNull<T>(array: ReadonlyArray<T>): T[]
public static NoNull<T>(array: ReadonlyArray<T>): NonNullable<T>[] {
return <NonNullable<T>[]>(<unknown>array?.filter((o) => o !== undefined && o !== null))
public static noNull<T>(array: ReadonlyArray<T>): NonNullable<T>[] {
return Lists.noNull(array)
}
public static Hist(array: ReadonlyArray<string>): Map<string, number> {
@ -195,29 +174,6 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
}
return hist
}
/**
* Removes all empty strings from this list
* If undefined or null is given, an empty list is returned
*
* Utils.NoEmpty(undefined) // => []
* Utils.NoEmpty(["abc","","def", null]) // => ["abc","def", null]
*
*/
public static NoEmpty(array: string[]): string[] {
const ls: string[] = []
if (!array) {
return ls
}
for (const t of array) {
if (t === "") {
continue
}
ls.push(t)
}
return ls
}
public static EllipsesAfter(str: string, l: number = 100) {
if (str === undefined || str === null) {
return undefined
@ -297,28 +253,6 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
}
return str
}
/**
* Creates a new array with all elements from 'arr' in such a way that every element will be kept only once
* Elements are returned in the same order as they appear in the lists.
* Null/Undefined is returned as is. If an emtpy array is given, a new empty array will be returned
*/
public static Dedup(arr: NonNullable<string[]>): NonNullable<string[]>
public static Dedup(arr: undefined): undefined
public static Dedup(arr: string[] | undefined): string[] | undefined
public static Dedup(arr: string[]): string[] {
if (arr === undefined || arr === null) {
return arr
}
const newArr = []
for (const string of arr) {
if (newArr.indexOf(string) < 0) {
newArr.push(string)
}
}
return newArr
}
public static DedupT<T>(arr: T[]): T[] {
if (!arr) {
return arr
@ -359,7 +293,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
uniq.push(img)
}
} else {
const ksNoNull = Utils.NoNull(ks)
const ksNoNull = Lists.noNull(ks)
const hasBeenSeen = ksNoNull.some((k) => seen.has(k))
if (!hasBeenSeen) {
uniq.push(img)
@ -1213,7 +1147,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
if (days > 0) {
return days + "days" + " " + hours + "h"
}
return hours + ":" + Utils.TwoDigits(minutes) + ":" + Utils.TwoDigits(seconds)
return hours + ":" + Utils.twoDigits(minutes) + ":" + Utils.twoDigits(seconds)
}
public static toHumanByteSize(bytes: number): string {
@ -1247,9 +1181,9 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
const date =
lastWeek.getFullYear() +
"-" +
Utils.TwoDigits(lastWeek.getMonth() + 1) +
Utils.twoDigits(lastWeek.getMonth() + 1) +
"-" +
Utils.TwoDigits(lastWeek.getDate())
Utils.twoDigits(lastWeek.getDate())
let osmcha_link = `"date__gte":[{"label":"${date}","value":"${date}"}],"editor":[{"label":"mapcomplete","value":"mapcomplete"}]`
if (theme !== undefined) {
osmcha_link =
@ -1833,16 +1767,6 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
}
return 50 * Math.round(number / 50)
}
public static NoNullInplace<T>(items: T[]): T[] {
for (let i = items.length - 1; i >= 0; i--) {
if (items[i] === null || items[i] === undefined || items[i] === "") {
items.splice(i, 1)
}
}
return items
}
/**
* Removes or rewrites some characters in links, as some blink/chromium based browsers are picky about them
*
@ -1860,8 +1784,6 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
return href
}
private static emojiRegex = /[\p{Extended_Pictographic}🛰]/u
/**
* Returns 'true' if the given string contains at least one and only emoji characters
*
@ -1870,19 +1792,9 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
* Utils.isEmoji("🍕") // => true
*/
public static isEmoji(string: string) {
return Utils.emojiRegex.test(string) || Utils.isEmojiFlag(string)
return Strings.isEmoji(string)
}
/**
* Utils.isEmojiFlag("🇧🇪") // => true
*/
public static isEmojiFlag(string: string) {
return /[🇦-🇿]{2}/u.test(string) // flags, see https://stackoverflow.com/questions/53360006/detect-with-regex-if-emoji-is-country-flag
}
public static concat<T>(param: T[][]): T[] {
return [].concat(...param)
}
/**
*
@ -1905,9 +1817,4 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
return <T>copy
}
public static pass(){
// Does nothing
}
}