const isNull = (obj) => obj === null;
const isUndefined = (obj) => typeof obj === 'undefined';
const isNullOrUndefined = (obj) => isUndefined(obj) || isNull(obj);
const isObject = (obj) => !isNullOrUndefined(obj) && typeof obj === 'object' && !Array.isArray(obj)
function stringify(data){
switch (typeof data) {
case 'undefined':
return 'undefined'
case 'boolean':
return data ? 'true' : 'false'
case 'number':
return String(data)
case 'string':
return data
case 'symbol':
return data.toString()
case 'function':
return data.toString()
case 'object':
if (isNull(data)) {
return 'null'
}
if (data instanceof Error) {
return data.toString()
}
if (data instanceof Date) {
return data.toISOString()
}
return JSON.stringify(data, null, 2)
default:
return 'unknown'
}
}
function escapeRegex(str){
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
function hasFunction(obj, method) {
return (
isObject(obj) &&
method in obj &&
typeof obj[method] === 'function'
);
};
Date.prototype.format = function (fmt) {
const padZero = (num) => num.toString().padStart(2, '0');
const map = {
'YYYY': this.getFullYear(),
'MM': padZero(this.getMonth() + 1),
'DD': padZero(this.getDate()),
'HH': padZero(this.getHours()),
'mm': padZero(this.getMinutes()),
'ss': padZero(this.getSeconds())
};
return fmt.replace(/YYYY|MM|DD|HH|mm|ss/g, (key) => map[key]);
};
/**
* Replace string variable
* @param {Record<string, unknown>} replacements
* @returns {string}
* @example
* 'Hello AAAnameBBB'.replaceVariable({name: 'World'},'AAA','BBB') // 'Hello World'
*/
String.prototype.replaceVariable = function (replacements, prefix = '%#', suffix = '#%') {
let current = this.toString();
prefix = escapeRegex(prefix);
suffix = escapeRegex(suffix);
const seen = new Set();
const patterns = Object.keys(replacements).map(key => {
const escKey = escapeRegex(key);
return {
value: replacements[key],
placeholderRegex: new RegExp(
`${prefix}${escKey}(?=(?::.*?${suffix}|${suffix}))(?::.*?)?${suffix}`,
"gs"
),
placeholderFormatRegex: new RegExp(
`(?<=${prefix}${escKey}(?=(?::.*?${suffix}|${suffix})):).*?(?=${suffix})`,
"gs"
)
};
});
while (true) {
if (seen.has(current)) break;
seen.add(current);
let next = current;
for (const { value, placeholderRegex, placeholderFormatRegex } of patterns) {
if (placeholderRegex.test(next)) {
let format = next.match(placeholderFormatRegex)
if (!isNullOrUndefined(format) && format.length != 0 && hasFunction(value, 'format')) {
next = next.replace(placeholderRegex, stringify(value.format(format[0])));
} else {
next = next.replace(placeholderRegex, stringify(value instanceof Date ? value.format('YYYY-MM-DD') : value));
}
}
}
if (current === next) break;
current = next;
}
return current;
};
var example = 'Hello ${name}! ${time}'.replaceVariable({
name: 'World',
time: new Date('2025-05-09T12:28:12')
},'${','}');
console.log(example);