1
0
Fork 0

Included grunt-text-replace module

This commit is contained in:
Michael Hackstein 2015-02-19 18:20:00 +01:00
parent 101985516a
commit 1370c28b4c
18 changed files with 1042 additions and 0 deletions

View File

@ -0,0 +1,9 @@
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = false

View File

@ -0,0 +1,13 @@
{
"curly": true,
"eqeqeq": true,
"immed": true,
"latedef": true,
"newcap": true,
"noarg": true,
"sub": true,
"undef": true,
"boss": true,
"eqnull": true,
"node": true
}

View File

@ -0,0 +1,3 @@
node_modules/
test/modified/
tmp/

View File

@ -0,0 +1,6 @@
language: node_js
node_js:
- "0.10"
before_script:
- npm install -g npm
- npm install -g grunt-cli

View File

@ -0,0 +1,105 @@
module.exports = function(grunt) {
grunt.initConfig({
jshint: {
all: [
'Gruntfile.js',
'tasks/*.js',
'<%= nodeunit.tests %>',
],
options: {
jshintrc: '.jshintrc',
},
},
replace: {
example: {
src: ['test/text_files/example.txt'],
dest: 'test/modified/',
replacements: [{
from: 'Hello',
to: 'Good bye'
}, {
from: /(f|F)(o{2,100})/g,
to: 'M$2'
}, {
from: /"localhost"/,
to: function (matchedWord, index, fullText, regexMatches) {
return '"www.mysite.com"';
}
}, {
from: '<p>Version:</p>',
to: '<p>Version: <%= grunt.template.date("18 Feb 2013", "yyyy-mm-dd") %></p>'
}, {
from: /[0-9]{1,2}\/[0-9]{1,2}\/[0-9]{2,4}/g,
to: function() {
return "<%= grunt.template.date('18 Feb 2013', 'dd/mm/yyyy') %>";
}
}]
},
overwrite: {
src: ['test/modified/example.txt'],
overwrite: true,
replacements: [{
from: 'World',
to: 'PLANET'
}]
},
disable_template_processing: {
src: ['test/text_files/template-example.txt'],
dest: 'test/modified/',
options: {
processTemplates: false
},
replacements: [{
from: /url\(.*\)/g,
to: function () {
return "url(<% some unprocessed text %>)";
}
}]
}
},
nodeunit: {
errors: ['test/text-replace-error-tests.js'],
tests: ['test/text-replace-unit-tests.js'],
replace: ['test/text-replace-functional-tests.js'],
},
});
grunt.loadTasks('tasks');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-nodeunit');
grunt.registerTask('default', ['jshint', 'test']);
/*
A note on testing (ie. running: grunt test):
There are two kinds of tests:
- Tests that don't result in a warning
- Test that do result in a warning (grunt.warn())
I haven't been able to find a convenient way of testing for grunt.warn()
events without enabling '--force' when running grunt. For this reason I've
set up the 'test' task to just run the main tests, and only if --force is on
to run the error-throwing tests.
*/
grunt.registerTask('test', function () {
var isForceOn = grunt.option('force') || false;
var taskList = ['nodeunit:tests'];
if (isForceOn) {
taskList.push('nodeunit:errors');
}
taskList.push('replace');
taskList.push('nodeunit:replace');
grunt.task.run(taskList);
});
};

View File

@ -0,0 +1,22 @@
Copyright (c) 2013 Jonathan Holmes
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,248 @@
# grunt-text-replace [!['Build status'][travis_image_url]][travis_page_url]
[travis_image_url]: https://api.travis-ci.org/yoniholmes/grunt-text-replace.png
[travis_page_url]: https://travis-ci.org/yoniholmes/grunt-text-replace
Replace text in files using strings, regexs or functions.
## Installation
In your project's [gruntfile][getting_started] directory, run:
```bash
npm install grunt-text-replace --save-dev
```
Then add this line to your project's [gruntfile][getting_started]:
```javascript
grunt.loadNpmTasks('grunt-text-replace');
```
[grunt]: http://gruntjs.com/
[getting_started]: https://github.com/gruntjs/grunt/wiki/Getting-started#the-gruntfile
## Usage
```javascript
replace: {
example: {
src: ['text/*.txt'], // source files array (supports minimatch)
dest: 'build/text/', // destination directory or file
replacements: [{
from: 'Red', // string replacement
to: 'Blue'
}, {
from: /(f|F)(o{2,100})/g, // regex replacement ('Fooo' to 'Mooo')
to: 'M$2'
}, {
from: 'Foo',
to: function (matchedWord) { // callback replacement
return matchedWord + ' Bar';
}
}]
}
}
```
Here's another example using [grunt.template][grunt.template], and overwriting
original source files:
```javascript
replace: {
another_example: {
src: ['build/*.html'],
overwrite: true, // overwrite matched source files
replacements: [{
from: /[0-9]{1,2}\/[0-9]{1,2}\/[0-9]{2,4}/g,
to: "<%= grunt.template.today('dd/mm/yyyy') %>"
}]
}
}
```
## API reference
### replace
*replace* is the top level task that goes in your `grunt.initConfig({})`. It is
a [multi-task][multitask], meaning that it must contain targets, which you can
name anything you like.
[multitask]: https://github.com/gruntjs/grunt/wiki/Configuring-tasks#task-configuration-and-targets
### src
*src* is an array of source files to be replaced, and is required.
It supports [minimatch][minimatch] paths.
[minimatch]: https://github.com/isaacs/minimatch
### dest
*dest* is the destination for files to be replaced, and can refer to either a:
- file: `'path/output.txt'`
- directory: `'path/'`
grunt-text-replace will throw an error if multiple source files are mapped to
a single file.
### overwrite
*overwrite* should be used for in-place replacement, that is when all you need
to do is overwrite existing files.
To use it, omit *dest*, otherwise
grunt-text-replace will throw an error. You can only use one or the other.
### replacements
*replacements* is an array of *from* and *to* replacements. See the
[examples](#usage) above.
### from
*from* is the old text that you'd like replace. It can be a:
- plain string: `'Red'` *matches all instances of 'Red' in file*
- regular expression object: `/Red/g` *same as above*
### to
*to* is the replacement. It can be a:
- plain string
- string containing a [grunt.template][grunt.template]
- string containing regex variables `$1`, `$2`, etc
- combination of the above
- function where the return value will be used as the replacement text (supports
[grunt.template][grunt.template])
- any JavaScript object
#### function
Where *to* is a function, the function receives 4 parameters:
1. **matchedWord**: the matched word
2. **index**: an integer representing point where word was found in a text
3. **fullText**: the full original text
4. **regexMatches**: an array containing all regex matches, empty if none
defined or found.
```javascript
// Where the original source file text is: "Hello world"
replacements: [{
from: /wor(ld)/g,
to: function (matchedWord, index, fullText, regexMatches) {
// matchedWord: "world"
// index: 6
// fullText: "Hello world"
// regexMatches: ["ld"]
return 'planet'; //
}
}]
// The new text will now be: "Hello planet"
```
#### JavaScript object
Where *to* is a JavaScript object, type coercion will apply as follows:
1. **null**: will result in an empty string
2. **undefined**: will return in an empty string
3. **other**: all other values will use default JavaScript type coercion. Examples:
- false: 'false'
- true: 'true'
- 0: '0'
### options
*options* is an object, specific to a target, and the only supported option is
*processTemplates*
#### processTemplates
*processTemplates* when set to false (by default it is true) switches off
grunt.template processing within function return statements. It doesn't work for
string replacements (ie. when the replacement is a string, not a function), as
grunt processes templates within config string values before they are passed to
the plugin.
```javascript
replace: {
prevent_templates_example: {
src: ['text/*.txt'],
dest: 'build/text/',
options: {
processTemplates: false
},
replacements: [{
from: /url\(.*\)/g,
to: function () {
return "url(<% Don't process this template, retain the delimeters %>)";
}
}]
}
}
```
[grunt.template]: http://gruntjs.com/api/grunt.template
## Road map
Some changes I'm considering. Happy to receive suggestions for/against:
- **Consolidate function parameters.** This would mean replacing the 4 existing
function parameters 'matchedWord', 'index', 'fullText' and 'regexMatches' with a single
'data' object with 4 members.
- **Source/Destination paths in function callback**. The above change makes it easier to
add the source and destination paths as part of the data parameter in the function callback,
which is a requested feature.
- **Grunt 4.0 'files' and 'options'**. At some point I might move to bringing the plugin
in alignment with the Grunt 4.0 convention of having standard 'files' and 'options' objects.
## Release History
- v0.4.0 - 2014/11/23. Dropping Node 0.8 support. Rewrote internals to prevent grunt-text-replace from make file changes where none are required. This was causing people difficulty with watch tasks.
- v0.3.12 - 2014/06/03. Minor update to docs - fix to a broken link.
- v0.3.11 - 2014/02/09. Added support for non-string or function 'to' replacements.
- v0.3.10 - 2013/12/02. Removed test for no source files found, accepting a pull request to do so. It's quite reasonable that you'd specify rewrite rules for files that may, or may not exist. Let me know if removing this is a problem for you.
- v0.3.9 - 2013/10/26. Copy amends in docs
- v0.3.8 - 2013/09/22. Minor data checking issue, merged from pull request.
- v0.3.7 - 2013/08/26. Bumped grunt requirements from 0.4.0 to 0.4.1 due to [changes to path API](http://gruntjs.com/blog/2013-03-13-grunt-0.4.1-released).
- v0.3.6 - 2013/06/21. Updated links in docs, some of which were pointing to 404 pages.
- v0.3.5 - 2013/06/19. Minor clean up of docs & package.json. No functional changes since 0.3.1.
- v0.3.1 - 2013/02/18. Minor feature addition: processTemplates: false to switch off grunt templates in function return statements.
- v0.3.0 - 2013/02/17. Updated to work in Grunt 4.0. This release is not backwards compatible with grunt 0.3.x.
- v0.2.10 - 2012/12/21. Minor internal refactor to better support globally installed instances of grunt on some systems.
- v0.2.9 - 2012/11/26. Fixed issue where overwrite: true was not working where multiple src files were defined.
- v0.2.7 - 2012/11/25. Fixed issue where replacing a string globally would fail
if regex characters were present in string. This is no longer a problem.
- v0.2.5 - 2012/11/23. Function replacements now support grunt.template.
- v0.2.0 - 2012/11/21. Added tests, refactored internals, strings now replace
globally within a file, updated documentation.
- v0.1.0 - 2012/11/12. Initial release.
Patch releases will generally remain undocumented in this release history.
I'll do so if there's enough reason for it, such as a functionality tweak, or
significant bug fix. For more detail see the source.
## License
Copyright (c) 2013 Jonathan Holmes
Licensed under the MIT license.

View File

@ -0,0 +1,187 @@
var grunt = require('grunt');
var path = require('path');
var gruntTextReplace = {};
exports.replace = function (settings) {
gruntTextReplace.replace(settings);
}
exports.replaceText = function (settings) {
var text = settings.text;
var replacements = settings.replacements;
return gruntTextReplace.replaceTextMultiple(text, replacements);
}
exports.replaceFile = function (settings) {
return gruntTextReplace.replaceFile(settings)
}
exports.replaceFileMultiple = function (settings) {
return gruntTextReplace.replaceFileMultiple(settings)
}
gruntTextReplace = {
replaceFileMultiple: function (settings) {
var sourceFiles = grunt.file.expand(settings.src);
sourceFiles.forEach(function (pathToSource) {
gruntTextReplace.replaceFile({
src: pathToSource,
dest: settings.dest,
replacements: settings.replacements
});
});
},
replaceFile: function (settings) {
var pathToSourceFile = settings.src;
var pathToDestinationFile = this.getPathToDestination(pathToSourceFile, settings.dest);
var replacements = settings.replacements;
var isThereAGenuineReplacement = replacements.reduce(function (previous, current) {
return previous || (current.from !== current.to)
}, false);
var isReplacementRequired = (pathToSourceFile !== pathToDestinationFile) || isThereAGenuineReplacement
if (isReplacementRequired) {
grunt.file.copy(pathToSourceFile, pathToDestinationFile, {
process: function (text) {
return gruntTextReplace.replaceTextMultiple(text, replacements);
}
});
}
},
replaceTextMultiple: function (text, replacements) {
return replacements.reduce(function (newText, replacement) {
return gruntTextReplace.replaceText({
text: newText,
from: replacement.from,
to: replacement.to
});
}, text);
},
replaceText: function (settings) {
var text = settings.text;
var from = this.convertPatternToRegex(settings.from);
var to = this.expandReplacement(settings.to);
return text.replace(from, to);
},
replace: function (settings) {
var src = grunt.file.expand(settings.src || []);
var dest = settings.dest;
var overwrite = settings.overwrite;
var replacements = settings.replacements;
var isDestinationDirectory = (/\/$/).test(dest);
var initialWarnCount = grunt.fail.warncount;
if (typeof dest === 'undefined' &&
typeof src === 'undefined' &&
typeof replacements === 'undefined') {
grunt.warn(gruntTextReplace.errorMessages.noTargetsDefined);
} else if (typeof dest === 'undefined' && overwrite !== true) {
grunt.warn(gruntTextReplace.errorMessages.noDestination);
} else if (typeof replacements === 'undefined') {
grunt.warn(gruntTextReplace.errorMessages.noReplacements);
} else if (typeof dest !== 'undefined' && overwrite === true) {
grunt.warn(gruntTextReplace.errorMessages.overwriteFailure);
} else if ((isDestinationDirectory === false && src.length > 1) && overwrite !== true) {
grunt.warn(gruntTextReplace.errorMessages.multipleSourceSingleDestination);
} else if (grunt.fail.warncount - initialWarnCount === 0) {
gruntTextReplace.replaceFileMultiple({
src: src,
dest: dest,
replacements: replacements
});
}
},
errorMessages: {
noTargetsDefined: "No targets were found. Remember to wrap functionality " +
"within a target.",
noDestination: "Destination is not defined! If you want to overwrite " +
"files, then make sure to set overwrite: true. If you don't wish to " +
"overwrite, then make sure to set a destination",
noReplacements: "No replacements were found.",
overwriteFailure: "Overwrite is to true, but a destination has also " +
"been defined. If you want to overwrite files, remove the destination. " +
"If you want to send files to a destination, then ensure overwrite is " +
"not set to true",
multipleSourceSingleDestination: "Cannot write multiple files to same " +
"file. If you wish to export to a directory, make sure there is a " +
"trailing slash on the destination. If you wish to write to a single " +
"file, make sure there is only one source file"
},
getPathToDestination: function (pathToSource, pathToDestinationFile) {
var isDestinationDirectory = (/\/$/).test(pathToDestinationFile);
var fileName = path.basename(pathToSource);
var newPathToDestination;
if (typeof pathToDestinationFile === 'undefined') {
newPathToDestination = pathToSource;
} else {
newPathToDestination = pathToDestinationFile + (isDestinationDirectory ? fileName : '');
}
return newPathToDestination;
},
convertPatternToRegex: function (pattern) {
var regexCharacters = '\\[](){}^$-.*+?|,/';
if (typeof pattern === 'string') {
regexCharacters.split('').forEach(function (character) {
var characterAsRegex = new RegExp('(\\' + character + ')', 'g');
pattern = pattern.replace(characterAsRegex, '\\$1');
});
pattern = new RegExp(pattern, 'g');
}
return pattern;
},
expandReplacement: function (replacement) {
if (typeof replacement === 'function') {
return this.expandFunctionReplacement(replacement);
} else if (typeof replacement === 'string') {
return this.expandStringReplacement(replacement);
} else {
return gruntTextReplace.expandNonStringReplacement(replacement);
}
},
expandFunctionReplacement: function (replacement) {
return function () {
var matchedSubstring = arguments[0];
var index = arguments[arguments.length - 2];
var fullText = arguments[arguments.length - 1];
var regexMatches = Array.prototype.slice.call(arguments, 1,
arguments.length - 2);
var returnValue = replacement(matchedSubstring, index, fullText,
regexMatches);
return (typeof returnValue === 'string') ?
gruntTextReplace.processGruntTemplate(returnValue) :
gruntTextReplace.expandNonStringReplacement(returnValue);
};
},
expandStringReplacement: function (replacement) {
return gruntTextReplace.processGruntTemplate(replacement);
},
expandNonStringReplacement: function (replacement) {
var isReplacementNullOrUndefined = (typeof replacement === 'undefined') || (replacement === null);
return isReplacementNullOrUndefined ? '' : String(replacement);
},
processGruntTemplate: function (string) {
var isProcessTemplateTrue = true;
if (grunt.task.current.data &&
grunt.task.current.data.options &&
typeof grunt.task.current.data.options.processTemplates !== 'undefined' &&
grunt.task.current.data.options.processTemplates === false) {
isProcessTemplateTrue = false;
}
return isProcessTemplateTrue ? grunt.template.process(string) : string;
}
}

View File

@ -0,0 +1,65 @@
{
"name": "grunt-text-replace",
"description": "Replace text in files using strings, regexs or functions.",
"version": "0.4.0",
"homepage": "https://github.com/yoniholmes/grunt-text-replace",
"author": {
"name": "Jonathan Holmes"
},
"repository": {
"type": "git",
"url": "https://github.com/yoniholmes/grunt-text-replace.git"
},
"bugs": {
"url": "https://github.com/yoniholmes/grunt-text-replace/issues"
},
"licenses": [
{
"type": "MIT",
"url": "https://github.com/yoniholmes/grunt-text-replace.git/blob/master/LICENSE-MIT"
}
],
"main": "Gruntfile.js",
"engines": {
"node": ">= 0.8.0"
},
"scripts": {
"test": "grunt --force"
},
"devDependencies": {
"grunt": ">= 0.4.1",
"grunt-contrib-jshint": ">= 0.6.3",
"grunt-contrib-nodeunit": ">= 0.2.0",
"sinon": "^1.12.1"
},
"keywords": [
"gruntplugin",
"replace",
"text",
"string",
"regex",
"function"
],
"dependencies": {},
"gitHead": "742013661eba90e251bc94ff8c06fbd6a1193ac0",
"_id": "grunt-text-replace@0.4.0",
"_shasum": "db9d9ce59e2fe49da277e9dbc195c3e11cfb16c2",
"_from": "grunt-text-replace@*",
"_npmVersion": "1.4.28",
"_npmUser": {
"name": "yoniholmes",
"email": "j.h.london.uk@gmail.com"
},
"maintainers": [
{
"name": "yoniholmes",
"email": "j.h.london.uk@gmail.com"
}
],
"dist": {
"shasum": "db9d9ce59e2fe49da277e9dbc195c3e11cfb16c2",
"tarball": "http://registry.npmjs.org/grunt-text-replace/-/grunt-text-replace-0.4.0.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/grunt-text-replace/-/grunt-text-replace-0.4.0.tgz"
}

View File

@ -0,0 +1,29 @@
/*
* grunt-text-replace
* https://github.com/Yoni/grunt-4-test
*
* Copyright (c) 2013 Jonathan Holmes
* Licensed under the MIT license.
*/
var gruntTextReplace = require('../lib/grunt-text-replace');
module.exports = function(grunt) {
// Please see the grunt documentation for more information regarding task
// creation: https://github.com/gruntjs/grunt/blob/devel/docs/toc.md
grunt.registerMultiTask('replace',
'General purpose text replacement for grunt. Allows you to replace ' +
'text in files using strings, regexs or functions.',
function () {
gruntTextReplace.replace({
src: this.data.src,
dest: this.data.dest,
overwrite: this.data.overwrite,
replacements: this.data.replacements
});
});
};

View File

@ -0,0 +1,115 @@
var grunt = require('grunt');
var fs = require('fs');
var gruntTextReplace = require('../lib/grunt-text-replace');
var replace = function (settings) {
return gruntTextReplace.replace(settings);
};
exports.textReplace = {
'Test error handling': {
setUp: function (done) {
grunt.file.copy('test/text_files/test.txt', 'test/temp/testA.txt');
grunt.file.copy('test/text_files/test.txt', 'test/temp/testB.txt');
done();
},
tearDown: function (done) {
fs.unlinkSync('test/temp/testA.txt');
fs.unlinkSync('test/temp/testB.txt');
fs.rmdirSync('test/temp');
done();
},
'Test no destination found': function (test) {
var warnCountBefore = grunt.fail.warncount;
replace({
src: 'test/temp/testA.txt',
replacements: [{ from: 'Hello', to: 'Good bye' }]
});
test.equal(grunt.fail.warncount - warnCountBefore, 1);
replace({
src: 'test/temp/testA.txt',
overwrite: true,
replacements: [{ from: 'Hello', to: 'Good bye' }]
});
test.equal(grunt.fail.warncount - warnCountBefore, 1);
replace({
src: 'test/temp/testA.txt',
dest: 'test/temp/',
replacements: [{ from: 'Hello', to: 'Good bye' }]
});
test.equal(grunt.fail.warncount - warnCountBefore, 1);
test.done();
},
'Test no replacements found': function (test) {
var warnCountBefore = grunt.fail.warncount;
replace({
src: 'test/temp/testA.txt',
dest: 'test/temp/'
});
test.equal(grunt.fail.warncount - warnCountBefore, 1);
replace({
src: 'test/temp/testA.txt',
dest: 'test/temp/',
replacements: [{ from: 'Hello', to: 'Good bye' }]
});
test.equal(grunt.fail.warncount - warnCountBefore, 1);
test.done();
},
'Test overwrite failure': function (test) {
var warnCountBefore = grunt.fail.warncount;
replace({
src: 'test/temp/testA.txt',
dest: 'test/temp/',
overwrite: true,
replacements: [{ from: 'Hello', to: 'Good bye' }]
});
test.equal(grunt.fail.warncount - warnCountBefore, 1);
replace({
src: 'test/temp/*',
overwrite: true,
replacements: [{ from: 'Hello', to: 'Good bye' }]
});
test.equal(grunt.fail.warncount - warnCountBefore, 1);
replace({
src: 'test/temp/testA.txt',
overwrite: true,
replacements: [{ from: 'Hello', to: 'Good bye' }]
});
test.equal(grunt.fail.warncount - warnCountBefore, 1);
test.done();
},
'Test destination error': function (test) {
var warnCountBefore = grunt.fail.warncount;
replace({
src: 'test/temp/*',
dest: 'test/temp',
replacements: [{ from: 'Hello', to: 'Good bye' }]
});
test.equal(grunt.fail.warncount - warnCountBefore, 1);
replace({
src: 'test/temp/*',
dest: 'test/temp/testA.txt',
replacements: [{ from: 'Hello', to: 'Good bye' }]
});
test.equal(grunt.fail.warncount - warnCountBefore, 2);
replace({
src: 'test/temp/testA.txt',
dest: 'test/temp/testB.txt',
replacements: [{ from: 'Hello', to: 'Good bye' }]
});
test.equal(grunt.fail.warncount - warnCountBefore, 2);
test.done();
}
}
};

View File

@ -0,0 +1,19 @@
var grunt = require('grunt');
var fs = require('fs');
exports.textReplace = {
'Test replace tasks in grunt file produced the correct result': function (test) {
var modifiedFile = grunt.file.read('test/modified/example.txt');
var expectedResult = grunt.file.read('test/text_files/expected-result.txt');
test.equal(modifiedFile, expectedResult);
test.done();
},
'Test "processTemplates: false" correctly disables grunt.template processing in function return statements': function (test) {
var modifiedFile = grunt.file.read('test/modified/template-example.txt');
var expectedResult = grunt.file.read('test/text_files/template-expected-result.txt');
test.equal(modifiedFile, expectedResult);
test.done();
}
};

View File

@ -0,0 +1,200 @@
var grunt = require('grunt');
var fs = require('fs');
var gruntTextReplace = require('../lib/grunt-text-replace');
var sinon = require('sinon');
var replaceText = function (text, from, to) {
return gruntTextReplace.replaceText({
text: text,
replacements: [{
from: from,
to: to
}]
});
};
var replaceTextMultiple = function (text, replacements) {
return gruntTextReplace.replaceText({
text: text,
replacements: replacements
});
};
var replaceFile = function (pathToSourceFile, pathToDestinationFile, replacements) {
return gruntTextReplace.replaceFile({
src: pathToSourceFile,
dest: pathToDestinationFile,
replacements: replacements
});
};
var replaceFileMultiple = function (sourceFiles, destinationDirectory, replacements) {
return gruntTextReplace.replaceFileMultiple({
src: sourceFiles,
dest: destinationDirectory,
replacements: replacements
});
};
exports.textReplace = {
'Test core replacement functionality': {
'Test string replacements': function (test) {
test.equal(replaceText('Hello world', 'Hello', 'Goodbye'), 'Goodbye world');
test.notEqual(replaceText('Hello w000rld', 'w0*rld', 'world'), 'Hello world');
test.equal(replaceText('Hello (*foo.)', '(*foo.)', 'world'), 'Hello world');
test.equal(replaceText('Hello \\foo', '\\', ''), 'Hello foo');
test.equal(replaceText('Foo bar bar', 'bar', 'foo'), 'Foo foo foo');
test.equal(replaceText('Foo bar bar', 'bar', 'Foo bar'), 'Foo Foo bar Foo bar');
test.done();
},
'Test regex replacements': function (test) {
test.equal(replaceText('Hello world', /Hello/, 'Goodbye'), 'Goodbye world');
test.equal(replaceText('Hello world', /(Hello) (world)/, '$2 $1'), 'world Hello');
test.equal(replaceText('Foo bar bar', /bar/, 'foo'), 'Foo foo bar');
test.equal(replaceText('Foo bar bar', /bar/g, 'foo'), 'Foo foo foo');
test.done();
},
'Test grunt.template replacements': function (test) {
test.equal(replaceText('Hello world', 'world',
'<%= grunt.template.date("20 Nov 2012 11:30:00 GMT", "dd/mm/yy") %>'), 'Hello 20/11/12');
test.done();
},
'Test function replacements': function (test) {
test.equal(replaceText('Hello world', 'world',
function (matchedWord, index, fullText, regexMatches) {
return new Array(4).join(matchedWord);
}), 'Hello worldworldworld');
test.equal(replaceText('Hello world', 'world',
function (matchedWord, index, fullText, regexMatches) {
return index;
}), 'Hello 6');
test.equal(replaceText('Hello world', 'Hello',
function (matchedWord, index, fullText, regexMatches) {
return index;
}), '0 world');
test.equal(replaceText('Hello world', 'foo',
function (matchedWord, index, fullText, regexMatches) {
return index;
}), 'Hello world');
test.equal(replaceText('Hello world', 'world',
function (matchedWord, index, fullText, regexMatches) {
return fullText;
}), 'Hello Hello world');
test.equal(replaceText('Hello world', /(Hello) (world)/g,
function (matchedWord, index, fullText, regexMatches) {
return 'Place: ' + regexMatches[1] + ', Greeting: ' + regexMatches[0];
}), 'Place: world, Greeting: Hello');
test.equal(replaceText('Hello world', /(Hello) (world)/g,
function (matchedWord, index, fullText, regexMatches) {
return regexMatches[0] + ' <%= grunt.template.date("20 Nov 2012 11:30:00 GMT", "dd/mm/yy") %>';
}), 'Hello 20/11/12');
test.done();
},
'Test non string or function "to" replacements': function (test) {
test.equal(replaceText('Hello 0 true 1 false 2345', 'true', false), 'Hello 0 false 1 false 2345');
test.equal(replaceText('Hello 0 true 1 false 2345', 'false', true), 'Hello 0 true 1 true 2345');
test.equal(replaceText('Hello 0 true 1 false 2345', '1', 22), 'Hello 0 true 22 false 2345');
test.equal(replaceText('Hello 0 true 1 false 2345', '0', 1), 'Hello 1 true 1 false 2345');
test.equal(replaceText('Hello 0 true 1 false 2345', /true|false/g, 0), 'Hello 0 0 1 0 2345');
test.equal(replaceText('Hello 0 true 1 false 2345', 'Hello', 1e5), '100000 0 true 1 false 2345');
test.equal(replaceText('Hello 0 true 1 false 2345', 'Hello', null), ' 0 true 1 false 2345');
test.equal(replaceText('Hello 0 true 1 false 2345', 'true', undefined), 'Hello 0 1 false 2345');
test.done();
},
'Test multiple replacements': function (test) {
test.equal(replaceTextMultiple('Hello world',
[{
from: 'Hello',
to: 'Hi'
}, {
from: 'world',
to: 'planet'
}]), 'Hi planet');
test.done();
}
},
'Test file handling': {
setUp: function (done) {
grunt.file.copy('test/text_files/test.txt', 'test/temp/testA.txt');
grunt.file.copy('test/text_files/test.txt', 'test/temp/testB.txt');
sinon.spy(grunt.file, "copy");
done();
},
tearDown: function (done) {
fs.unlinkSync('test/temp/testA.txt');
fs.unlinkSync('test/temp/testB.txt');
fs.rmdirSync('test/temp');
grunt.file.copy.restore();
done();
},
'Test change to file specifying destination file': function (test) {
var originalText, replacedText;
originalText = grunt.file.read('test/temp/testA.txt');
replaceFile('test/temp/testA.txt', 'test/temp/testA.txt', [{from: 'world', to: 'planet'}]);
replacedText = grunt.file.read('test/temp/testA.txt');
test.equal(originalText, 'Hello world');
test.equal(replacedText, 'Hello planet');
test.done();
},
'Test files do not get changed if there are no matches and paths are the same': function (test) {
replaceFile('test/temp/testA.txt', 'test/temp/testA.txt', [{from: 'world', to: 'planet'}]);
test.equal(grunt.file.copy.callCount, 1);
replaceFile('test/temp/testA.txt', 'test/temp/testA.txt', [{from: 'planet', to: 'planet'}]);
test.equal(grunt.file.copy.callCount, 1);
test.done();
},
'Test files get changed if there are no matches and paths are the different': function (test) {
replaceFile('test/temp/testA.txt', 'test/temp/testB.txt', [{from: 'world', to: 'planet'}]);
test.equal(grunt.file.copy.callCount, 1);
replaceFile('test/temp/testA.txt', 'test/temp/testB.txt', [{from: 'world', to: 'world'}]);
test.equal(grunt.file.copy.callCount, 2);
test.done();
},
'Test change to file specifying destination directory': function (test) {
var originalText, replacedText;
originalText = grunt.file.read('test/temp/testA.txt');
replaceFile('test/temp/testA.txt', 'test/temp/', [{from: 'world', to: 'planet'}]);
replacedText = grunt.file.read('test/temp/testA.txt');
test.equal(originalText, 'Hello world');
test.equal(replacedText, 'Hello planet');
test.done();
},
'Test change to multiple files specifying paths': function (test) {
var originalText, replacedTextA, replacedTextB;
originalText = grunt.file.read('test/temp/testA.txt');
replaceFileMultiple(['test/temp/testA.txt', 'test/temp/testB.txt'], 'test/temp/', [{from: 'world', to: 'planet'}]);
replacedTextA = grunt.file.read('test/temp/testA.txt');
replacedTextB = grunt.file.read('test/temp/testB.txt');
test.equal(originalText, 'Hello world');
test.equal(replacedTextA, 'Hello planet');
test.equal(replacedTextB, 'Hello planet');
test.done();
},
'Test change to multiple files specifying minimatch paths': function (test) {
var originalText, replacedTextA, replacedTextB;
originalText = grunt.file.read('test/temp/testA.txt');
replaceFileMultiple(['test/temp/test*.txt'], 'test/temp/', [{from: 'world', to: 'planet'}]);
replacedTextA = grunt.file.read('test/temp/testA.txt');
replacedTextB = grunt.file.read('test/temp/testB.txt');
test.equal(originalText, 'Hello world');
test.equal(replacedTextA, 'Hello planet');
test.equal(replacedTextB, 'Hello planet');
test.done();
}
}
};

View File

@ -0,0 +1,9 @@
Hello World.
Foooooooooo.
<p>Version:</p>
<a href="localhost">Link</a>
01/12/2012

View File

@ -0,0 +1,9 @@
Good bye PLANET.
Moooooooooo.
<p>Version: 2013-02-18</p>
<a href="www.mysite.com">Link</a>
18/02/2013

View File

@ -0,0 +1 @@
url('http://www.google.com');

View File

@ -0,0 +1 @@
url(<% some unprocessed text %>);

View File

@ -0,0 +1 @@
Hello world