'use strict'; function clearDirtyParam(source) { return source.replace(/:([^ ]+)/, ''); } function escapeRegExp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } function isObject(obj) { return typeof obj === 'object' && !!obj; } function replaceKeyword(source, keyword, value, options = {}) { const { pattern, specElement, exactMatch, templateLiterals } = options; if (pattern instanceof RegExp) { return source.replace(pattern, value); } if (!pattern || !specElement) { return source.replace(new RegExp(`:${keyword}`, 'g'), value); } if (!exactMatch) { keyword = ` *${keyword} *`; } // TODO: change to pattern (?) when all browsers support negative lookbehind const escapePattern = escapeRegExp(pattern).replace(specElement, keyword.toString()); const replacementPattern = `(\\S|)${escapePattern}`; const escapeRegExpPatternWithBegin = new RegExp(`^${escapePattern}$`); return source.replace(new RegExp(replacementPattern, 'g'), (replacement) => { if (escapeRegExpPatternWithBegin.test(replacement)) { return value; } if (replacement[0] === templateLiterals) { return replacement.slice(1); } return `${replacement[0]}${value}`; }); } function replaceKeywordForArrayParams(source, params, options) { for (const i in params) { source = replaceKeyword(source, i, params[i], options); } return source; } function replaceKeywordForNestedObjectParams(source, key, params, options) { Object.entries(params).forEach(([objectKey, objectValue]) => { const replaceKey = `${key}.${objectKey}`; if (isObject(objectValue)) { source = replaceKeywordForNestedObjectParams(source, replaceKey, objectValue, options); } else { source = replaceKeyword(source, replaceKey, objectValue, options); } }); return source; } function replaceKeywordForObjectParams(source, params, options) { Object.entries(params).forEach(([key, value]) => { if (isObject(value)) { source = replaceKeywordForNestedObjectParams(source, key, value, options); } else { source = replaceKeyword(source, key, value, options); } }); return source; } function interpole(source, params, options = { clearDirtyParam: false }) { if (typeof source !== 'string') { return source; } const { clearDirtyParam: needClearDirtyParam, ...otherOptions } = options; if (Array.isArray(params)) { source = replaceKeywordForArrayParams(source, params, otherOptions); } else { source = replaceKeywordForObjectParams(source, params, otherOptions); } if (needClearDirtyParam) { return clearDirtyParam(source); } return source; } module.exports = interpole;