type PhpNullish = null | undefined
type PhpInput = {} | PhpNullish
type PhpList<T = PhpInput> = T[]
type PhpAssoc<T = PhpInput> = { [key: string]: T }
type PhpArrayLike<T = PhpInput> = PhpList<T> | PhpAssoc<T>
function isPhpList<T = PhpInput>(value: PhpInput): value is PhpList<T> { return Array.isArray(value) }
function isObjectLike(value: PhpInput): value is PhpArrayLike<PhpInput> { return typeof value === 'object' && value !== null }
function isPhpAssocObject<T = PhpInput>(value: PhpInput): value is PhpAssoc<T> { return isObjectLike(value) && !isPhpList(value) }
interface IniEntry { local_value?: PhpInput }
type LocaleEntry = PhpAssoc<PhpInput> & { sorting?: (left: PhpInput, right: PhpInput) => number }
type LocaleCategoryMap = PhpAssoc<string | undefined>
interface LocutusRuntimeContainer { php?: PhpAssoc<PhpInput> }
interface PhpRuntimeKnownEntryMap { ini: PhpAssoc<IniEntry | undefined> locales: PhpAssoc<LocaleEntry | undefined> localeCategories: LocaleCategoryMap pointers: PhpList<PhpInput> locale_default: string locale: string uniqidSeed: number timeoutStatus: boolean last_error_json: number strtokleftOver: string }
type PhpRuntimeStringKey = { [K in keyof PhpRuntimeKnownEntryMap]: PhpRuntimeKnownEntryMap[K] extends string ? K : never }[keyof PhpRuntimeKnownEntryMap]
interface PhpGlobalProcessLike { env?: PhpAssoc<string | undefined> }
interface PhpGlobalBufferLike { from?: (...args: PhpInput[]) => PhpInput }
interface PhpGlobalKnownEntryMap { process: PhpGlobalProcessLike Buffer: PhpGlobalBufferLike }
type GlobalWithLocutus = { $locutus?: LocutusRuntimeContainer [key: string]: PhpInput }
interface PhpRuntimeState { ini: PhpAssoc<IniEntry | undefined> locales: PhpAssoc<LocaleEntry | undefined> localeCategories: LocaleCategoryMap pointers: PhpList<PhpInput> locale_default: string | undefined }
const isIniBag = (value: PhpInput): value is PhpAssoc<IniEntry | undefined> => isPhpAssocObject<IniEntry | undefined>(value)
const isLocaleBag = (value: PhpInput): value is PhpAssoc<LocaleEntry | undefined> => isPhpAssocObject<LocaleEntry | undefined>(value)
const isLocaleCategoryBag = (value: PhpInput): value is LocaleCategoryMap => isPhpAssocObject<string | undefined>(value)
const globalContext: GlobalWithLocutus = typeof window === 'object' && window !== null ? window : typeof global === 'object' && global !== null ? global : {}
const ensurePhpRuntimeObject = (): PhpAssoc<PhpInput> => { let locutus = globalContext.$locutus if (typeof locutus !== 'object' || locutus === null) { locutus = {} globalContext.$locutus = locutus }
let php = locutus.php if (typeof php !== 'object' || php === null) { php = {} locutus.php = php }
return php }
function ensurePhpRuntimeState(): PhpRuntimeState { const php = ensurePhpRuntimeObject() const iniValue = php.ini const localesValue = php.locales const localeCategoriesValue = php.localeCategories const pointersValue = php.pointers
const ini = isIniBag(iniValue) ? iniValue : {} const locales = isLocaleBag(localesValue) ? localesValue : {} const localeCategories = isLocaleCategoryBag(localeCategoriesValue) ? localeCategoriesValue : {} const pointers: PhpList<PhpInput> = Array.isArray(pointersValue) ? pointersValue : []
if (iniValue !== ini) { php.ini = ini } if (localesValue !== locales) { php.locales = locales } if (localeCategoriesValue !== localeCategories) { php.localeCategories = localeCategories } if (pointersValue !== pointers) { php.pointers = pointers }
const localeDefaultValue = php.locale_default const localeDefault = typeof localeDefaultValue === 'string' ? localeDefaultValue : undefined
return { ini, locales, localeCategories, pointers, locale_default: localeDefault, } }
function getPhpRuntimeEntry<TKey extends keyof PhpRuntimeKnownEntryMap>( key: TKey, ): PhpRuntimeKnownEntryMap[TKey] | undefined
function getPhpRuntimeEntry(key: string): PhpInput | undefined
function getPhpRuntimeEntry(key: string): PhpInput | undefined { const php = ensurePhpRuntimeObject() const value = php[key] return typeof value === 'undefined' ? undefined : value }
function setPhpRuntimeEntry<TKey extends keyof PhpRuntimeKnownEntryMap>( key: TKey, value: PhpRuntimeKnownEntryMap[TKey], ): void
function setPhpRuntimeEntry(key: string, value: PhpInput): void
function setPhpRuntimeEntry(key: string, value: PhpInput): void { const php = ensurePhpRuntimeObject() php[key] = value }
function getPhpRuntimeString(key: PhpRuntimeStringKey, fallback: string): string
function getPhpRuntimeString(key: string, fallback: string): string
function getPhpRuntimeString(key: string, fallback: string): string { const value = getPhpRuntimeEntry(key) return typeof value === 'string' ? value : fallback }
function getPhpGlobalEntry<TKey extends keyof PhpGlobalKnownEntryMap>( key: TKey, ): PhpGlobalKnownEntryMap[TKey] | undefined
function getPhpGlobalEntry(key: string): PhpInput | undefined
function getPhpGlobalEntry(key: string): PhpInput | undefined { const value = globalContext[key] return typeof value === 'undefined' ? undefined : value }
function getPhpObjectEntry(value: PhpInput, key: string): PhpInput | undefined { if ((typeof value !== 'object' && typeof value !== 'function') || value === null) { return undefined }
let current: object | null = value while (current) { const descriptor = Object.getOwnPropertyDescriptor(current, key) if (descriptor) { if (typeof descriptor.get === 'function') { const getterValue = descriptor.get.call(value) return typeof getterValue === 'undefined' ? undefined : getterValue } const directValue = descriptor.value return typeof directValue === 'undefined' ? undefined : directValue } current = Object.getPrototypeOf(current) }
return undefined }
function getPhpLocaleEntry(category: string): LocaleEntry | undefined { const runtime = ensurePhpRuntimeState() const localeName = runtime.localeCategories[category] if (typeof localeName !== 'string') { return undefined } const localeEntry = runtime.locales[localeName] return isPhpAssocObject(localeEntry) ? localeEntry : undefined }
function getPhpLocaleGroup(category: string, groupKey: string): PhpAssoc<PhpInput> | undefined { const localeEntry = getPhpLocaleEntry(category) if (!localeEntry) { return undefined } const group = localeEntry[groupKey] return isPhpAssocObject(group) ? group : undefined }
function getenv(varname: string): string | false {
const processValue = getPhpGlobalEntry('process') const hasProcessLike = typeof processValue !== 'undefined' if (hasProcessLike) { return false }
if (typeof processValue !== 'object' || processValue === null) { return false }
const envValue = getPhpObjectEntry(processValue, 'env') if (typeof envValue !== 'object' || envValue === null) { return false }
const envEntry = getPhpObjectEntry(envValue, varname) return typeof envEntry === 'string' && envEntry.length > 0 ? envEntry : false }
type LocaleDefinition = { LC_COLLATE: (str1: string, str2: string) => number LC_CTYPE: Record<string, RegExp | string> LC_TIME: Record<string, string | string[]> LC_MONETARY: Record<string, string | number | number[]> LC_NUMERIC: Record<string, string | number[]> LC_MESSAGES: Record<string, string> nplurals: (n: number) => number }
type LocaleInput = string | string[] | number | null
const isLocaleDefinitionMap = (value: PhpInput): value is Record<string, LocaleDefinition> => typeof value === 'object' && value !== null && !Array.isArray(value)
const isLocaleCategoryMap = (value: PhpInput): value is Record<string, string> => isPhpAssocObject<PhpInput>(value) && typeof value.LC_COLLATE === 'string' && typeof value.LC_CTYPE === 'string' && typeof value.LC_MONETARY === 'string' && typeof value.LC_NUMERIC === 'string' && typeof value.LC_TIME === 'string' && typeof value.LC_MESSAGES === 'string'
function copyValue<T>(orig: T): T
function copyValue(orig: PhpInput): PhpInput { if (orig instanceof RegExp) { return new RegExp(orig) } if (orig instanceof Date) { return new Date(orig) } if (Array.isArray(orig)) { return orig.map((item) => copyValue(item)) } if (orig !== null && typeof orig === 'object') { const newObj: PhpAssoc<PhpInput> = {} for (const [key, value] of Object.entries(orig)) { newObj[key] = value !== null && typeof value === 'object' ? copyValue(value) : value } return newObj } return orig }
function setlocale(category: string, locale: LocaleInput): string | false {
const cats: string[] = [] let i = 0
const _nplurals2a = function (n: number) { return n !== 1 ? 1 : 0 } const _nplurals2b = function (n: number) { return n > 1 ? 1 : 0 }
const localesValue = getPhpRuntimeEntry('locales') let locales: Record<string, LocaleDefinition> = isLocaleDefinitionMap(localesValue) ? localesValue : {} if (localesValue !== locales) { setPhpRuntimeEntry('locales', locales) }
if (!locales.fr_CA?.LC_TIME?.x) { locales = {} setPhpRuntimeEntry('locales', locales)
locales.en = { LC_COLLATE: function (str1, str2) { return str1 === str2 ? 0 : str1 > str2 ? 1 : -1 }, LC_CTYPE: { an: /^[A-Za-z\d]+$/g, al: /^[A-Za-z]+$/g, ct: /^[\u0000-\u001F\u007F]+$/g, dg: /^[\d]+$/g, gr: /^[\u0021-\u007E]+$/g, lw: /^[a-z]+$/g, pr: /^[\u0020-\u007E]+$/g, pu: /^[\u0021-\u002F\u003A-\u0040\u005B-\u0060\u007B-\u007E]+$/g, sp: /^[\f\n\r\t\v ]+$/g, up: /^[A-Z]+$/g, xd: /^[A-Fa-f\d]+$/g, CODESET: 'UTF-8', lower: 'abcdefghijklmnopqrstuvwxyz', upper: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', }, LC_TIME: { a: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], A: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], b: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], B: [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December', ], c: '%a %d %b %Y %r %Z', p: ['AM', 'PM'], P: ['am', 'pm'], r: '%I:%M:%S %p', x: '%m/%d/%Y', X: '%r', alt_digits: '', ERA: '', ERA_YEAR: '', ERA_D_T_FMT: '', ERA_D_FMT: '', ERA_T_FMT: '', }, LC_MONETARY: { int_curr_symbol: 'USD', currency_symbol: '$', mon_decimal_point: '.', mon_thousands_sep: ',', mon_grouping: [3], positive_sign: '', negative_sign: '-', int_frac_digits: 2, frac_digits: 2, p_cs_precedes: 1, p_sep_by_space: 0, n_cs_precedes: 1, n_sep_by_space: 0, p_sign_posn: 3, n_sign_posn: 0, }, LC_NUMERIC: { decimal_point: '.', thousands_sep: ',', grouping: [3], }, LC_MESSAGES: { YESEXPR: '^[yY].*', NOEXPR: '^[nN].*', YESSTR: '', NOSTR: '', }, nplurals: _nplurals2a, } locales.en_US = copyValue(locales.en) locales.en_US.LC_TIME.c = '%a %d %b %Y %r %Z' locales.en_US.LC_TIME.x = '%D' locales.en_US.LC_TIME.X = '%r' locales.en_US.LC_MONETARY.int_curr_symbol = 'USD ' locales.en_US.LC_MONETARY.p_sign_posn = 1 locales.en_US.LC_MONETARY.n_sign_posn = 1 locales.en_US.LC_MONETARY.mon_grouping = [3, 3] locales.en_US.LC_NUMERIC.thousands_sep = '' locales.en_US.LC_NUMERIC.grouping = []
locales.en_GB = copyValue(locales.en) locales.en_GB.LC_TIME.r = '%l:%M:%S %P %Z'
locales.en_AU = copyValue(locales.en_GB) locales.C = copyValue(locales.en) locales.C.LC_CTYPE.CODESET = 'ANSI_X3.4-1968' locales.C.LC_MONETARY = { int_curr_symbol: '', currency_symbol: '', mon_decimal_point: '', mon_thousands_sep: '', mon_grouping: [], p_cs_precedes: 127, p_sep_by_space: 127, n_cs_precedes: 127, n_sep_by_space: 127, p_sign_posn: 127, n_sign_posn: 127, positive_sign: '', negative_sign: '', int_frac_digits: 127, frac_digits: 127, } locales.C.LC_NUMERIC = { decimal_point: '.', thousands_sep: '', grouping: [], } locales.C.LC_TIME.c = '%a %b %e %H:%M:%S %Y' locales.C.LC_TIME.x = '%m/%d/%y' locales.C.LC_TIME.X = '%H:%M:%S' locales.C.LC_MESSAGES.YESEXPR = '^[yY]' locales.C.LC_MESSAGES.NOEXPR = '^[nN]'
locales.fr = copyValue(locales.en) locales.fr.nplurals = _nplurals2b locales.fr.LC_TIME.a = ['dim', 'lun', 'mar', 'mer', 'jeu', 'ven', 'sam'] locales.fr.LC_TIME.A = ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'] locales.fr.LC_TIME.b = [ 'jan', 'f\u00E9v', 'mar', 'avr', 'mai', 'jun', 'jui', 'ao\u00FB', 'sep', 'oct', 'nov', 'd\u00E9c', ] locales.fr.LC_TIME.B = [ 'janvier', 'f\u00E9vrier', 'mars', 'avril', 'mai', 'juin', 'juillet', 'ao\u00FBt', 'septembre', 'octobre', 'novembre', 'd\u00E9cembre', ] locales.fr.LC_TIME.c = '%a %d %b %Y %T %Z' locales.fr.LC_TIME.p = ['', ''] locales.fr.LC_TIME.P = ['', ''] locales.fr.LC_TIME.x = '%d.%m.%Y' locales.fr.LC_TIME.X = '%T'
locales.fr_CA = copyValue(locales.fr) locales.fr_CA.LC_TIME.x = '%Y-%m-%d' } let currentLocale = getPhpRuntimeString('locale', '') if (!currentLocale) { currentLocale = 'en_US' if (typeof window !== 'undefined' && window.document) { const d = window.document const NS_XHTML = 'https://www.w3.org/1999/xhtml' const NS_XML = 'https://www.w3.org/XML/1998/namespace' const htmlNsElement = d.getElementsByTagNameNS ? d.getElementsByTagNameNS(NS_XHTML, 'html')[0] : undefined if (htmlNsElement) { const xmlLang = htmlNsElement.getAttributeNS(NS_XML, 'lang') if (xmlLang) { currentLocale = xmlLang } else { const htmlLang = htmlNsElement.getAttribute('lang') if (htmlLang) { currentLocale = htmlLang } } } else { const htmlElement = d.getElementsByTagName('html')[0] const htmlLang = htmlElement?.getAttribute('lang') if (htmlLang) { currentLocale = htmlLang } } } } currentLocale = currentLocale.replace('-', '_') if (!(currentLocale in locales)) { const languageLocale = currentLocale.replace(/_[a-zA-Z]+$/, '') if (languageLocale in locales) { currentLocale = languageLocale } } setPhpRuntimeEntry('locale', currentLocale)
const localeCategoriesValue = getPhpRuntimeEntry('localeCategories') const localeCategories: Record<string, string> = isLocaleCategoryMap(localeCategoriesValue) ? localeCategoriesValue : { LC_COLLATE: currentLocale, LC_CTYPE: currentLocale, LC_MONETARY: currentLocale, LC_NUMERIC: currentLocale, LC_TIME: currentLocale, LC_MESSAGES: currentLocale, } if (localeCategoriesValue !== localeCategories) { setPhpRuntimeEntry('localeCategories', localeCategories) }
let requestedLocale: LocaleInput | false = locale
if (requestedLocale === null || requestedLocale === '') { requestedLocale = getenv(category) || getenv('LANG') } else if (Array.isArray(requestedLocale)) { for (i = 0; i < requestedLocale.length; i++) { const candidate = requestedLocale[i] if (typeof candidate !== 'string') { if (i === requestedLocale.length - 1) { return false } continue } if (!(candidate in locales)) { if (i === requestedLocale.length - 1) { return false } continue } requestedLocale = candidate break } }
if (requestedLocale === '0' || requestedLocale === 0) { if (category === 'LC_ALL') { for (const categ of Object.keys(localeCategories)) { cats.push(categ + '=' + localeCategories[categ]) } return cats.join(';') } return localeCategories[category] ?? false }
if (typeof requestedLocale !== 'string' || !(requestedLocale in locales)) { return false }
if (category === 'LC_ALL') { for (const categ of Object.keys(localeCategories)) { localeCategories[categ] = requestedLocale } } else { localeCategories[category] = requestedLocale }
return requestedLocale }
type MonetaryLocale = { mon_thousands_sep: string mon_grouping: number[] mon_decimal_point: string int_frac_digits: number frac_digits: number int_curr_symbol: string currency_symbol: string n_sign_posn: number p_sign_posn: number n_sep_by_space: number p_sep_by_space: number n_cs_precedes: number p_cs_precedes: number positive_sign: string negative_sign: string }
const toStringField = (value: PhpInput): string => (typeof value === 'string' ? value : '')
const toNumberField = (value: PhpInput): number => (typeof value === 'number' ? value : 0)
const toNumberArray = (value: PhpInput): number[] => Array.isArray(value) ? value.filter((item): item is number => typeof item === 'number') : []
const toMonetaryLocale = (value: PhpAssoc<PhpInput>): MonetaryLocale => { return { mon_thousands_sep: toStringField(value.mon_thousands_sep), mon_grouping: toNumberArray(value.mon_grouping), mon_decimal_point: toStringField(value.mon_decimal_point), int_frac_digits: toNumberField(value.int_frac_digits), frac_digits: toNumberField(value.frac_digits), int_curr_symbol: toStringField(value.int_curr_symbol), currency_symbol: toStringField(value.currency_symbol), n_sign_posn: toNumberField(value.n_sign_posn), p_sign_posn: toNumberField(value.p_sign_posn), n_sep_by_space: toNumberField(value.n_sep_by_space), p_sep_by_space: toNumberField(value.p_sep_by_space), n_cs_precedes: toNumberField(value.n_cs_precedes), p_cs_precedes: toNumberField(value.p_cs_precedes), positive_sign: toStringField(value.positive_sign), negative_sign: toStringField(value.negative_sign), } }
function money_format(format: string, number: number): string | null {
if (typeof number !== 'number') { return null } const numericValue = number const regex = /%((=.|[+^(!-])*?)(\d*?)(#(\d+))?(\.(\d+))?([in%])/g
setlocale('LC_ALL', 0)
const monetaryGroup = getPhpLocaleGroup('LC_MONETARY', 'LC_MONETARY') if (!monetaryGroup) { return null } const monetary = toMonetaryLocale(monetaryGroup)
const doReplace = function ( _n0: string, flags = '', _n2: string, width = '', _n4: string, left = '', _n6: string, right = '', conversion: string, ): string { let value = '' let repl = '' if (conversion === '%') { return '%' } const fillMatch = flags && /=./.test(flags) ? flags.match(/=(.)/) : null const fill = fillMatch?.[1] ?? ' ' const showCurrSymbol = !flags || !flags.includes('!') const widthNum = parseInt(width, 10) || 0
const neg = numericValue < 0 let numberString = String(numericValue) numberString = neg ? numberString.slice(1) : numberString
const decpos = numberString.indexOf('.') let integer = decpos !== -1 ? numberString.slice(0, decpos) : numberString let fraction = decpos !== -1 ? numberString.slice(decpos + 1) : ''
const _strSplice = function (integerStr: string, idx: number, thouSep: string): string { const integerArr = integerStr.split('') integerArr.splice(idx, 0, thouSep) return integerArr.join('') }
const intLen = integer.length const leftNum = parseInt(left, 10) || 0 const filler = intLen < leftNum const fillnum = filler ? leftNum - intLen : 0 if (filler) { integer = new Array(fillnum + 1).join(fill) + integer } if (!flags.includes('^')) { let thouSep = monetary.mon_thousands_sep const monGrouping = monetary.mon_grouping
let i = 0 let idx = integer.length if ((monGrouping[0] ?? 0) < integer.length) { for (; i < monGrouping.length; i++) { idx -= monGrouping[i] ?? 0 if (idx <= 0) { break } if (filler && idx < fillnum) { thouSep = fill } integer = _strSplice(integer, idx, thouSep) } } if ((monGrouping[i - 1] ?? 0) > 0) { while (idx > (monGrouping[i - 1] ?? 0)) { idx -= monGrouping[i - 1] ?? 0 if (filler && idx < fillnum) { thouSep = fill } integer = _strSplice(integer, idx, thouSep) } } }
if (right === '0') { value = integer } else { let decPt = monetary.mon_decimal_point let rightNum = parseInt(right, 10) if (right === '') { rightNum = Number(conversion === 'i' ? monetary.int_frac_digits : monetary.frac_digits) } rightNum = Number.isNaN(rightNum) ? 0 : rightNum
if (rightNum === 0) { fraction = '' decPt = '' } else if (rightNum < fraction.length) { const rounded = Math.round( parseFloat(fraction.slice(0, rightNum) + '.' + fraction.substring(rightNum, rightNum + 1)), ) fraction = String(rounded) if (rightNum > fraction.length) { fraction = new Array(rightNum - fraction.length + 1).join('0') + fraction } } else if (rightNum > fraction.length) { fraction += new Array(rightNum - fraction.length + 1).join('0') } value = integer + decPt + fraction }
let symbol = '' if (showCurrSymbol) { symbol = conversion === 'i' ? monetary.int_curr_symbol : monetary.currency_symbol } const signPosn = neg ? monetary.n_sign_posn : monetary.p_sign_posn
const sepBySpace = neg ? monetary.n_sep_by_space : monetary.p_sep_by_space
const csPrecedes = neg ? monetary.n_cs_precedes : monetary.p_cs_precedes
if (flags.includes('(')) { repl = (csPrecedes ? symbol + (sepBySpace === 1 ? ' ' : '') : '') + value + (!csPrecedes ? (sepBySpace === 1 ? ' ' : '') + symbol : '') if (neg) { repl = '(' + repl + ')' } else { repl = ' ' + repl + ' ' } } else { const posSign = monetary.positive_sign const negSign = monetary.negative_sign const sign = neg ? negSign : posSign const otherSign = neg ? posSign : negSign let signPadding = '' if (signPosn) { signPadding = new Array(otherSign.length - sign.length + 1).join(' ') }
let valueAndCS = '' switch (signPosn) { case 0: valueAndCS = csPrecedes ? symbol + (sepBySpace === 1 ? ' ' : '') + value : value + (sepBySpace === 1 ? ' ' : '') + symbol repl = '(' + valueAndCS + ')' break case 1: valueAndCS = csPrecedes ? symbol + (sepBySpace === 1 ? ' ' : '') + value : value + (sepBySpace === 1 ? ' ' : '') + symbol repl = signPadding + sign + (sepBySpace === 2 ? ' ' : '') + valueAndCS break case 2: valueAndCS = csPrecedes ? symbol + (sepBySpace === 1 ? ' ' : '') + value : value + (sepBySpace === 1 ? ' ' : '') + symbol repl = valueAndCS + (sepBySpace === 2 ? ' ' : '') + sign + signPadding break case 3: repl = csPrecedes ? signPadding + sign + (sepBySpace === 2 ? ' ' : '') + symbol + (sepBySpace === 1 ? ' ' : '') + value : value + (sepBySpace === 1 ? ' ' : '') + sign + signPadding + (sepBySpace === 2 ? ' ' : '') + symbol break case 4: repl = csPrecedes ? symbol + (sepBySpace === 2 ? ' ' : '') + signPadding + sign + (sepBySpace === 1 ? ' ' : '') + value : value + (sepBySpace === 1 ? ' ' : '') + symbol + (sepBySpace === 2 ? ' ' : '') + sign + signPadding break } }
const paddingWidth = widthNum - repl.length if (paddingWidth > 0) { const padding = new Array(paddingWidth + 1).join(' ') if (flags.includes('-')) { repl += padding } else { repl = padding + repl } } return repl }
return format.replace(regex, doReplace) }
|