1 module.exports = function( grunt ) {
10 readOptionalJSON = function( filepath ) {
13 data = grunt.file.readJSON( filepath );
19 pkg: grunt.file.readJSON("package.json"),
20 dst: readOptionalJSON("dist/.destination.json"),
26 "src/sizzle-jquery.js",
27 "src/sizzle/sizzle.js"
43 "src/manipulation.js",
45 { flag: "css", src: "src/css.js" },
47 { flag: "ajax", src: "src/ajax.js" },
48 { flag: "ajax/script", src: "src/ajax/script.js", needs: ["ajax"] },
49 { flag: "ajax/jsonp", src: "src/ajax/jsonp.js", needs: [ "ajax", "ajax/script" ] },
50 { flag: "ajax/xhr", src: "src/ajax/xhr.js", needs: ["ajax"] },
51 { flag: "effects", src: "src/effects.js", needs: ["css"] },
52 { flag: "offset", src: "src/offset.js", needs: ["css"] },
53 { flag: "dimensions", src: "src/dimensions.js", needs: ["css"] },
54 { flag: "deprecated", src: "src/deprecated.js" },
63 src: [ "dist/jquery.js" ],
65 jshintrc: "src/.jshintrc"
69 src: [ "Gruntfile.js" ],
75 // TODO: Once .jshintignore is supported, use that instead.
76 // issue located here: https://github.com/gruntjs/grunt-contrib-jshint/issues/1
77 src: [ "test/data/{test,testinit,testrunner}.js", "test/unit/**/*.js" ],
79 jshintrc: "test/.jshintrc"
85 tests: "ajax attributes callbacks core css data deferred dimensions effects event manipulation offset queue selector serialize support traversing Sizzle".split(" ")
89 files: [ "<%= jshint.grunt.src %>", "<%= jshint.tests.src %>", "src/**/*.js" ],
96 "dist/jquery.min.js": [ "dist/jquery.js" ]
99 banner: "/*! jQuery v<%= pkg.version %> jquery.com | jquery.org/license */",
100 sourceMap: "dist/jquery.min.map",
109 grunt.registerTask( "testswarm", function( commit, configFile ) {
111 testswarm = require( "testswarm" ),
113 pull = /PR-(\d+)/.exec( commit ),
114 config = grunt.file.readJSON( configFile ).jquery,
115 tests = grunt.config([ this.name, "tests" ]);
118 jobName = "jQuery pull <a href='https://github.com/jquery/jquery/pull/" +
119 pull[ 1 ] + "'>#" + pull[ 1 ] + "</a>";
121 jobName = "jQuery commit #<a href='https://github.com/jquery/jquery/commit/" +
122 commit + "'>" + commit.substr( 0, 10 ) + "</a>";
125 tests.forEach(function( test ) {
126 testUrls.push( config.testUrl + commit + "/test/index.html?module=" + test );
130 url: config.swarmUrl,
132 timeout: 1000 * 60 * 30,
135 authUsername: config.authUsername,
136 authToken: config.authToken,
138 runMax: config.runMax,
140 "runUrls[]": testUrls,
141 "browserSets[]": config.browserSets
145 // Build src/selector.js
146 grunt.registerMultiTask( "selector", "Build src/selector.js", function() {
148 var name = this.file.dest,
149 files = this.file.src,
151 api: grunt.file.read( files[0] ),
152 src: grunt.file.read( files[1] )
158 sizzle-jquery.js -> sizzle between "EXPOSE" blocks,
159 replace define & window.Sizzle assignment
163 if ( typeof define === "function" && define.amd ) {
164 define(function() { return Sizzle; });
166 window.Sizzle = Sizzle;
172 Sizzle.attr = jQuery.attr;
173 jQuery.find = Sizzle;
174 jQuery.expr = Sizzle.selectors;
175 jQuery.expr[":"] = jQuery.expr.pseudos;
176 jQuery.unique = Sizzle.uniqueSort;
177 jQuery.text = Sizzle.getText;
178 jQuery.isXMLDoc = Sizzle.isXML;
179 jQuery.contains = Sizzle.contains;
183 // Break into 3 pieces
184 parts = sizzle.src.split("// EXPOSE");
185 // Replace the if/else block with api
186 parts[1] = sizzle.api;
188 compiled = parts.join("");
190 grunt.verbose.write("Injected sizzle-jquery.js into sizzle.js");
192 // Write concatenated source to file
193 grunt.file.write( name, compiled );
195 // Fail task if errors were logged.
196 if ( this.errorCount ) {
200 // Otherwise, print a success message.
201 grunt.log.writeln( "File '" + name + "' created." );
205 // Special "alias" task to make custom build creation less grawlix-y
206 grunt.registerTask( "custom", function() {
207 var done = this.async(),
208 args = [].slice.call(arguments),
209 modules = args.length ? args[0].replace(/,/g, ":") : "";
212 // Translation example
214 // grunt custom:+ajax,-dimensions,-effects,-offset
218 // grunt build:*:*:+ajax:-dimensions:-effects:-offset
220 grunt.log.writeln( "Creating custom build...\n" );
223 cmd: process.platform === "win32" ? "grunt.cmd" : "grunt",
224 args: [ "build:*:*:" + modules, "uglify", "dist" ]
225 }, function( err, result ) {
227 grunt.verbose.error();
232 grunt.log.writeln( result.stdout.replace("Done, without errors.", "") );
238 // Special concat/build task to handle various jQuery build requirements
240 grunt.registerMultiTask(
242 "Concatenate source (include/exclude modules with +/- flags), embed date/version",
244 // Concat specified files.
246 modules = this.flags,
247 optIn = !modules["*"],
248 explicit = optIn || Object.keys(modules).length > 1,
249 name = this.file.dest,
250 src = this.file.srcRaw,
253 version = grunt.config( "pkg.version" ),
254 excluder = function( flag, needsFlag ) {
255 // optIn defaults implicit behavior to weak exclusion
256 if ( optIn && !modules[ flag ] && !modules[ "+" + flag ] ) {
257 excluded[ flag ] = false;
260 // explicit or inherited strong exclusion
261 if ( excluded[ needsFlag ] || modules[ "-" + flag ] ) {
262 excluded[ flag ] = true;
264 // explicit inclusion overrides weak exclusion
265 } else if ( excluded[ needsFlag ] === false &&
266 ( modules[ flag ] || modules[ "+" + flag ] ) ) {
268 delete excluded[ needsFlag ];
270 // ...all the way down
271 if ( deps[ needsFlag ] ) {
272 deps[ needsFlag ].forEach(function( subDep ) {
273 modules[ needsFlag ] = true;
274 excluder( needsFlag, subDep );
280 // append commit id to version
281 if ( process.env.COMMIT ) {
282 version += " " + process.env.COMMIT;
285 // figure out which files to exclude based on these rules in this order:
286 // dependency explicit exclude
287 // > explicit exclude
288 // > explicit include
289 // > dependency implicit exclude
290 // > implicit exclude
292 // * none (implicit exclude)
293 // *:* all (implicit include)
294 // *:*:-css all except css and dependents (explicit > implicit)
295 // *:*:-css:+effects same (excludes effects because explicit include is trumped by explicit exclude of dependency)
296 // *:+effects none except effects and its dependencies (explicit include trumps implicit exclude of dependency)
297 src.forEach(function( filepath ) {
298 var flag = filepath.flag;
304 // check for dependencies
305 if ( filepath.needs ) {
306 deps[ flag ] = filepath.needs;
307 filepath.needs.forEach(function( needsFlag ) {
308 excluder( flag, needsFlag );
314 // append excluded modules to version
315 if ( Object.keys( excluded ).length ) {
316 version += " -" + Object.keys( excluded ).join( ",-" );
317 // set pkg.version to version with excludes, so minified file picks it up
318 grunt.config.set( "pkg.version", version );
322 // conditionally concatenate source
323 src.forEach(function( filepath ) {
324 var flag = filepath.flag,
330 if ( excluded[ flag ] !== undefined ) {
331 message = ( "Excluding " + flag ).red;
335 message = ( "Including " + flag ).green;
337 // If this module was actually specified by the
338 // builder, then st the flag to include it in the
340 if ( modules[ "+" + flag ] ) {
345 // Only display the inclusion/exclusion list when handling
348 // Additionally, only display modules that have been specified
350 if ( explicit && specified ) {
351 grunt.log.writetableln([ 27, 30 ], [
353 ( "(" + filepath.src + ")").grey
357 filepath = filepath.src;
361 compiled += grunt.file.read( filepath );
367 compiled = compiled.replace( /@VERSION/g, version )
368 .replace( "@DATE", function () {
369 var date = new Date();
379 // Write concatenated source to file
380 grunt.file.write( name, compiled );
382 // Fail task if errors were logged.
383 if ( this.errorCount ) {
387 // Otherwise, print a success message.
388 grunt.log.writeln( "File '" + name + "' created." );
391 // Process files for distribution
392 grunt.registerTask( "dist", function() {
393 var flags, paths, stored;
395 // Check for stored destination paths
396 // ( set in dist/.destination.json )
397 stored = Object.keys( grunt.config("dst") );
399 // Allow command line input as well
400 flags = Object.keys( this.flags );
402 // Combine all output target paths
403 paths = [].concat( stored, flags ).filter(function( path ) {
407 // Ensure the dist files are pure ASCII
408 var fs = require("fs"),
411 distpaths.forEach(function( filename ) {
412 var text = fs.readFileSync( filename, "utf8" ),
414 if ( text.length !== Buffer.byteLength( text, "utf8" ) ) {
415 grunt.log.writeln( filename + ": Non-ASCII characters detected:" );
416 for ( i = 0; i < text.length; i++ ) {
417 c = text.charCodeAt( i );
419 grunt.log.writeln( "- position " + i + ": " + c );
420 grunt.log.writeln( "-- " + text.substring( i - 20, i + 20 ) );
427 // Modify map so that it points to files in the same folder;
428 // see https://github.com/mishoo/UglifyJS2/issues/47
429 if ( /\.map$/.test( filename ) ) {
430 text = text.replace( /"dist\//g, "\"" );
431 fs.writeFileSync( filename, text, "utf-8" );
434 // Optionally copy dist files to other locations
435 paths.forEach(function( path ) {
438 if ( !/\/$/.test( path ) ) {
442 created = path + filename.replace( "dist/", "" );
443 grunt.file.write( created, text );
444 grunt.log.writeln( "File '" + created + "' created." );
451 // Load grunt tasks from NPM packages
452 grunt.loadNpmTasks("grunt-compare-size");
453 grunt.loadNpmTasks("grunt-git-authors");
454 grunt.loadNpmTasks("grunt-update-submodules");
455 grunt.loadNpmTasks("grunt-contrib-watch");
456 grunt.loadNpmTasks("grunt-contrib-jshint");
457 grunt.loadNpmTasks("grunt-contrib-uglify");
460 grunt.registerTask( "default", [ "update_submodules", "selector", "build:*:*", "jshint", "uglify", "dist:*", "compare_size" ] );
462 // Short list as a high frequency watch task
463 grunt.registerTask( "dev", [ "selector", "build:*:*", "jshint" ] );