1 | var fs = require("fs"),
|
2 | path = require("path"),
|
3 | colors = require("colors");
|
4 |
|
5 |
|
6 | var excludes = [],
|
7 | includes,
|
8 | regex,
|
9 | canReplace,
|
10 | replaceFunc,
|
11 | lineCount = 0,
|
12 | limit = 400,
|
13 | options;
|
14 |
|
15 | module.exports = function(opts) {
|
16 | options = opts;
|
17 | var flags = "g";
|
18 | if (options.ignoreCase) {
|
19 | flags += "i";
|
20 | }
|
21 | if (options.multiline) {
|
22 | flags += "m";
|
23 | }
|
24 | regex = new RegExp(options.regex, flags);
|
25 | canReplace = !options.preview && options.replacement !== undefined;
|
26 |
|
27 | if (options.include) {
|
28 | includes = options.include.split(",").map(patternToRegex);
|
29 | }
|
30 | if (options.exclude) {
|
31 | excludes = options.exclude.split(",");
|
32 | }
|
33 | var list = fs.readFileSync(options.excludeList, "utf-8").split("\n");
|
34 | excludes = excludes.concat(list)
|
35 | .filter(function(line) {
|
36 | return line && line.indexOf("#");
|
37 | })
|
38 | .map(patternToRegex);
|
39 |
|
40 | if (!options.silent) {
|
41 | var verb = canReplace ? "Replaced" : "Found";
|
42 | console.log(verb + " occurences in these files:");
|
43 | }
|
44 | if (options.funcFile) {
|
45 | eval('replaceFunc = ' + fs.readFileSync(options.funcFile, "utf-8"));
|
46 | }
|
47 |
|
48 | for (var i = 0; i < options.path.length; i++) {
|
49 | if(options.async) {
|
50 | replacizeFile(options.path[i]);
|
51 | }
|
52 | else {
|
53 | replacizeFileSync(options.path[i]);
|
54 | }
|
55 | }
|
56 | }
|
57 |
|
58 | function patternToRegex(pattern) {
|
59 | return new RegExp("^" + pattern.replace(/\./g, '\\.').replace(/\*/g, '.*').trim() + "$");
|
60 | }
|
61 |
|
62 | function includeFile(file) {
|
63 | if (includes) {
|
64 | for (var i = 0; i < includes.length; i++) {
|
65 | if (file.match(includes[i]))
|
66 | return true;
|
67 | }
|
68 | return false;
|
69 | }
|
70 | else {
|
71 | for (var i = 0; i < excludes.length; i++) {
|
72 | if (file.match(excludes[i]))
|
73 | return false;
|
74 | }
|
75 | return true;
|
76 | }
|
77 | }
|
78 |
|
79 | function replacizeFile(file) {
|
80 | fs.lstat(file, function(err, stats) {
|
81 | if (err) throw err;
|
82 |
|
83 | if (stats.isSymbolicLink()) {
|
84 |
|
85 | return;
|
86 | }
|
87 | if (stats.isFile()) {
|
88 | if (!includeFile(file)) {
|
89 | return;
|
90 | }
|
91 | fs.readFile(file, "utf-8", function(err, text) {
|
92 | if (err) {
|
93 | if (err.code == 'EMFILE') {
|
94 | console.log('Too many files, try running `replace` without --async');
|
95 | process.exit(1);
|
96 | }
|
97 | throw err;
|
98 | }
|
99 |
|
100 | text = replacizeText(text, file);
|
101 | if(canReplace) {
|
102 | fs.writeFile(file, text, function(err) {
|
103 | if (err) throw err;
|
104 | });
|
105 | }
|
106 | });
|
107 | }
|
108 | else if (stats.isDirectory() && options.recursive) {
|
109 | fs.readdir(file, function(err, files) {
|
110 | if (err) throw err;
|
111 | for (var i = 0; i < files.length; i++) {
|
112 | replacizeFile(path.join(file, files[i]));
|
113 | }
|
114 | });
|
115 | }
|
116 | });
|
117 | }
|
118 |
|
119 | function replacizeFileSync(file) {
|
120 | var stats = fs.lstatSync(file);
|
121 | if (stats.isSymbolicLink()) {
|
122 |
|
123 | return;
|
124 | }
|
125 | if (stats.isFile()) {
|
126 | if (!includeFile(file)) {
|
127 | return;
|
128 | }
|
129 | var text = fs.readFileSync(file, "utf-8");
|
130 |
|
131 | text = replacizeText(text, file);
|
132 | if (canReplace) {
|
133 | fs.writeFileSync(file, text);
|
134 | }
|
135 | }
|
136 | else if (stats.isDirectory() && options.recursive) {
|
137 | var files = fs.readdirSync(file);
|
138 | for (var i = 0; i < files.length; i++) {
|
139 | replacizeFileSync(path.join(file, files[i]));
|
140 | }
|
141 | }
|
142 | }
|
143 |
|
144 | function replacizeText(text, file) {
|
145 | var match = text.match(regex);
|
146 | if (!match) {
|
147 | return text;
|
148 | }
|
149 |
|
150 | if (!options.silent) {
|
151 | var printout = "\t" + file;
|
152 | if (options.count) {
|
153 | printout += " (" + match.length + ")";
|
154 | }
|
155 | console.log(printout);
|
156 | }
|
157 | if (!options.silent && !options.quiet
|
158 | && !(lineCount > options.maxLines)
|
159 | && options.multiline) {
|
160 | var lines = text.split("\n");
|
161 | for (var i = 0; i < lines.length; i++) {
|
162 | var line = lines[i];
|
163 | if (line.match(regex)) {
|
164 | if (++lineCount > options.maxLines) {
|
165 | break;
|
166 | }
|
167 | var replacement = options.replacement || "$&";
|
168 | line = line.replace(regex, replaceFunc || replacement[options.color]);
|
169 | console.log("\t\t" + (i + 1) + ": " + line.slice(0, limit));
|
170 | }
|
171 | }
|
172 | }
|
173 | if (canReplace) {
|
174 | return text.replace(regex, replaceFunc || options.replacement);
|
175 | }
|
176 | }
|