UNPKG

replace-regex

Version:

TS compatible modern nodeJS find-and-replace in files with Regex & Glob support

83 lines (82 loc) 2.57 kB
import fastGlob from 'fast-glob'; import { isArray, isFunction, isString } from 'is-what'; import * as fs from 'node:fs/promises'; /** * async use fast-glob to get all files */ async function getPathsAsync(patterns, options) { const { ignore, disableGlobs, fastGlobOptions } = options; // disable globs, just ensure file(s) name if (disableGlobs) return isString(patterns) ? [patterns] : patterns; return await fastGlob(patterns, { ignore, ...fastGlobOptions }); } /** * replace main */ function replaceFactory(options) { const { contents, from, to, file, ignoreCase } = options; const result = { file, changed: false, matchCount: 0, replaceCount: 0, }; const _from = isFunction(from) ? from(file) : from; const flags = ignoreCase ? 'gi' : 'g'; const fromRegex = isString(_from) ? new RegExp(_from, flags) : _from; const matches = contents.match(fromRegex); if (matches) { const replacements = matches.filter((match) => match !== to); result.matchCount = matches.length; result.replaceCount = replacements.length; } const newContents = isFunction(to) ? contents.replace(fromRegex, (match) => to(match, file)) : contents.replace(fromRegex, to); result.changed = newContents !== contents; return { result, newContents, }; } /** * async replace string in single file */ async function replaceFileAsync(options) { const { file, from, to, dry, ignoreCase } = options; const contents = await fs.readFile(file); // replace action const { result, newContents } = replaceFactory({ contents: contents.toString(), from, to, file, ignoreCase, }); if (!result.changed || dry) return result; // write action await fs.writeFile(file, newContents); return result; } /** * Uses fast-glob to find and replace text in files. Supports RegExp. */ export async function replaceRegex(options) { const { files, from, dry, to, ignoreCase } = options; // dry mode, do not replace if (dry) console.log('[dry mode] no files will be overwritten'); const foundFiles = await getPathsAsync(files, options); const fromClauses = isArray(from) ? from : [from]; const results = []; for (const from of fromClauses) { for (const file of foundFiles) { results.push(replaceFileAsync({ file, from, to, dry, ignoreCase })); } } return await Promise.all(results); }