Comparing version 0.2.3 to 0.2.5
185
cli.js
@@ -6,3 +6,2 @@ #!/usr/bin/env node | ||
Thing = require("nature").Thing, | ||
path = require("path"), | ||
rename = require("./lib/rename"), | ||
@@ -15,40 +14,43 @@ Glob = require("glob").Glob, | ||
\n\ | ||
-f, --find The find string, or regular expression when --regex is set.\n\ | ||
If not set, the whole filename will be replaced.\n\ | ||
-r, --replace The replace string. With --regex set, --replace can reference\n\ | ||
parenthesised substrings from --find with $1, $2, $3 etc.\n\ | ||
If omitted, defaults to a blank string. The special token\n\ | ||
'{{index}}' will insert an incrementing number per file\n\ | ||
processed.\n\ | ||
-e, --regex When set, --find is intepreted as a regular expression.\n\ | ||
-d, --dry-run Used for test runs. Prints the new names but will not rename the file.\n\ | ||
-h, --help Print usage instructions.\n"; | ||
-f, --find The find string, or regular expression when --regex is set.\n\ | ||
If not set, the whole filename will be replaced.\n\ | ||
-r, --replace The replace string. With --regex set, --replace can reference\n\ | ||
parenthesised substrings from --find with $1, $2, $3 etc.\n\ | ||
If omitted, defaults to a blank string. The special token\n\ | ||
'{{index}}' will insert an incrementing number per file\n\ | ||
processed.\n\ | ||
-e, --regex When set, --find is intepreted as a regular expression.\n\ | ||
-i, --insensitive Enable case-insensitive finds.\n\ | ||
-d, --dry-run Used for test runs. Set this to do everything but rename the file.\n\ | ||
-h, --help Print usage instructions.\n"; | ||
/* | ||
TODO: Tidy error handling, presets | ||
*/ | ||
var optionSet; | ||
try { | ||
optionSet = new Thing() | ||
.mixIn(new rename.RenameOptions(), "rename") | ||
.define({ | ||
name: "files", | ||
type: Array, | ||
required: true, | ||
defaultOption: true, | ||
groups: ["rename"], | ||
valueFailMsg: "Must supply at least one file, and all must exist" | ||
}) | ||
.define({ name: "dry-run", type: "boolean", alias: "d" }) | ||
.define({ name: "help", type: "boolean", alias: "h" }) | ||
.on("error", function(err){ | ||
console.error(red("Error: ") + err.message); | ||
process.exit(1); | ||
}) | ||
.set(process.argv); | ||
} catch (e){ | ||
log(red("Invalid argument: " + e.message)); | ||
process.exit(1); | ||
function red(txt){ return "\x1b[31m" + txt + "\x1b[0m"; } | ||
function green(txt){ return "\x1b[32m" + txt + "\x1b[0m"; } | ||
function pluck(object, fn){ | ||
var output = []; | ||
for (var prop in object){ | ||
if (fn(object[prop])) output.push(prop); | ||
} | ||
return output; | ||
} | ||
var optionSet; | ||
optionSet = new Thing() | ||
.on("error", function(err){ | ||
log(red("Error: " + err.message)); | ||
process.exit(1); | ||
}) | ||
.mixIn(new rename.RenameOptions(), "rename") | ||
.define({ | ||
name: "files", | ||
type: Array, | ||
required: true, | ||
defaultOption: true, | ||
groups: ["rename"], | ||
valueFailMsg: "Must supply at least one file, and all must exist" | ||
}) | ||
.define({ name: "dry-run", type: "boolean", alias: "d" }) | ||
.define({ name: "help", type: "boolean", alias: "h" }) | ||
.set(process.argv); | ||
if (optionSet.help){ | ||
@@ -59,36 +61,2 @@ log(usage); | ||
var fileList = {}; | ||
if (optionSet.files){ | ||
optionSet.files.forEach(function(file){ | ||
if (fs.existsSync(file)){ | ||
fileList[file] = fs.statSync(file).isDirectory() ? 2 : 1; | ||
} else { | ||
var glob = new Glob(file, { sync: true, stat: true }); | ||
glob.found.forEach(function(file){ | ||
fileList[file] = glob.cache[file]; | ||
}); | ||
} | ||
}); | ||
} | ||
// log(fileList); | ||
if (optionSet.valid){ | ||
var noExist = pluck(fileList, function(val){ return val === false; }), | ||
files = pluck(fileList, function(val){ return val === 1; }), | ||
dirs = pluck(fileList, function(val){ return val === 2 || val instanceof Array; }); | ||
// log(noExist);log(files);log(dirs);return; | ||
noExist.forEach(function(file){ | ||
log(red("File does not exist: " + file)); | ||
}); | ||
doWork(files); | ||
doWork(dirs.reverse()); | ||
} else { | ||
log(red("Error: some values were invalid")); | ||
log(red(optionSet.validationMessages.toString())); | ||
log(usage); | ||
} | ||
function doWork(files){ | ||
@@ -99,7 +67,8 @@ var results, | ||
try { | ||
results = rename.rename({ | ||
files: files, | ||
find: optionSet.find, | ||
results = rename.rename({ | ||
files: files, | ||
find: optionSet.find, | ||
replace: optionSet.replace, | ||
regex: optionSet.regex | ||
regex: optionSet.regex, | ||
insensitive: optionSet.insensitive | ||
}); | ||
@@ -110,3 +79,3 @@ } catch (e){ | ||
} | ||
results.forEach(function(result){ | ||
@@ -118,6 +87,6 @@ if (result.before === result.after || !result.after ){ | ||
log( | ||
"%s: %s -> %s (%s)", | ||
red("no change"), | ||
result.before, | ||
result.after, | ||
"%s: %s -> %s (%s)", | ||
red("no change"), | ||
result.before, | ||
result.after, | ||
red("file exists") | ||
@@ -133,6 +102,6 @@ ); | ||
log( | ||
"%s: %s -> %s (%s)", | ||
red("no change"), | ||
result.before, | ||
result.after, | ||
"%s: %s -> %s (%s)", | ||
red("no change"), | ||
result.before, | ||
result.after, | ||
red(e.message) | ||
@@ -150,15 +119,39 @@ ); | ||
function red(txt){ return "\x1b[31m" + txt + "\x1b[0m"; } | ||
function green(txt){ return "\x1b[32m" + txt + "\x1b[0m"; } | ||
// function mixin(from, to){ | ||
// for (var prop in from){ | ||
// to[prop.replace(/^\.\//, "")] = from[prop]; | ||
// } | ||
// } | ||
function pluck(object, fn){ | ||
var output = []; | ||
for (var prop in object){ | ||
if (fn(object[prop])) output.push(prop); | ||
} | ||
return output; | ||
var fileList = {}; | ||
if (optionSet.files){ | ||
optionSet.files.forEach(function(file){ | ||
if (fs.existsSync(file)){ | ||
fileList[file] = fs.statSync(file).isDirectory() ? 2 : 1; | ||
} else { | ||
var glob = new Glob(file, { sync: true, stat: true }); | ||
glob.found.forEach(function(file){ | ||
fileList[file] = glob.cache[file]; | ||
}); | ||
} | ||
}); | ||
} | ||
if (optionSet.valid){ | ||
var noExist = pluck(fileList, function(val){ return val === false; }), | ||
files = pluck(fileList, function(val){ return val === 1; }), | ||
dirs = pluck(fileList, function(val){ return val === 2 || val instanceof Array; }); | ||
noExist.forEach(function(file){ | ||
log(red("File does not exist: " + file)); | ||
}); | ||
doWork(files); | ||
doWork(dirs.reverse()); | ||
} else { | ||
log(red("Some values were invalid")); | ||
log(red(optionSet.validationMessages.toString())); | ||
log(usage); | ||
} | ||
/* | ||
TODO: presets, replace token: $dirname, --js expression and $js token, date and string padding functions, -i option for case-insensitive | ||
renamer -i -f "something" -r "$1" --findModifier 'toUpperCase()' // returns SOMETHING | ||
renamer -i -f "two words" -r "$1" --findModifier 'toProperCase()' // returns Two Words | ||
*/ |
"use strict"; | ||
var fs = require("fs"), | ||
Thing = require("nature").Thing, | ||
var Thing = require("nature").Thing, | ||
path = require("path"), | ||
util = require("util"), | ||
l = console.log; | ||
function escapeRegExp(string){ | ||
return string | ||
? string.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1") | ||
: ""; | ||
} | ||
exports.rename = function(options){ | ||
options = new exports.RenameOptions() | ||
.on("error", function(err){ | ||
throw err; | ||
}) | ||
.set(options); | ||
options = new exports.RenameOptions().set(options); | ||
if (options.valid){ | ||
@@ -19,22 +21,13 @@ var output = []; | ||
dirname = path.dirname(file), | ||
basename = path.basename(file); | ||
if (options.regex){ | ||
if(options.find){ | ||
basename = basename.replace(new RegExp(options.find, "g"), options.replace); | ||
after = path.join(dirname, basename); | ||
} else { | ||
after = path.join(dirname, options.replace); | ||
} | ||
basename = path.basename(file), | ||
re = options.regex ? options.find : escapeRegExp(options.find), | ||
reOptions = "g" + (options.insensitive ? "i" : ""); | ||
if(options.find){ | ||
basename = basename.replace(new RegExp(re, reOptions), options.replace); | ||
after = path.join(dirname, basename); | ||
} else { | ||
if(options.find){ | ||
while (basename.indexOf(options.find) !== -1){ | ||
basename = basename.replace(options.find, options.replace); | ||
} | ||
after = path.join(dirname, basename); | ||
} else { | ||
after = path.join(dirname, options.replace); | ||
} | ||
after = path.join(dirname, options.replace); | ||
} | ||
output.push({ before: path.normalize(file), after: after }); | ||
@@ -54,4 +47,3 @@ }); | ||
exports.RenameOptions = function(){ | ||
return new Thing() | ||
.define({ | ||
this.define({ | ||
name: "files", | ||
@@ -64,3 +56,5 @@ type: Array, | ||
.define({ name: "replace", type: "string", alias: "r", default: "" }) | ||
.define({ name: "regex", type: "boolean", alias: "e" }); | ||
.define({ name: "regex", type: "boolean", alias: "e" }) | ||
.define({ name: "insensitive", type: "boolean", alias: "i" }); | ||
}; | ||
util.inherits(exports.RenameOptions, Thing); |
{ | ||
"name": "renamer", | ||
"description": "Batch rename files.", | ||
"version": "0.2.3", | ||
"version": "0.2.5", | ||
"bin": "cli.js", | ||
@@ -9,11 +9,11 @@ "repository": "https://github.com/75lb/renamer", | ||
"scripts": { | ||
"test": "mocha --reporter spec test/unit-*.js" | ||
"test": "mocha --reporter spec test/unit-*.js test/integration.js" | ||
}, | ||
"dependencies": { | ||
"nature": "~0.1.0", | ||
"nature": "~0.2.0", | ||
"glob": "~3.2.6" | ||
}, | ||
"devDependencies": { | ||
"mocha": "~1.7.4" | ||
"mocha": "~1.14" | ||
} | ||
} |
@@ -5,3 +5,3 @@ [![Build Status](https://travis-ci.org/75lb/renamer.png)](https://travis-ci.org/75lb/renamer) | ||
======= | ||
Batch rename files. | ||
Batch rename files and folders. | ||
@@ -19,3 +19,3 @@ Install | ||
```sh | ||
$ renamer [--find <pattern>] [--replace <string>] [--dry-run] [--regex] <files> | ||
$ renamer [--regex] [--find <pattern>] [--replace <string>] [--dry-run] <files> | ||
``` | ||
@@ -31,3 +31,3 @@ ``` | ||
-e, --regex When set, --find is intepreted as a regular expression. | ||
-d, --dry-run Used for test runs. Set to do everything but rename the file. | ||
-d, --dry-run Used for test runs. Set this to do everything but rename the file. | ||
-h, --help Print usage instructions. | ||
@@ -171,2 +171,26 @@ ``` | ||
_prefix files and folders, recursively_ | ||
```sh | ||
$ tree | ||
. | ||
├── pic1.jpg | ||
├── pic2.jpg | ||
└── pics | ||
├── pic3.jpg | ||
└── pic4.jpg | ||
$ renamer --regex --find '^' --replace 'good-' '**' | ||
$ tree | ||
. | ||
├── good-pic1.jpg | ||
├── good-pic2.jpg | ||
└── good-pics | ||
├── good-pic3.jpg | ||
└── good-pic4.jpg | ||
``` | ||
[![NPM](https://nodei.co/npm-dl/renamer.png?months=1)](https://nodei.co/npm/renamer/) | ||
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/75lb/renamer/trend.png)](https://bitdeli.com/free "Bitdeli Badge") |
@@ -13,3 +13,3 @@ #!/usr/bin/env node | ||
function clearDir(dirName){ | ||
console.log("clearing dir: " + dirName) | ||
console.log("clearing dir: " + dirName); | ||
fs.readdirSync(dirName).forEach(function(file){ | ||
@@ -16,0 +16,0 @@ if (fs.statSync(path.resolve(dirName, file)).isDirectory()){ |
var rename = require("../lib/rename"), | ||
assert = require("assert"), | ||
l = console.log; | ||
assert = require("assert"); | ||
@@ -8,3 +7,3 @@ describe("rename --find <string> --replace <string>", function(){ | ||
var args = [ | ||
"--find", "clive", "--replace", "hater", | ||
"--find", "clive", "--replace", "hater", | ||
"file clive 1.txt", "&*123file clive 2.txt", "clicclicclivehater.avi" | ||
@@ -17,8 +16,7 @@ ]; | ||
]); | ||
}); | ||
it("replace complex string pattern in files", function(){ | ||
var args = [ | ||
"--find", "[]()£$%^", "--replace", "[].*$%^", | ||
"--find", "[]()£$%^", "--replace", "[].*$%^", | ||
"...[]()£$%^...", "++[]()£$%^++" | ||
@@ -31,6 +29,6 @@ ]; | ||
}); | ||
it("replace all <find-string> instances", function(){ | ||
var args = [ | ||
"--find", "a", "--replace", "b", | ||
"--find", "a", "--replace", "b", | ||
"aaaaa", "rraarr" | ||
@@ -43,8 +41,8 @@ ]; | ||
}); | ||
it("replace simple string pattern in deep files", function(){ | ||
var args = [ | ||
"--find", "clive", "--replace", "hater", | ||
"clive/clive.txt", | ||
"clive/clive/clive.txt", | ||
"--find", "clive", "--replace", "hater", | ||
"clive/clive.txt", | ||
"clive/clive/clive.txt", | ||
"clive/clive/clive/clive.txt" | ||
@@ -57,4 +55,15 @@ ]; | ||
]); | ||
}); | ||
it("case-insensitive find", function(){ | ||
var args = [ | ||
"--find", "clive", "--replace", "hater", "-i", | ||
"file CLIVe 1.txt", "&*123file clIVe 2.txt", "clicclicClivEhater.avi" | ||
]; | ||
assert.deepEqual(rename.rename(args), [ | ||
{ before: "file CLIVe 1.txt", after: "file hater 1.txt" }, | ||
{ before: "&*123file clIVe 2.txt", after: "&*123file hater 2.txt" }, | ||
{ before: "clicclicClivEhater.avi", after: "clicclichaterhater.avi" } | ||
]); | ||
}); | ||
}); | ||
@@ -65,5 +74,5 @@ | ||
var args = [ | ||
"--find", "clive", "--replace", "hater", "--regex", | ||
"file clive 1.txt", | ||
"&*123file clive 2.txt", | ||
"--find", "clive", "--replace", "hater", "--regex", | ||
"file clive 1.txt", | ||
"&*123file clive 2.txt", | ||
"clicclicclivehater.avi" | ||
@@ -76,3 +85,3 @@ ]; | ||
]); | ||
}); | ||
@@ -82,4 +91,4 @@ | ||
var args = [ | ||
"--find", "clive", "--replace", "hater", "--regex", | ||
"clive/&*123file clive 2.txt", | ||
"--find", "clive", "--replace", "hater", "--regex", | ||
"clive/&*123file clive 2.txt", | ||
"clive/hater/clicclicclivehater.avi" | ||
@@ -92,6 +101,6 @@ ]; | ||
}); | ||
it("replace all <find-string> instances", function(){ | ||
var args = [ | ||
"--find", "a", "--replace", "b", "--regex", | ||
"--find", "a", "--replace", "b", "--regex", | ||
"aaaaa", "rraarr", | ||
@@ -110,3 +119,3 @@ "aaa/aaaaa", "aaa/rraarr" | ||
var args = [ | ||
"--find", "\\.(?!\\w+$)", "--replace", " ", "--regex", | ||
"--find", "\\.(?!\\w+$)", "--replace", " ", "--regex", | ||
"loads.of.full.stops.every.where.mp4", | ||
@@ -116,12 +125,24 @@ "loads.of.full.stops.every.where.jpeg" | ||
assert.deepEqual(rename.rename(args), [ | ||
{ | ||
before: "loads.of.full.stops.every.where.mp4", | ||
after: "loads of full stops every where.mp4" | ||
{ | ||
before: "loads.of.full.stops.every.where.mp4", | ||
after: "loads of full stops every where.mp4" | ||
}, | ||
{ | ||
before: "loads.of.full.stops.every.where.jpeg", | ||
after: "loads of full stops every where.jpeg" | ||
{ | ||
before: "loads.of.full.stops.every.where.jpeg", | ||
after: "loads of full stops every where.jpeg" | ||
} | ||
]); | ||
}); | ||
}); | ||
it("case-insensitive find", function(){ | ||
var args = [ | ||
"--find", "clive", "--replace", "hater", "-i", "--regex", | ||
"file CLIVe 1.txt", "&*123file clIVe 2.txt", "clicclicClivEhater.avi" | ||
]; | ||
assert.deepEqual(rename.rename(args), [ | ||
{ before: "file CLIVe 1.txt", after: "file hater 1.txt" }, | ||
{ before: "&*123file clIVe 2.txt", after: "&*123file hater 2.txt" }, | ||
{ before: "clicclicClivEhater.avi", after: "clicclichaterhater.avi" } | ||
]); | ||
}); | ||
}); | ||
@@ -137,9 +158,9 @@ | ||
[ | ||
{ | ||
before: "one.txt", | ||
after: "1.txt" | ||
{ | ||
before: "one.txt", | ||
after: "1.txt" | ||
}, | ||
{ | ||
before: "two.txt", | ||
after: "2.txt" | ||
{ | ||
before: "two.txt", | ||
after: "2.txt" | ||
} | ||
@@ -150,1 +171,19 @@ ] | ||
}); | ||
describe("error handling", function(){ | ||
it("should handle crap input", function(){ | ||
assert.throws(function(){ | ||
rename.rename("ldjf", 1, true); | ||
}); | ||
assert.throws(function(){ | ||
rename.rename({ file: "clive.txt", find: "i", r: "o" }); | ||
}); | ||
assert.doesNotThrow(function(){ | ||
rename.rename({ files: "clive.txt", find: "i", r: "o" }); | ||
}); | ||
}); | ||
it("should not loop infinitly", function(){ | ||
rename.rename({ files: "bb.txt", find: "bb", replace: "bb" }); | ||
assert.ok(true); | ||
}); | ||
}); |
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
19961
9
377
193
3
+ Addednature@0.2.5(transitive)
+ Addedunderscore@1.5.2(transitive)
- Removednature@0.1.3(transitive)
- Removedunderscore@1.4.4(transitive)
Updatednature@~0.2.0