From 85af37e07ff652187e37b89c81e7e1434687e03b Mon Sep 17 00:00:00 2001 From: Colin Bowern Date: Fri, 4 Oct 2013 22:54:27 -0400 Subject: [PATCH] Initial commit --- .gitignore | 3 + .jshintrc | 13 ++++ Gruntfile.js | 116 ++++++++++++++++++++++++++++++++++ LICENSE-MIT | 22 +++++++ README.md | 81 ++++++++++++++++++++++++ debug.ps1 | 1 + package.json | 47 ++++++++++++++ tasks/importer.js | 77 ++++++++++++++++++++++ test/expected/foo.js | 6 ++ test/expected/footoo.js | 6 ++ test/fixtures/bar/buzz.js | 3 + test/fixtures/bar/fizz.js | 3 + test/fixtures/foo.js | 2 + test/fixtures/foo.template.js | 2 + test/fixtures/footoo.js | 2 + test/importer_test.js | 56 ++++++++++++++++ 16 files changed, 440 insertions(+) create mode 100644 .gitignore create mode 100644 .jshintrc create mode 100644 Gruntfile.js create mode 100644 LICENSE-MIT create mode 100644 README.md create mode 100644 debug.ps1 create mode 100644 package.json create mode 100644 tasks/importer.js create mode 100644 test/expected/foo.js create mode 100644 test/expected/footoo.js create mode 100644 test/fixtures/bar/buzz.js create mode 100644 test/fixtures/bar/fizz.js create mode 100644 test/fixtures/foo.js create mode 100644 test/fixtures/foo.template.js create mode 100644 test/fixtures/footoo.js create mode 100644 test/importer_test.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b785247 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules +npm-debug.log +tmp diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..f57a8ff --- /dev/null +++ b/.jshintrc @@ -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 +} diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..78ca48d --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,116 @@ +/* + * grunt-importer + * https://github.com/colinbowern/grunt-importer + * + * Copyright (c) 2013 Colin Bowern + * Licensed under the MIT license. + */ + +'use strict'; + +module.exports = function (grunt) { + + // Project configuration. + grunt.initConfig({ + jshint: { + all: [ + 'Gruntfile.js', + 'tasks/*.js', + '<%= nodeunit.tests %>', + ], + options: { + jshintrc: '.jshintrc', + }, + }, + + // Before generating any new files, remove any previously-created files. + clean: { + tests: ['tmp'], + }, + + // Setup for tests + copy: { + tests: { + files: [{ + expand: true, + cwd: 'test/fixtures', + src: ['**/*.*', '!**/*.template.js'], + dest: 'tmp/replace_single_file' + }, + { + expand: true, + cwd: 'test/fixtures', + src: ['**/*.*', '!**/*.template.js'], + dest: 'tmp/replace_multiple_files' + }, + { + expand: true, + cwd: 'test/fixtures', + src: ['**/*.*', '!foo.js'], + dest: 'tmp/rename_file' + }] + } + }, + + // Configurations to be tested + importer: { + replace_single_file: { + files: [{ src: 'tmp/replace_single_file/foo.js' }] + }, + replace_multiple_files: { + files: [{ src: 'tmp/replace_multiple_files/*.js' }] + }, + rename_file: { + files: [{ + expand: true, + src: 'tmp/rename_file/foo.template.js', + rename: function (dest, src) { + return (dest || '') + src.replace('.template.js', '.js'); + } + }] + }, + different_output_folder: { + files : [{ + expand: true, + flatten: true, + src: 'test/fixtures/foo.js', + dest: 'tmp/different_output_folder/' + }] + }, + different_output_folder_and_rename: { + files: [{ + expand: true, + flatten: true, + src: 'test/fixtures/foo.template.js', + dest: 'tmp/different_output_folder_and_rename/', + rename: function (dest, src) { + return (dest || '') + src.replace('.template.js', '.js'); + } + }] + } + }, + + // Unit tests + nodeunit: { + tests: ['test/*_test.js'], + }, + + }); + + // Actually load this plugin's task(s). + grunt.loadTasks('tasks'); + + // These plugins provide necessary tasks. + grunt.loadNpmTasks('grunt-contrib-jshint'); + grunt.loadNpmTasks('grunt-contrib-clean'); + grunt.loadNpmTasks('grunt-contrib-nodeunit'); + grunt.loadNpmTasks('grunt-contrib-copy'); + + // Whenever the "test" task is run, first clean the "tmp" dir, then run this + // plugin's task(s), then test the result. + grunt.registerTask('test', ['clean', 'copy', 'importer', 'nodeunit']); + + // By default, lint and run all tests. + grunt.registerTask('default', ['jshint', 'test']); + +}; diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..e4d1a0b --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,22 @@ +Copyright (c) 2013 Colin Bowern + +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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..413e4b3 --- /dev/null +++ b/README.md @@ -0,0 +1,81 @@ +# grunt-importer + +> Importer adds an #import statement to JavaScript based languages including CoffeeScript that works like #include in C-based languages. It concatenates them together in the places you've defined. + +## Getting Started +This plugin requires Grunt `~0.4.1` + +If you haven't used [Grunt](http://gruntjs.com/) before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to create a [Gruntfile](http://gruntjs.com/sample-gruntfile) as well as install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command: + +```shell +npm install grunt-importer --save-dev +``` + +Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript: + +```js +grunt.loadNpmTasks('grunt-importer'); +``` + +## The "importer" task + +### Overview +In your project's Gruntfile, add a section named `importer` to the data object passed into `grunt.initConfig()`. + +```js +grunt.initConfig({ + importer: { + scripts: { + files: [{ + expand: true, + src: 'scripts/layout.template.js', + rename: function (dest, src) { + return (dest || '') + src.replace('.template.js', '.js'); + } + }] + }, + }, +}) +``` + +### Usage Examples + +#### Replace a Single File +In this example the script would be replaced in-place with any import statements substituted for their references. + +```js +grunt.initConfig({ + importer: { + scripts: { + files: [{ src: 'tmp/replace_single_file/foo.js' }] + } + }, +}) +``` + +#### Output to Different Folder and Rename +In this example the dynamic file expanding object is used to output the results to a different folder using a different file name: + +```js +grunt.initConfig({ + importer: { + scripts: { + files: [{ + expand: true, + flatten: true, + src: 'test/fixtures/foo.template.js', + dest: 'tmp/different_output_folder_and_rename/', + rename: function (dest, src) { + return (dest || '') + src.replace('.template.js', '.js'); + } + }] + }, + }, +}) +``` + +## Contributing +In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](http://gruntjs.com/). + +## Release History +* 2013-10-04   v1.0.0   Initial release diff --git a/debug.ps1 b/debug.ps1 new file mode 100644 index 0000000..3836092 --- /dev/null +++ b/debug.ps1 @@ -0,0 +1 @@ +node --debug-brk $env:APPDATA\npm\node_modules\grunt-cli\bin\grunt --force \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..7690e0d --- /dev/null +++ b/package.json @@ -0,0 +1,47 @@ +{ + "name": "grunt-importer", + "description": "Importer adds an #import statement to JavaScript based languages including CoffeeScript that works like #include in C-based languages. It compiles files into JavaScript, concatenates them together in the places you've defined, and generates source maps.", + "version": "0.1.0", + "homepage": "https://github.com/colinbowern/grunt-importer", + "author": { + "name": "Colin Bowern", + "email": "colin@bowern.com", + "url": "http://colinbowern.com" + }, + "repository": { + "type": "git", + "url": "git://github.com/colinbowern/grunt-importer.git" + }, + "bugs": { + "url": "https://github.com/colinbowern/grunt-importer/issues" + }, + "licenses": [ + { + "type": "MIT", + "url": "https://github.com/colinbowern/grunt-importer/blob/master/LICENSE-MIT" + } + ], + "main": "Gruntfile.js", + "engines": { + "node": ">= 0.8.0" + }, + "scripts": { + "test": "grunt test" + }, + "devDependencies": { + "grunt-contrib-jshint": "~0.6.0", + "grunt-contrib-clean": "~0.4.0", + "grunt-contrib-nodeunit": "~0.2.0", + "grunt": "~0.4.1", + "grunt-contrib-copy": "~0.4.1" + }, + "peerDependencies": { + "grunt": "~0.4.1" + }, + "keywords": [ + "gruntplugin" + ], + "dependencies": { + "importer": "~0.7.0" + } +} diff --git a/tasks/importer.js b/tasks/importer.js new file mode 100644 index 0000000..c60a362 --- /dev/null +++ b/tasks/importer.js @@ -0,0 +1,77 @@ +/* + * grunt-importer + * https://github.com/colinbowern/grunt-importer + * + * Copyright (c) 2013 Colin Bowern + * Licensed under the MIT license. + */ + +'use strict'; + +module.exports = function (grunt) { + + var importer = require('importer'), + path = require('path'), + fs = require('fs'); + + grunt.registerMultiTask('importer', 'Importer adds an #import statement to JavaScript based languages including CoffeeScript that works like #include in C-based languages. It compiles files into JavaScript, concatenates them together in the places you have defined, and generates source maps.', function () { + var done = this.async(); + + if (this.files.length < 1) { + grunt.verbose.warn('No source files provided, nothing to do.'); + } + + grunt.util.async.forEachSeries(this.files, function (f, nextFileObj) { + var destination = f.dest; + + var files = f.src.filter(function (filepath) { + if (!grunt.file.exists(filepath)) { + grunt.log.warn('Source file "' + filepath + '" was not found.'); + return false; + } else { + return true; + } + }); + + if (files.length === 0) { + if (f.src.length < 1) { + grunt.log.warn('No source files found, nothing to do.'); + } + return nextFileObj(); + } + + grunt.util.async.concatSeries(files, function (file, next) { + grunt.log.writeln(file); + grunt.log.writeln(destination); + var destinationFile = destination || file; + + var pkg = importer.createPackage(file); + pkg.build(function(err, changed) { + if (!err && changed) { + var results = { + sourceFile: file, + destinationFile: destinationFile, + destinationSourceMapFile: pkg.sourceMap, + data: changed + }; + next(err, results); + } else { + nextFileObj(err); + } + }); + }, function (err, results) { + if (!results) { + grunt.log.warn('Destination not written because results were empty.'); + nextFileObj(); + } + for(var i = 0; i < results.length; i++) { + var result = results[i]; + + grunt.file.write(result.destinationFile, result.data.code); + grunt.log.writeln('File "' + result.destinationFile + '" created.'); + } + nextFileObj(); + }); + }, done); + }); +}; \ No newline at end of file diff --git a/test/expected/foo.js b/test/expected/foo.js new file mode 100644 index 0000000..0661383 --- /dev/null +++ b/test/expected/foo.js @@ -0,0 +1,6 @@ +(function() { + //fizz +})(); +(function() { + //buzz +})(); \ No newline at end of file diff --git a/test/expected/footoo.js b/test/expected/footoo.js new file mode 100644 index 0000000..0661383 --- /dev/null +++ b/test/expected/footoo.js @@ -0,0 +1,6 @@ +(function() { + //fizz +})(); +(function() { + //buzz +})(); \ No newline at end of file diff --git a/test/fixtures/bar/buzz.js b/test/fixtures/bar/buzz.js new file mode 100644 index 0000000..63176ff --- /dev/null +++ b/test/fixtures/bar/buzz.js @@ -0,0 +1,3 @@ +(function() { + //buzz +})(); \ No newline at end of file diff --git a/test/fixtures/bar/fizz.js b/test/fixtures/bar/fizz.js new file mode 100644 index 0000000..fb72da6 --- /dev/null +++ b/test/fixtures/bar/fizz.js @@ -0,0 +1,3 @@ +(function() { + //fizz +})(); \ No newline at end of file diff --git a/test/fixtures/foo.js b/test/fixtures/foo.js new file mode 100644 index 0000000..86b6186 --- /dev/null +++ b/test/fixtures/foo.js @@ -0,0 +1,2 @@ +//import "bar/fizz.js" +//import "bar/buzz.js" \ No newline at end of file diff --git a/test/fixtures/foo.template.js b/test/fixtures/foo.template.js new file mode 100644 index 0000000..86b6186 --- /dev/null +++ b/test/fixtures/foo.template.js @@ -0,0 +1,2 @@ +//import "bar/fizz.js" +//import "bar/buzz.js" \ No newline at end of file diff --git a/test/fixtures/footoo.js b/test/fixtures/footoo.js new file mode 100644 index 0000000..86b6186 --- /dev/null +++ b/test/fixtures/footoo.js @@ -0,0 +1,2 @@ +//import "bar/fizz.js" +//import "bar/buzz.js" \ No newline at end of file diff --git a/test/importer_test.js b/test/importer_test.js new file mode 100644 index 0000000..524af17 --- /dev/null +++ b/test/importer_test.js @@ -0,0 +1,56 @@ +'use strict'; + +var grunt = require('grunt'); + +exports.importer = { + replace_single_file: function (test) { + test.expect(1); + + var actualCode = grunt.file.read('tmp/replace_single_file/foo.js').replace(/(?:\r|\n)+/g, ""); + var expectedCode = grunt.file.read('test/expected/foo.js').replace(/(?:\r|\n)+/g, ""); + test.equal(actualCode, expectedCode, 'source file contents match expected results.'); + + test.done(); + }, + replace_multiple_files: function (test) { + test.expect(2); + + var actual, expected; + actual = grunt.file.read('tmp/replace_multiple_files/foo.js').replace(/(?:\r|\n)+/g, ""); + expected = grunt.file.read('test/expected/foo.js').replace(/(?:\r|\n)+/g, ""); + test.equal(actual, expected, 'source file contents match expected results.'); + + actual = grunt.file.read('tmp/replace_multiple_files/footoo.js').replace(/(?:\r|\n)+/g, ""); + expected = grunt.file.read('test/expected/footoo.js').replace(/(?:\r|\n)+/g, ""); + test.equal(actual, expected, 'source file contents match expected results.'); + + test.done(); + }, + rename_file: function (test) { + test.expect(1); + + var actualCode = grunt.file.read('tmp/rename_file/foo.js').replace(/(?:\r|\n)+/g, ""); + var expectedCode = grunt.file.read('test/expected/foo.js').replace(/(?:\r|\n)+/g, ""); + test.equal(actualCode, expectedCode, 'source file contents match expected results.'); + + test.done(); + }, + different_output_folder: function (test) { + test.expect(1); + + var actualCode = grunt.file.read('tmp/different_output_folder/foo.js').replace(/(?:\r|\n)+/g, ""); + var expectedCode = grunt.file.read('test/expected/foo.js').replace(/(?:\r|\n)+/g, ""); + test.equal(actualCode, expectedCode, 'source file contents match expected results.'); + + test.done(); + }, + different_output_folder_and_rename: function (test) { + test.expect(1); + + var actualCode = grunt.file.read('tmp/different_output_folder_and_rename/foo.js').replace(/(?:\r|\n)+/g, ""); + var expectedCode = grunt.file.read('test/expected/foo.js').replace(/(?:\r|\n)+/g, ""); + test.equal(actualCode, expectedCode, 'source file contents match expected results.'); + + test.done(); + } +};