Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

grunt-neuter

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

grunt-neuter - npm Package Compare versions

Comparing version 0.5.0 to 0.6.0

.travis.yml

75

Gruntfile.js

@@ -61,22 +61,40 @@ /*

// Run to test the default simple require options.
custom_separator_options: {
// Run to test the basePath option.
simple_basepath_options: {
// NOTE: this uses the filepath transform fixture because it performs the same operation
files: {
'tmp/custom_separator_options' : ['test/fixtures/simple_require_statements.js']
'tmp/simple_basepath_options' : ['test/fixtures/simple_require_filepath_transforms.js']
},
options: {
separator: '!!!!'
basePath: 'test/fixtures/'
}
},
// Run to test the inclusion of source urls.
custom_source_url_inclusion_option: {
// Run to test relative require statements.
relative_require_statements: {
files: {
'tmp/custom_source_url_inclusion_option' : ['test/fixtures/simple_require_statements.js']
'tmp/relative_require_statements' : ['test/fixtures/relative_require_statements.js']
}
},
// Run to test relative require statements in conjunction with the basePath option
relative_requires_with_basepath: {
files: {
'tmp/relative_requires_with_basepath' : ['test/fixtures/relative_requires_with_basepath.js'],
},
options: {
includeSourceURL: true
basePath: 'test/fixtures/'
}
},
// Run to test the default simple require options.
custom_separator_options: {
files: {
'tmp/custom_separator_options' : ['test/fixtures/simple_require_statements.js']
},
options: {
separator: '!!!!'
}
},
// Run to test that duplicate require statemtns only write a source file to the

@@ -137,2 +155,43 @@ // destination once.

}
},
optional_semicolons: {
files: {
'tmp/optional_semicolons': ['test/fixtures/optional_semicolons.js']
}
},
optional_dotjs: {
files: {
'tmp/optional_dotjs': ['test/fixtures/optional_dotjs.js']
}
},
source_maps: {
files: {
'tmp/source_maps': ['test/fixtures/glob_require.js']
},
options: {
includeSourceMap: true
}
},
process_as_template: {
files: {
'tmp/process_as_template': ['test/fixtures/process_as_template.js']
},
options: {
process: {
data: {
foo: 5,
bar: 'baz'
}
}
}
},
process_with_function: {
files: {
'tmp/process_with_function': ['test/fixtures/simple_require.js']
},
options: {
process: function(src, filepath) {
return '// Source for: ' + filepath + '\n' + src;
}
}
}

@@ -139,0 +198,0 @@ },

5

package.json
{
"name": "grunt-neuter",
"version": "0.5.0",
"version": "0.6.0",
"description": "Builds source files in the order you require.",

@@ -19,3 +19,4 @@ "main": "Gruntfile.js",

"dependencies": {
"glob": "~3.2.1"
"glob": "~3.2.3",
"source-map": "~0.1.22"
},

@@ -22,0 +23,0 @@ "devDependencies": {

@@ -1,7 +0,6 @@

# grunt-neuter
# grunt-neuter [![Build Status](https://travis-ci.org/trek/grunt-neuter.png)](https://travis-ci.org/trek/grunt-neuter)
> Concatenate files in the order you `require`.
_Note that this plugin has not yet been released, and only works with the latest bleeding-edge, in-development version of grunt. See the [When will I be able to use in-development feature 'X'?](https://github.com/gruntjs/grunt/wiki/Frequently-Asked-Questions) FAQ entry for more information._
## Getting Started

@@ -53,2 +52,98 @@ If you haven't used [grunt][] before, be sure to check out the [Getting Started][] guide, as it explains how to create a [gruntfile][Getting Started] as well as install and use grunt plugins. Once you're familiar with that process, install this plugin with this command:

## Example
Given the following files:
`a.js`
```javascript
require('b');
var myVariable = 'hello';
```
`b.js`
```javascript
var variableFromB = 'b';
window.availableEverywhere = true;
```
Resulting output would be
```javascript
(function(){
var variableFromB = 'b';
window.availableEverywhere = true;
})();
(function(){
var myVariable = 'hello';
})();
```
## Relative Paths
Relative paths using a dot to indicate the file's current directory are valid as well:
`a.js`
```javascript
require('dir/b');
var variableFromA = 'a';
```
`dir/b.js`
```javascript
require('./c');
var variableFromB = 'b';
```
`dir/c.js`
```javascript
var variableFromC = 'c';
```
Outputs
```javascript
(function(){
var variableFromC = 'c';
})();
(function(){
var variableFromB = 'b';
})();
(function(){
var variableFromA = 'a';
})();
```
Note that directory traversal using `../` is **not** supported.
## Example Gruntfile Use
```javascript
grunt.initConfig({
neuter: {
application: {
src: 'tmp/application.js',
dest: 'app/index.js'
}
}
});
```
or
```javascript
grunt.initConfig({
neuter: {
'tmp/application.js' :'app/index.js'
}
});
```
### Options

@@ -65,2 +160,9 @@

### basePath
Type: `String`
Default: `""`
Specifying a base path allows you to omit said portion of the filepath from your require statements. For example: when using `basePath: "lib/js/"` in your task options, `require("lib/js/file.js");` can instead be written as `require("file.js");`. Note that the trailing slash *must* be included.
### filepathTransform

@@ -71,6 +173,6 @@ Type: `Function`

Specifying a filepath transform allows you to omit said portion of the filepath from your require statements. For example: when using `filepathTransform: function(filepath){ return 'lib/js/' + filepath; }` in your task options, require("lib/js/file.js") can instead be written as require("file.js").
Specifying a filepath transform allows you to control the path to the file that actually gets concatenated. For example, when using `filepathTransform: function(filepath){ return 'lib/js/' + filepath; }` in your task options, `require("lib/js/file.js");` can instead be written as `require("file.js");` (This achieves the same result as specifying `basePath: "lib/js/"`). When used in conjunction with the `basePath` option, the base path will be prepended to the `filepath` argument and a second argument will be provided that is the directory of the file **without** the `basePath`.
### includeSourceURL
Type: Boolean`
Type: `Boolean`

@@ -97,1 +199,15 @@ Default: `false`

around in a way that isn't meaningful to neutering.
### process
Type: `Boolean` `Object` `Function` Default: `false`
Process source files before concatenating, either as [templates](https://github.com/gruntjs/grunt/wiki/grunt.template) or with a custom function (similar to [grunt-contrib-concat](https://github.com/gruntjs/grunt-contrib-concat)). When using grunt for templating, the delimiters default to neuter's own special type (`{% %}`), which helps avoid errors when requiring libraries like [Underscore](http://underscorejs.org/) or [Lo-Dash](http://lodash.com/).
* `false` - No processing will occur.
* `true` - Process source files using [grunt.template.process][] without any data.
* `options` object - Process source files using [grunt.template.process][], using the specified options.
* `function(src, filepath)` - Process source files using the given function, called once for each file. The returned value will be used as source code.
_(Default processing options are explained in the [grunt.template.process][] documentation)_
[grunt.template.process]: https://github.com/gruntjs/grunt/wiki/grunt.template#grunttemplateprocess

@@ -11,3 +11,8 @@ /*

var glob = require("glob");
var path = require("path");
var SourceNode = require('source-map').SourceNode;
var SourceMapGenerator = require('source-map').SourceMapGenerator;
var SourceMapConsumer = require('source-map').SourceMapConsumer;
module.exports = function(grunt) {

@@ -26,16 +31,29 @@ grunt.registerMultiTask('neuter', 'Concatenate files in the order you require', function() {

// no need to include a .js as this will be appended for you.
var requireSplitter = /^\s*(require\(\s*[\'||\"].*[\'||\"]\s*\));+\n*/m;
var requireMatcher = /^require\(\s*[\'||\"](.*)[\'||\"]\s*\)/m;
var requireSplitter = /^\s*(require\(\s*[\'||\"].*[\'||\"]\s*\));*\n*/m;
var requireMatcher = /^require\(\s*[\'||\"](.*?)(?:\.js)?[\'||\"]\s*\)/m;
// add mustache style delimiters
grunt.template.addDelimiters('neuter', '{%', '%}');
var options = this.options({
basePath: '',
filepathTransform: function(filepath){ return filepath; },
template: "(function() {\n\n{%= src %}\n\n})();",
separator: "\n\n",
includeSourceURL: false,
skipFiles: []
includeSourceMap: false,
skipFiles: [],
process: false
});
// process, but with no data
if (options.process === true) {
options.process = {};
}
// default to using 'neuter' style templates for processing
// (this avoids issues with requiring underscore or lodash)
if (grunt.util.kindOf(options.process) === 'object') {
options.process.delimiters = options.process.delimiters || 'neuter';
}
// a poor man's Set

@@ -54,3 +72,10 @@ var skipFiles = {};

files.forEach(function(filepath) {
// save the file's directory without the 'basePath' prefix
var dirname = (path.dirname(filepath) + '/').replace(options.basePath, '');
// create an absolute path to the file and prepend the 'basePath'
var normalizePath = function(path) {
return options.basePath + path.replace(/^\.\//, dirname) + '.js';
};
// once a file has been required its source will

@@ -63,2 +88,9 @@ // never be written to the resulting destination file again.

// process file as a template if specified
if (typeof options.process === 'function') {
src = options.process(src, filepath);
} else if (options.process) {
src = grunt.template.process(src, options.process);
}
// if a file should not be nuetered

@@ -70,3 +102,2 @@ // it is part of the skipFiles option

} else {
// split the source into code sections

@@ -87,3 +118,3 @@ // these will be either require(...) statements

if (match) {
finder(options.filepathTransform(match[1]) + '.js');
finder(options.filepathTransform(normalizePath(match[1]), dirname));
} else {

@@ -101,20 +132,74 @@ out.push({filepath: filepath, src: section});

// which defaults to a functional closure.
// source map support adapted from Koji NAKAMURA's grunt-concat-sourcemap
// https://github.com/kozy4324/grunt-concat-sourcemap
this.files.forEach(function(file) {
grunt.file.expand({nonull: true}, file.src).map(finder, this);
var outStr = out.map(function(section){
var templateData = {
data: section,
delimiters:'neuter'
};
if (options.includeSourceURL) {
return "eval(" + JSON.stringify(grunt.template.process(options.template, templateData) + "//@ sourceURL=" + section.filepath) +")";
} else {
return grunt.template.process(options.template, templateData);
}
}).join(options.separator);
var sourceNode = new SourceNode(null, null, null);
grunt.file.write(file.dest, outStr);
out = out.map(function(section) {
return {
src: grunt.template.process(options.template, {data: section, delimiters: 'neuter'}),
filepath: section.filepath
};
});
// test if template block has newlines to offset against
var m, n;
if (m = options.template.match(/([\S\s]*)(?={%= src %})/)) {
var beforeOffset = m[0].split("\n").length - 1;
}
if (n = options.template.match(/{%= src %}([\S\s]*)/)) {
var afterOffset = n[1].split("\n").length - 1;
}
for (var i = 0; i < out.length; i++) {
var src = out[i].src;
// split on newline and re-add
var chunks = src.split('\n');
for (var j=0; j < chunks.length - 1; j++) {
chunks[j] = chunks[j] + '\n';
}
// Lines that map to their original file are added as SourceNodes
// (with line data). Others are added as dataless chunks.
for (var k=0; k < chunks.length; k++) {
var line = chunks[k];
if (k > beforeOffset && k < chunks.length - afterOffset) {
sourceNode.add(new SourceNode(k + 1 - beforeOffset, 0, out[i].filepath, line));
}
else {
sourceNode.add(line);
}
};
// If this isn't the last file, add the separator as a dataless
// chunk.
if (i != out.length - 1) {
sourceNode.add(options.separator);
}
}
if (options.includeSourceMap) {
var mapFilePath = file.dest.split('/').pop() + '.map';
sourceNode.add('//@ sourceMappingURL=' + mapFilePath);
}
var codeMap = sourceNode.toStringWithSourceMap({
file: file.dest,
sourceRoot: options.sourceRoot
});
grunt.file.write(file.dest, codeMap.code);
if (options.includeSourceMap) {
var generator = SourceMapGenerator.fromSourceMap(new SourceMapConsumer(codeMap.map.toJSON()));
var newSourceMap = generator.toJSON();
newSourceMap.file = path.basename(newSourceMap.file);
grunt.file.write(file.dest + ".map", JSON.stringify(newSourceMap, null, ' '));
}
});
});
};

@@ -22,26 +22,34 @@ 'use strict';

},
custom_separator_options: function(test){
simple_basepath_options: function(test) {
var actual = grunt.file.read('tmp/custom_separator_options');
var expected = grunt.file.read('test/expected/custom_separator_options');
test.equal(actual, expected, 'statment separator can be customized');
var actual = grunt.file.read('tmp/simple_basepath_options');
var expected = grunt.file.read('test/expected/simple_require_filepath_transforms');
test.equal(actual, expected, 'files are correctly combined');
test.done();
},
custom_source_url_inclusion_option: function(test){
relative_require_statements: function(test) {
var actual = grunt.file.read('tmp/custom_source_url_inclusion_option');
var expected = grunt.file.read('test/expected/custom_source_url_inclusion_option');
test.equal(actual, expected, '@ sourceURL can be included for debugging');
var actual = grunt.file.read('tmp/relative_require_statements');
var expected = grunt.file.read('test/expected/relative_require_statements');
test.equal(actual, expected, 'files are correctly combined');
test.done();
},
requires_are_only_included_once: function(test){
relative_requires_with_basepath: function(test) {
var actual = grunt.file.read('tmp/custom_source_url_inclusion_option');
var expected = grunt.file.read('test/expected/custom_source_url_inclusion_option');
test.equal(actual, expected, '@ sourceURL can be included for debugging');
var actual = grunt.file.read('tmp/relative_requires_with_basepath');
var expected = grunt.file.read('test/expected/relative_requires_with_basepath');
test.equal(actual, expected, 'files are correctly combined');
test.done();
},
custom_separator_options: function(test){
var actual = grunt.file.read('tmp/custom_separator_options');
var expected = grunt.file.read('test/expected/custom_separator_options');
test.equal(actual, expected, 'statment separator can be customized');
test.done();
},
duplicate_require_statements: function(test){

@@ -88,5 +96,5 @@

},
do_not_replace_requires_in_statements: function(test){
var actual = grunt.file.read('tmp/do_not_replace_requires_in_statements');

@@ -99,3 +107,3 @@ var expected = grunt.file.read('test/expected/do_not_replace_requires_in_statements');

comment_out_require: function(test){
var actual = grunt.file.read('tmp/comment_out_require');

@@ -122,4 +130,45 @@ var expected = grunt.file.read('test/expected/comment_out_require');

test.done();
},
optional_semicolons: function(test){
var actual = grunt.file.read('tmp/optional_semicolons');
var expected = grunt.file.read('test/expected/optional_semicolons');
test.equal(actual, expected, 'semicolons are optional as long as there\'s a newline');
test.done();
},
optional_dotjs: function(test){
var actual = grunt.file.read('tmp/optional_dotjs');
var expected = grunt.file.read('test/expected/optional_dotjs');
test.equal(actual, expected, 'the .js extension is optional');
test.done();
},
source_maps: function(test) {
var actualJs = grunt.file.read('tmp/source_maps');
var actualMap = grunt.file.read('tmp/source_maps.map');
var expectedJs = grunt.file.read('test/expected/source_maps');
var expectedMap = grunt.file.read('test/expected/source_maps.map');
test.equal(actualJs, expectedJs, 'the js includes sourceMap output');
test.equal(actualMap, expectedMap, 'the map is generated');
test.done();
},
process_as_template: function(test) {
var actual = grunt.file.read('tmp/process_as_template');
var expected = grunt.file.read('test/expected/process_as_template');
test.equal(actual, expected, 'files are processed as templates');
test.done();
},
process_with_function: function(test) {
var actual = grunt.file.read('tmp/process_with_function');
var expected = grunt.file.read('test/expected/process_with_function');
test.equal(actual, expected, 'files are processed with a function');
test.done();
}
};
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc