feat: init

This commit is contained in:
2026-02-13 22:02:30 +01:00
commit 8f9ff830fb
16711 changed files with 3307340 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
'use strict';
/**
* Dependencies
*/
const parseConfig = require('./parse-config');
/**
* Combine CLI script arguments with config options
*/
module.exports = function combineConfig(config, argv) {
//Extract options from config
let {
from, to, files, ignore, encoding, verbose,
allowEmptyPaths, disableGlobs, isRegex, 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 isRegex === 'undefined') {
isRegex = !!argv.isRegex;
}
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, isRegex, dry, quiet,
});
};

View File

@@ -0,0 +1,9 @@
'use strict';
/**
* Error handler
*/
module.exports = function errorHandler(error, exitCode = 1) {
console.error(error);
process.exit(exitCode);
};

View File

@@ -0,0 +1,26 @@
'use strict';
/**
* Dependencies
*/
const globAsync = require('./glob-async');
/**
* Get paths asynchrously
*/
module.exports = function getPathsAsync(patterns, config) {
//Extract relevant config
const {ignore, disableGlobs, allowEmptyPaths, glob: cfg} = config;
//Not using globs?
if (disableGlobs) {
return Promise.resolve(patterns);
}
//Expand globs and flatten paths
return Promise
.all(patterns
.map(pattern => globAsync(pattern, ignore, allowEmptyPaths, cfg)))
.then(paths => [].concat.apply([], paths));
};

View File

@@ -0,0 +1,42 @@
'use strict';
/**
* Dependencies
*/
const glob = require('glob');
/**
* Get paths (sync)
*/
module.exports = function getPathsSync(patterns, config) {
//Extract relevant config
const {ignore, disableGlobs, glob: globConfig, cwd} = config;
//Not using globs?
if (disableGlobs) {
return patterns;
}
//Prepare glob config
const cfg = Object.assign({ignore}, globConfig, {nodir: true});
//Append CWD configuration if given (#56)
//istanbul ignore if
if (cwd) {
cfg.cwd = cwd;
}
//Get paths
const paths = patterns.map(pattern => glob.sync(pattern, cfg));
const flattened = [].concat.apply([], paths);
//Prefix each path with CWD if given (#56)
//istanbul ignore if
if (cwd) {
return flattened.map(path => `${cwd}${path}`);
}
//Return flattened
return flattened;
};

34
node_modules/replace-in-file/lib/helpers/glob-async.js generated vendored Normal file
View File

@@ -0,0 +1,34 @@
'use strict';
/**
* Dependencies
*/
const glob = require('glob');
/**
* Async wrapper for glob
*/
module.exports = function globAsync(pattern, ignore, allowEmptyPaths, cfg) {
//Prepare glob config
cfg = Object.assign({ignore}, cfg, {nodir: true});
//Return promise
return new Promise((resolve, reject) => {
glob(pattern, cfg, (error, files) => {
//istanbul ignore if: hard to make glob error
if (error) {
return reject(error);
}
//Error if no files match, unless allowed
if (!allowEmptyPaths && files.length === 0) {
return reject(new Error('No files match the pattern: ' + pattern));
}
//Resolve
resolve(files);
});
});
};

View File

@@ -0,0 +1,23 @@
'use strict';
/**
* Dependencies
*/
const path = require('path');
/**
* Helper to load options from a config file
*/
module.exports = function loadConfig(file) {
//No config file provided?
if (!file) {
return {};
}
//Resolve path
file = path.resolve(file);
//Try to load
return require(file);
};

View File

@@ -0,0 +1,75 @@
'use strict';
/**
* Get replacement helper
*/
function getReplacement(replace, isArray, i) {
if (isArray && typeof replace[i] === 'undefined') {
return null;
}
if (isArray) {
return replace[i];
}
return replace;
}
/**
* Helper to make replacements
*/
module.exports = function makeReplacements(contents, from, to, file, count) {
//Turn into array
if (!Array.isArray(from)) {
from = [from];
}
//Check if replace value is an array and prepare result
const isArray = Array.isArray(to);
const result = {file};
//Counting? Initialize number of matches
if (count) {
result.numMatches = 0;
result.numReplacements = 0;
}
//Make replacements
const newContents = from.reduce((contents, item, i) => {
//Call function if given, passing in the filename
if (typeof item === 'function') {
item = item(file);
}
//Get replacement value
let replacement = getReplacement(to, isArray, i);
if (replacement === null) {
return contents;
}
//Call function if given, appending the filename
if (typeof replacement === 'function') {
const original = replacement;
replacement = (...args) => original(...args, file);
}
//Count matches
if (count) {
const matches = contents.match(item);
if (matches) {
const replacements = matches.filter(match => match !== replacement);
result.numMatches += matches.length;
result.numReplacements += replacements.length;
}
}
//Make replacement
return contents.replace(item, replacement);
}, contents);
//Check if changed
result.hasChanged = (newContents !== contents);
//Return result and new contents
return [result, newContents];
};

View File

@@ -0,0 +1,74 @@
'use strict';
/**
* Defaults
*/
const defaults = {
ignore: [],
encoding: 'utf-8',
disableGlobs: false,
allowEmptyPaths: false,
countMatches: false,
isRegex: false,
verbose: false,
quiet: false,
dry: false,
glob: {},
cwd: null,
};
/**
* Parse config
*/
module.exports = 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, from, to, processor, 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 {
//Validate values
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)');
}
}
//Ensure arrays
if (!Array.isArray(files)) {
config.files = [files];
}
if (!Array.isArray(ignore)) {
if (typeof ignore === 'undefined') {
config.ignore = [];
}
else {
config.ignore = [ignore];
}
}
//Use default encoding if invalid
if (typeof encoding !== 'string' || encoding === '') {
config.encoding = 'utf-8';
}
//Merge config with defaults
return Object.assign({}, defaults, config);
};

View File

@@ -0,0 +1,45 @@
'use strict';
/**
* Dependencies
*/
const fs = require('fs');
const runProcessors = require('./run-processors');
/**
* Helper to process in a single file (async)
*/
module.exports = function processAsync(file, processor, config) {
//Extract relevant config
const {encoding, dry} = config;
//Wrap in promise
return new Promise((resolve, reject) => {
fs.readFile(file, encoding, (error, contents) => {
//istanbul ignore if
if (error) {
return reject(error);
}
//Make replacements
const [result, newContents] = runProcessors(
contents, processor, file,
);
//Not changed or dry run?
if (!result.hasChanged || dry) {
return resolve(result);
}
//Write to file
fs.writeFile(file, newContents, encoding, error => {
//istanbul ignore if
if (error) {
return reject(error);
}
resolve(result);
});
});
});
};

View File

@@ -0,0 +1,30 @@
'use strict';
/**
* Dependencies
*/
const fs = require('fs');
const runProcessors = require('./run-processors');
/**
* Helper to process in a single file (sync)
*/
module.exports = function processSync(file, processor, config) {
//Extract relevant config and read file contents
const {encoding, dry} = config;
const contents = fs.readFileSync(file, encoding);
//Process contents and check if anything changed
const [result, newContents] = runProcessors(
contents, processor, file,
);
//Contents changed and not a dry run? Write to file
if (result.hasChanged && !dry) {
fs.writeFileSync(file, newContents, encoding);
}
//Return result
return result;
};

View File

@@ -0,0 +1,45 @@
'use strict';
/**
* Dependencies
*/
const fs = require('fs');
const makeReplacements = require('./make-replacements');
/**
* Helper to replace in a single file (async)
*/
module.exports = function replaceAsync(file, from, to, config) {
//Extract relevant config
const {encoding, dry, countMatches} = config;
//Wrap in promise
return new Promise((resolve, reject) => {
fs.readFile(file, encoding, (error, contents) => {
//istanbul ignore if
if (error) {
return reject(error);
}
//Make replacements
const [result, newContents] = makeReplacements(
contents, from, to, file, countMatches
);
//Not changed or dry run?
if (!result.hasChanged || dry) {
return resolve(result);
}
//Write to file
fs.writeFile(file, newContents, encoding, error => {
//istanbul ignore if
if (error) {
return reject(error);
}
resolve(result);
});
});
});
};

View File

@@ -0,0 +1,30 @@
'use strict';
/**
* Dependencies
*/
const fs = require('fs');
const makeReplacements = require('./make-replacements');
/**
* Helper to replace in a single file (sync)
*/
module.exports = function replaceSync(file, from, to, config) {
//Extract relevant config and read file contents
const {encoding, dry, countMatches} = config;
const contents = fs.readFileSync(file, encoding);
//Replace contents and check if anything changed
const [result, newContents] = makeReplacements(
contents, from, to, file, countMatches
);
//Contents changed and not a dry run? Write to file
if (result.hasChanged && !dry) {
fs.writeFileSync(file, newContents, encoding);
}
//Return result
return result;
};

View File

@@ -0,0 +1,16 @@
/**
* Run processors
*/
module.exports = function runProcessors(contents, processor, file, count) {
const processors = Array.isArray(processor) ? processor : [processor];
const result = {file};
const newContents = processors.reduce((contents, processor, i) => {
return processor(contents);
}, contents);
result.hasChanged = (newContents !== contents);
return [result, newContents];
};

View File

@@ -0,0 +1,23 @@
'use strict';
/**
* Dependencies
*/
const chalk = require('chalk');
/**
* Success handler
*/
module.exports = function successHandler(results, verbose) {
const changed = results.filter(result => result.hasChanged);
const numChanges = changed.length;
if (numChanges > 0) {
console.log(chalk.green(`${numChanges} file(s) were changed`));
if (verbose) {
changed.forEach(result => console.log(chalk.grey('-', result.file)));
}
}
else {
console.log(chalk.yellow('No files were changed'));
}
};