2026-02-15 22:46:25 +00:00
import { Exception } from "./Exception" ;
2025-11-12 21:12:36 +00:00
export abstract class StringTools {
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-unsafe-assignment -- regex-parser is a CommonJS module without ESM support
private static RegexParser : ( input : string ) = > RegExp = require ( "regex-parser" ) ;
public static isValidJson ( str : string ) : boolean {
try {
JSON . parse ( str ) ;
} catch {
return false ;
}
return true ;
}
public static dateToString ( date : Date , includeTime : boolean = true ) : string {
if ( includeTime ) {
return date . toLocaleString ( 'sv-SE' , {
year : 'numeric' ,
month : '2-digit' ,
day : '2-digit' ,
hour : '2-digit' ,
minute : '2-digit' ,
second : '2-digit'
} ) . replace ( /[:\s]/g , '-' ) ;
} else {
return date . toLocaleDateString ( 'sv-SE' , {
year : 'numeric' ,
month : '2-digit' ,
day : '2-digit'
} ) . replace ( /[:\s]/g , '-' ) ;
}
}
public static escapeRegex ( string : string ) : string {
return string . replace ( /[.*+?^${}()|[\]\\]/g , "\\$&" ) ;
}
2026-02-20 00:32:44 +00:00
// Builds a regex from a string that matches flexibly on whitespace but strictly on all other characters.
public static toWhitespaceFlexibleRegex ( input : string ) : RegExp {
const pattern = this . escapeRegex ( input ) . replace ( /(\\\s|\s)+/g , "\\s+" ) ;
return new RegExp ( pattern ) ;
}
2025-11-12 21:12:36 +00:00
public static asRegex ( input : string , requiredFlags : string [ ] ) : RegExp | null {
let regex : RegExp ;
try {
regex = this . RegexParser ( input ) ;
let flags = regex . flags ;
for ( const requiredFlag of requiredFlags ) {
if ( ! flags . includes ( requiredFlag ) ) {
flags = flags + requiredFlag ;
}
}
regex = new RegExp ( regex . source , flags ) ;
} catch {
try { // If parsing fails, escape the input and use required flags
regex = new RegExp ( StringTools . escapeRegex ( input ) , requiredFlags . join ( "" ) ) ;
} catch {
return null ;
}
}
return regex ;
}
2026-03-15 19:48:28 +00:00
public static toBase64 ( text : string ) : string {
const bytes = new TextEncoder ( ) . encode ( text ) ;
let binary = "" ;
for ( let i = 0 ; i < bytes . length ; i ++ ) {
binary += String . fromCharCode ( bytes [ i ] ) ;
}
return btoa ( binary ) ;
}
2026-06-28 14:31:07 +00:00
public static toBytes ( input : string ) : Uint8Array {
2026-06-28 14:42:47 +00:00
return new Uint8Array ( this . toBuffer ( input ) ) ;
}
public static toBuffer ( input : string ) : ArrayBuffer {
2025-12-17 18:06:16 +00:00
const binaryString = atob ( input ) ;
2026-06-28 14:42:47 +00:00
const buffer = new ArrayBuffer ( binaryString . length ) ;
const bytes = new Uint8Array ( buffer ) ;
2025-12-17 18:06:16 +00:00
for ( let i = 0 ; i < binaryString . length ; i ++ ) {
bytes [ i ] = binaryString . charCodeAt ( i ) ;
}
2026-06-28 14:42:47 +00:00
return buffer ;
2025-12-17 18:06:16 +00:00
}
2026-02-15 22:46:25 +00:00
public static async computeSHA256Hash ( base64 : string ) : Promise < string > {
2026-06-28 14:42:47 +00:00
const buffer = this . toBuffer ( base64 ) ;
2026-06-28 14:31:07 +00:00
const hashBuffer = await crypto . subtle . digest ( 'SHA-256' , buffer ) ;
2026-02-15 22:46:25 +00:00
const hashArray = Array . from ( new Uint8Array ( hashBuffer ) ) ;
return hashArray . map ( b = > b . toString ( 16 ) . padStart ( 2 , '0' ) ) . join ( '' ) ;
}
public static async resizeB64Image ( base64 : string , mimeType : string , maxWidth : number = 1000 , maxHeight : number = 1000 ) : Promise < string > {
return new Promise ( ( resolve , reject ) = > {
const img = new Image ( ) ;
img . onload = ( ) = > {
let width = img . width ;
let height = img . height ;
if ( width > maxWidth || height > maxHeight ) {
const aspectRatio = width / height ;
if ( width > height ) {
width = maxWidth ;
height = maxWidth / aspectRatio ;
} else {
height = maxHeight ;
width = maxHeight * aspectRatio ;
}
}
2026-07-04 12:27:22 +00:00
const canvas = createEl ( "canvas" ) ;
2026-02-15 22:46:25 +00:00
canvas . width = width ;
canvas . height = height ;
const context = canvas . getContext ( "2d" ) ;
if ( ! context ) {
reject ( Exception . new ( "Failed to get canvas context" ) ) ;
return ;
}
context . drawImage ( img , 0 , 0 , width , height ) ;
const dataURL = canvas . toDataURL ( mimeType , 0.92 ) ;
const base64Only = dataURL . split ( ',' ) [ 1 ] ;
resolve ( base64Only ) ;
} ;
img . onerror = ( ) = > reject ( Exception . new ( "Failed to load image" ) ) ;
if ( ! base64 . startsWith ( 'data:' ) ) {
base64 = ` data: ${ mimeType } ;base64, ${ base64 } ` ;
}
img . src = base64 ;
} ) ;
}
2025-11-12 21:12:36 +00:00
}