packages/extract-svg-sprite-webpack-plugin/lib/utils/replacer.js (85 lines of code) (raw):

const MINI_EXTRACT_MODULE_TYPE = 'css/mini-extract'; module.exports = class Replacer { /** * @param {string} input * @param {string} needle * @return {Array<number>[]} */ static getAllStringOccurrences(input, needle) { const indexes = []; let prevIndex = 0; // eslint-disable-next-line keyword-spacing,no-constant-condition while (true) { const startIndex = input.indexOf(needle, prevIndex); if (startIndex === -1) { break; } const endIndex = startIndex + needle.length; indexes.push([startIndex, endIndex]); prevIndex = endIndex; } return indexes; } /** * @param {NormalModule} module * @param {Compilation} compilation * @return {ReplaceSource} */ static getModuleReplaceSource(module, compilation) { const { dependencyTemplates, outputOptions, requestShortener, runtimeTemplate, moduleGraph, chunkGraph } = compilation; const args = []; // webpack 5 if (moduleGraph && chunkGraph) { args.push({ dependencyTemplates, runtimeTemplate, moduleGraph, chunkGraph }); } else { args.push(dependencyTemplates); // webpack 3 if (!runtimeTemplate) { args.push(outputOptions); args.push(requestShortener); } // webpack 4 else { args.push(runtimeTemplate); } } const cachedSource = module.source(...args); return typeof cachedSource.replace === 'function' ? cachedSource : cachedSource._source; } /** * @param {NormalModule} module * @param {Replacement[]} replacements * @param {Compilation} compilation * @return {NormalModule} */ static replaceInModuleSource(module, replacements, compilation) { if (module.type === MINI_EXTRACT_MODULE_TYPE) { replacements.forEach(({ token, replaceTo }) => { if (module.content.indexOf(token) < 0) { return; } const regExp = new RegExp(token, 'g'); module.content = module.content.replace(regExp, replaceTo); }); return module; } const source = Replacer.getModuleReplaceSource(module, compilation); if (!source) { return module; } const originalSourceContent = module.originalSource().source(); replacements.forEach(({ token, replaceTo }) => { const indexes = Replacer.getAllStringOccurrences( originalSourceContent, token ); indexes.forEach(idx => { const start = idx[0]; const end = idx[1] - 1; /** * source.replacements in webpack <= 4 * source._replacements in webpack 5 */ const sourceReplacements = source.replacements || source._replacements; const alreadyHasReplacement = sourceReplacements.find( r => r[0] === start && r[1] === end && r[2] === replaceTo ); if (alreadyHasReplacement) { return; } source.replace(start, end, replaceTo); }); }); return module; } };