UNPKG

replace-in-file

Version:

A simple utility to quickly replace text in one or more files.

173 lines (150 loc) 4.35 kB
import path from 'node:path' import fs from 'node:fs/promises' import fsSync from 'node:fs' /** * Helper to load options from a config file */ export async function loadConfig(file) { //No config file provided? if (!file) { throw new Error(`No config file provided`) } //Read file const json = await fs.readFile(path.resolve(file), 'utf8') return JSON.parse(json) } /** * Helper to convert a string to Regex if it matches the pattern */ export function stringToRegex(str) { //Array given if (Array.isArray(str)) { return str.map(stringToRegex) } //Not a string, or no match const regexMatch = /.*\/([gimyus]*)$/ if (typeof str !== 'string' || !str.match(regexMatch)) { return str } //Extract flags and pattern const flags = str.replace(/.*\/([gimyus]*)$/, '$1') const pattern = str.replace(new RegExp(`^/(.*?)/${flags}$`), '$1') //Return regex return new RegExp(pattern, flags) } /** * Parse config */ export function parseConfig(config) { //Validate config if (typeof config !== 'object' || config === null) { throw new Error('Must specify configuration object') } //Fix glob config.glob = config.glob || {} //Extract data const {files, getTargetFile, from, to, processor, processorAsync, ignore, encoding} = config if (typeof processor !== 'undefined') { if (typeof processor !== 'function' && !Array.isArray(processor)) { throw new Error(`Processor should be either a function or an array of functions`) } } else if (typeof processorAsync !== 'undefined') { if (typeof processorAsync !== 'function' && !Array.isArray(processorAsync)) { throw new Error(`ProcessorAsync should be either a function or an array of functions`) } } else { if (typeof files === 'undefined') { throw new Error('Must specify file or files') } if (typeof from === 'undefined') { throw new Error('Must specify string or regex to replace') } if (typeof to === 'undefined') { throw new Error('Must specify a replacement (can be blank string)') } if (typeof getTargetFile !== 'undefined' && typeof getTargetFile !== 'function') { throw new Error(`Target file transformation parameter should be a function that takes the source file path as argument and returns the target file path`) } } //Ensure arrays if (!Array.isArray(files)) { config.files = [files] } if (!Array.isArray(ignore)) { if (typeof ignore === 'undefined') { config.ignore = [] } else { config.ignore = [ignore] } } //Since we can't store Regexp in JSON, convert from string if needed config.from = stringToRegex(from) //Use default encoding if invalid if (typeof encoding !== 'string' || encoding === '') { config.encoding = 'utf-8' } //Merge config with defaults return Object.assign({}, { ignore: [], encoding: 'utf-8', disableGlobs: false, allowEmptyPaths: false, countMatches: false, verbose: false, quiet: false, dry: false, glob: {}, cwd: null, getTargetFile: source => source, fs, fsSync, }, config) } /** * Combine CLI script arguments with config options */ export function combineConfig(config, argv) { //Extract options from config let { from, to, files, ignore, encoding, verbose, allowEmptyPaths, disableGlobs, dry, quiet, } = config //Get from/to parameters from CLI args if not defined in options if (typeof from === 'undefined') { from = argv._.shift() } if (typeof to === 'undefined') { to = argv._.shift() } //Get files and ignored files if (typeof files === 'undefined') { files = argv._ } if (typeof ignore === 'undefined' && typeof argv.ignore !== 'undefined') { ignore = argv.ignore } //Other parameters if (typeof encoding === 'undefined') { encoding = argv.encoding } if (typeof disableGlobs === 'undefined') { disableGlobs = !!argv.disableGlobs } if (typeof verbose === 'undefined') { verbose = !!argv.verbose } if (typeof dry === 'undefined') { dry = !!argv.dry } if (typeof quiet === 'undefined') { quiet = !!argv.quiet } //Return through parser to validate return parseConfig({ from, to, files, ignore, encoding, verbose, allowEmptyPaths, disableGlobs, dry, quiet, }) }