Comparing version 0.3.0 to 0.3.1
28
cli.js
#!/usr/bin/env node | ||
"use strict"; | ||
var Thing = require("nature").Thing, | ||
var Model = require("nature").Model, | ||
dope = require("console-dope"), | ||
renamer = require("./lib/renamer"), | ||
Renamer = renamer.Renamer, | ||
RenameOptions = renamer.RenameOptions, | ||
w = require("wodge"); | ||
@@ -41,3 +43,3 @@ | ||
var argv; | ||
argv = new Thing() | ||
argv = new Model() | ||
.on("error", function(err){ | ||
@@ -47,3 +49,4 @@ logError("Error: " + err.message); | ||
}) | ||
.mixIn(new renamer.RenameOptions(), "rename") | ||
.mixIn(new RenameOptions(), "rename") | ||
.define({ name: "verbose", type: "boolean", alias: "v" }) | ||
.define({ name: "help", type: "boolean", alias: "h" }) | ||
@@ -60,3 +63,17 @@ .set(process.argv); | ||
if (argv.files.length){ | ||
renamer.process(argv.where({ group: "rename" }) ); | ||
if (argv["dry-run"]) dope.bold.underline.log("Dry run"); | ||
var renamer = new Renamer(argv.where({ group: "rename" })); | ||
var results = renamer.process(); | ||
results.forEach(function(file){ | ||
if (file.error){ | ||
log(false, file.before + " %red{->} " + file.after, file.error) | ||
} else { | ||
if(file.renamed){ | ||
log(true, file.before + " %green{->} " + file.after); | ||
} else if (!file.renamed && argv.verbose){ | ||
log(false, file.before); | ||
} | ||
} | ||
}); | ||
} else { | ||
@@ -74,4 +91,1 @@ dope.log(usage); | ||
*/ | ||
/* | ||
BUG: renamer -r blah{{index}} * // index should not reset when processing folders, also appears incorrectly as tick in dry-run | ||
*/ |
"use strict"; | ||
var Thing = require("nature").Thing, | ||
var Model = require("nature").Model, | ||
path = require("path"), | ||
dope = require("console-dope"), | ||
util = require("util"), | ||
fs = require("fs"), | ||
Result = require("./Result"), | ||
mfs = require("more-fs"), | ||
Glob = require("glob").Glob, | ||
@@ -11,17 +12,4 @@ w = require("wodge"); | ||
exports.RenameOptions = RenameOptions; | ||
exports.process = process; | ||
exports.Renamer = Renamer; | ||
function log(success, msg, error){ | ||
dope.log( | ||
"%%%s{%s} %s %s", | ||
success ? "green" : "red", | ||
success ? w.symbol.tick : w.symbol.cross, | ||
msg, | ||
error ? "(%red{" + error + "})" : "" | ||
); | ||
} | ||
function logError(msg){ | ||
dope.red.log(msg); | ||
} | ||
function RenameOptions(){ | ||
@@ -38,8 +26,41 @@ this.define({ | ||
.define({ name: "dry-run", type: "boolean", alias: "d" }) | ||
.define({ name: "verbose", type: "boolean", alias: "v" }) | ||
.define({ name: "insensitive", type: "boolean", alias: "i" }); | ||
} | ||
util.inherits(RenameOptions, Thing); | ||
util.inherits(RenameOptions, Model); | ||
/** | ||
@constructor | ||
*/ | ||
function Renamer(options){ | ||
this._options = new RenameOptions().set(options); | ||
if (!this._options.valid) throw new Error("Invalid options: " + this._options.validationMessages); | ||
} | ||
/** | ||
@method process | ||
@return {Array} results An array of result objects | ||
@example | ||
[ | ||
{ before: "file1.txt", after: "clive.txt", renamed: false, error: "file exists" } | ||
{ before: "file2.txt", after: "clive2.txt", renamed: true } | ||
] | ||
*/ | ||
Renamer.prototype.process = function(){ | ||
var options = this._options, | ||
fileStats = new mfs.FileStats(options.files); | ||
options.files = fileStats.files | ||
.concat(fileStats.dirs.reverse()) | ||
.map(function(file){ return { before: file }; }); | ||
var results = options.files | ||
.map(this._renameFile.bind(this)) | ||
.map(replaceIndexToken) | ||
.map(this._dryRun.bind(this)) | ||
.map(this._renameOnDisk.bind(this)); | ||
return results; | ||
}; | ||
/** | ||
Search globally by default. If `options.regex` is not set then ensure any special regex characters in `options.find` are escaped. | ||
@@ -55,8 +76,11 @@ */ | ||
Perform the replace, on the basename only. If no `options.find` is supplied, the entire basename is replaced by `options.replace`. | ||
@returns {Object} beforeAfter An object containing the input path before and after the rename. | ||
@method | ||
@param result {ResultObject} input | ||
@returns {ResultObject} resultObject An object containing the input path before and after the rename. | ||
*/ | ||
function renameFile(options, file){ | ||
Renamer.prototype._renameFile = function(result, index, resultsSoFar){ | ||
var after, | ||
dirname = path.dirname(file), | ||
basename = path.basename(file), | ||
options = this._options, | ||
dirname = path.dirname(result.before), | ||
basename = path.basename(result.before), | ||
re = regExBuilder(options); | ||
@@ -71,106 +95,51 @@ | ||
return { before: path.normalize(file), after: after }; | ||
} | ||
result.before = path.normalize(result.before); | ||
result.after = after; | ||
result.renamed = true; | ||
function replaceIndexToken(beforeAfter, index){ | ||
if (beforeAfter.after){ | ||
beforeAfter.after = beforeAfter.after.replace("{{index}}", index + 1); | ||
} | ||
return beforeAfter; | ||
} | ||
return result; | ||
}; | ||
function doRename(options, from, to){ | ||
var newFilenames = [], | ||
logMsg = from + " %green{->} " + to; | ||
Renamer.prototype._dryRun = function(result, index, resultsSoFar){ | ||
var existing = resultsSoFar.filter(function(prevResult, prevIndex){ | ||
return prevIndex < index && (prevResult.before !== result.before) && (prevResult.after === result.after); | ||
}); | ||
if (from === to || !to ){ | ||
if (options.verbose) log(false, from); | ||
} else { | ||
if (fs.existsSync(to) || newFilenames.indexOf(to) > -1){ | ||
log(false, logMsg, "file exists"); | ||
} else { | ||
if (!options["dry-run"]) { | ||
try { | ||
fs.renameSync(from, to); | ||
newFilenames.push(to); | ||
log(true, logMsg); | ||
} catch(e){ | ||
log(false, logMsg, e.message); | ||
} | ||
} else { | ||
newFilenames.push(to); | ||
log(true, logMsg); | ||
} | ||
} | ||
if (result.before === result.after ){ | ||
result.renamed = false; | ||
} else if (existing.length || fs.existsSync(result.after)){ | ||
result.renamed = false; | ||
result.error = "file exists"; | ||
} | ||
} | ||
function renameFiles(options){ | ||
var results; | ||
return result; | ||
}; | ||
try { | ||
results = options.files | ||
.map(renameFile.bind(null, options)) | ||
.map(replaceIndexToken); | ||
} catch (e){ | ||
logError(e.message); | ||
process.exit(1); | ||
} | ||
results.forEach(function(result){ | ||
doRename(options, result.before, result.after); | ||
}); | ||
} | ||
/* | ||
@returns {Object} fileStats Each key is an existing file, it's value either 1 or 2, meaning "file" or "directory", e.g.: | ||
{ | ||
"file1": 1, | ||
"file2": 1, | ||
"folder1": 2, | ||
"folder1/file1": 1, | ||
"folder1/file2": 1 | ||
} | ||
/** | ||
Perform the replace, on disk. Sets the `renamed` and/or `error` properties on the resultObject. | ||
@method | ||
@param result {ResultObject} input | ||
@returns {ResultObject} resultObject | ||
*/ | ||
function getFileStats(files){ | ||
var fileStats = {}, | ||
existingFiles = files.filter(fs.existsSync), | ||
notExistingFiles = w.without(files, existingFiles); | ||
Renamer.prototype._renameOnDisk = function(result){ | ||
var options = this._options; | ||
existingFiles.forEach(function(file){ | ||
fileStats[file] = fs.statSync(file).isDirectory() ? 2 : 1; | ||
}); | ||
notExistingFiles.forEach(function(file){ | ||
var glob = new Glob(file, { sync: true, stat: true }); | ||
if (glob.found.length){ | ||
glob.found.forEach(function(file){ | ||
fileStats[file] = glob.cache[file] instanceof Array ? 2 : 1; | ||
}); | ||
} else { | ||
logError("File does not exist: " + file); | ||
if (!options["dry-run"] && result.renamed === true) { | ||
try { | ||
fs.renameSync(result.before, result.after); | ||
} catch(e){ | ||
result.renamed = false; | ||
result.error = e.message; | ||
} | ||
}); | ||
return fileStats; | ||
} | ||
} | ||
function process(options){ | ||
var options = new RenameOptions().set(options); | ||
return result; | ||
}; | ||
if (!options.valid) throw new Error("Invalid options: " + options.validationMessages); | ||
if (options["dry-run"]){ | ||
dope.negative.log("Dry run"); | ||
function replaceIndexToken(result, index){ | ||
if (result.after){ | ||
result.after = result.after.replace("{{index}}", index + 1); | ||
} | ||
var fileStats = getFileStats(options.files), | ||
files = w.pluck(fileStats, function(val){ return val === 1; }), | ||
dirs = w.pluck(fileStats, function(val){ return val === 2; }); | ||
options.files = files; | ||
renameFiles(options); | ||
options.files = dirs.reverse(); | ||
renameFiles(options); | ||
return result; | ||
} |
{ | ||
"name": "renamer", | ||
"description": "Batch rename files and folders", | ||
"version": "0.3.0", | ||
"version": "0.3.1", | ||
"bin": "cli.js", | ||
@@ -13,8 +13,9 @@ "main": "./lib/renamer", | ||
"dependencies": { | ||
"nature": "~0.3.0", | ||
"nature": "~0.4.0", | ||
"glob": "~3.2.6", | ||
"wodge": "~0.4.0", | ||
"console-dope": "~0.3" | ||
"console-dope": "~0.3", | ||
"more-fs": "~0.1.2" | ||
}, | ||
"devDependencies": {} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
10
23074
5
444
+ Addedmore-fs@~0.1.2
+ Addedmore-fs@0.1.4(transitive)
+ Addednature@0.4.3(transitive)
+ Addedwodge@0.6.11(transitive)
- Removednature@0.3.2(transitive)
- Removedunderscore@1.6.0(transitive)
- Removedwodge@0.3.2(transitive)
Updatednature@~0.4.0