Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Passes full file path to the replacement function #76

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,19 @@ gulp.task('templates', function(){
.pipe(gulp.dest('build/file.txt'));
});
```
### Use FilePath
```javascript
var replace = require('gulp-replace');

gulp.task('templates', function(){
gulp.src(['file.txt'])
.pipe(replace(/foo(.{3})/g, function($0, str){
return str + 'foo' + this.filePath;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return 'bar in' + this.filePath;

It is customary to replace foo with bar :) In this case, we can just tack the path onto the end.

}, {passFileName: true}))
.pipe(gulp.dest('build/file.txt'));
});
```

### String Replace
```javascript
var replace = require('gulp-replace');
Expand Down Expand Up @@ -61,6 +74,8 @@ Type: `String` or `Function`

The replacement string or function. See the [MDN documentation for String.replace] for details.

if `Function` and `options.passFileName` is true, then Function within the filePath is equal to the current file `file.path`.

### gulp-replace options

An optional third argument, `options`, can be passed.
Expand All @@ -69,11 +84,17 @@ An optional third argument, `options`, can be passed.
Type: `Object`

##### options.skipBinary
Type: `boolean`
Type: `boolean`
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These actually need two spaces or a line break after them, otherwise they appear on the same line

Default: `false`

Skip binary files

##### options.passFileName
Type: `boolean`
Default: `false`

Passes full file path to the replacement function
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes the full file path available inside the replacement function as this.filePath



[MDN documentation for RegExp]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp
[MDN documentation for String.replace]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#Specifying_a_string_as_a_parameter
Expand Down
151 changes: 82 additions & 69 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,73 +5,86 @@ var rs = require('replacestream');
var istextorbinary = require('istextorbinary');

module.exports = function(search, replacement, options) {
return new Transform({
objectMode: true,
transform: function(file, enc, callback) {
if (file.isNull()) {
return callback(null, file);
}

function doReplace() {
if (file.isStream()) {
file.contents = file.contents.pipe(rs(search, replacement));
return callback(null, file);
}

if (file.isBuffer()) {
if (search instanceof RegExp) {
file.contents = new Buffer(String(file.contents).replace(search, replacement));
}
else {
var chunks = String(file.contents).split(search);

var result;
if (typeof replacement === 'function') {
// Start with the first chunk already in the result
// Replacements will be added thereafter
// This is done to avoid checking the value of i in the loop
result = [ chunks[0] ];

// The replacement function should be called once for each match
for (var i = 1; i < chunks.length; i++) {
// Add the replacement value
result.push(replacement(search));

// Add the next chunk
result.push(chunks[i]);
}

result = result.join('');
}
else {
result = chunks.join(replacement);
}

file.contents = new Buffer(result);
}
return callback(null, file);
}

callback(null, file);
}

if (options && options.skipBinary) {
istextorbinary.isText(file.path, file.contents, function(err, result) {
if (err) {
return callback(err, file);
}

if (!result) {
callback(null, file);
} else {
doReplace();
}
});

return;
}

doReplace();
}
});
return new Transform({
objectMode: true,
transform: function(file, enc, callback) {
if (file.isNull()) {
return callback(null, file);
}

function doReplace() {
if (file.isStream()) {
file.contents = file.contents.pipe(rs(search, replacement));
return callback(null, file);
}

if (file.isBuffer()) {
if (search instanceof RegExp) {
file.contents = new Buffer(String(file.contents).replace(search, replacement));
}
else {
var chunks = String(file.contents).split(search);

var result;
if (typeof replacement === 'function') {
// Start with the first chunk already in the result
// Replacements will be added thereafter
// This is done to avoid checking the value of i in the loop
result = [ chunks[0] ];

// The replacement function should be called once for each match
for (var i = 1; i < chunks.length; i++) {
// Add the replacement value
result.push(replacement(search));

// Add the next chunk
result.push(chunks[i]);
}

result = result.join('');
}
else {
result = chunks.join(replacement);
}

file.contents = new Buffer(result);
}
return callback(null, file);
}

callback(null, file);
}

if (options) {
if (options.passFileName && typeof replacement === 'function') {
var userReplacement = replacement;
replacement = function () {
var context = {
filePath: file.path
};
userReplacement.apply(context, arguments);
};
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is definitely a clever way to achieve this, but I wonder if users will ever use .bind() on their replacement functions and therefore be unable to use passFilePath.

}

if(options.skipBinary) {
istextorbinary.isText(file.path, file.contents, function(err, result) {
if (err) {
return callback(err, file);
}

if (!result) {
callback(null, file);
} else {
doReplace();
}
});

return;
}

}

doReplace();
}
});
};
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do not change spaces to tabs in your PR, it makes it hard to review. Can you change it back and push a new commit?

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "gulp-replace",
"version": "0.5.4",
"version": "0.5.5",
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a new feature, so we should bump to 0.6.0.

"description": "A string replace plugin for gulp",
"dependencies": {
"istextorbinary": "1.0.2",
Expand Down