Browse Source

grunt like wp

windhamdavid 10 years ago
parent
commit
bf3b7c2c97
2 changed files with 368 additions and 98 deletions
  1. 22 61
      .jshintrc
  2. 346 37
      Gruntfile.js

+ 22 - 61
.jshintrc

@@ -1,63 +1,24 @@
-// --------------------------------------------------------------------
-// WordPress JSHint Configuration
-// --------------------------------------------------------------------
 {
-    "bitwise"       : true,     // Prohibit bitwise operators (&, |, ^, etc.).
-    "curly"         : true,     // Require {} for every new block or scope.
-    "eqeqeq"        : true,     // Require triple equals i.e. `===`.
-    "forin"         : true,     // Tolerate `for in` loops without `hasOwnPrototype`.
-    "immed"         : true,     // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );`
-    "latedef"       : true,     // Prohibit variable use before definition.
-    "newcap"        : true,     // Require capitalization of all constructor functions e.g. `new F()`.
-    "noarg"         : true,     // Prohibit use of `arguments.caller` and `arguments.callee`.
-    "noempty"       : true,     // Prohibit use of empty blocks.
-    "nonew"         : true,     // Prohibit use of constructors for side-effects.
-    "plusplus"      : false,    // Prohibit use of `++` & `--`.
-    "regexp"        : false,    // Prohibit `.` and `[^...]` in regular expressions.
-    "undef"         : true,     // Require all non-global variables be declared before they are used.
-    "strict"        : true,     // Require `use strict` pragma in every file.
-    "trailing"      : true,     // Prohibit trailing whitespaces.
-    "asi"           : false,    // Tolerate Automatic Semicolon Insertion (no semicolons).
-    "boss"          : false,    // Tolerate assignments inside if, for & while. Usually conditions & loops are for comparison, not assignments.
-    "debug"         : false,    // Allow debugger statements e.g. browser breakpoints.
-    "eqnull"        : false,    // Tolerate use of `== null`.
-    "es5"           : false,    // Allow EcmaScript 5 syntax.
-    "esnext"        : false,    // Allow ES.next specific features such as `const` and `let`.
-    "evil"          : false,    // Tolerate use of `eval`.
-    "expr"          : false,    // Tolerate `ExpressionStatement` as Programs.
-    "funcscope"     : false,    // Tolerate declarations of variables inside of control structures while accessing them later from the outside.
-    "globalstrict"  : false,    // Allow global "use strict" (also enables 'strict').
-    "iterator"      : false,    // Allow usage of __iterator__ property.
-    "lastsemic"     : false,    // Tolerate missing semicolons when it is omitted for the last statement in a one-line block.
-    "laxbreak"      : false,    // Tolerate unsafe line breaks e.g. `return [\n] x` without semicolons.
-    "laxcomma"      : false,    // Suppress warnings about comma-first coding style.
-    "loopfunc"      : false,    // Allow functions to be defined within loops.
-    "multistr"      : false,    // Tolerate multi-line strings.
-    "onecase"       : false,    // Tolerate switches with just one case.
-    "proto"         : false,    // Tolerate __proto__ property. This property is deprecated.
-    "regexdash"     : false,    // Tolerate unescaped last dash i.e. `[-...]`.
-    "scripturl"     : false,    // Tolerate script-targeted URLs.
-    "smarttabs"     : false,    // Tolerate mixed tabs and spaces when the latter are used for alignmnent only.
-    "shadow"        : false,    // Allows re-define variables later in code e.g. `var x=1; x=2;`.
-    "sub"           : false,    // Tolerate all forms of subscript notation besides dot notation e.g. `dict['key']` instead of `dict.key`.
-    "supernew"      : true,     // Tolerate `new function () { ... };` and `new Object;`.
-    "validthis"     : false,    // Tolerate strict violations when the code is running in strict mode and you use this in a non-constructor function.
-    "browser"       : true,     // Standard browser globals e.g. `window`, `document`.
-    "couch"         : false,    // Enable globals exposed by CouchDB.
-    "devel"         : false,    // Allow development statements e.g. `console.log();`.
-    "dojo"          : false,    // Enable globals exposed by Dojo Toolkit.
-    "jquery"        : true,     // Enable globals exposed by jQuery JavaScript library.
-    "mootools"      : false,    // Enable globals exposed by MooTools JavaScript framework.
-    "node"          : false,    // Enable globals available when code is running inside of the NodeJS runtime environment.
-    "nonstandard"   : false,    // Define non-standard but widely adopted globals such as escape and unescape.
-    "prototypejs"   : false,    // Enable globals exposed by Prototype JavaScript framework.
-    "rhino"         : false,    // Enable globals available when your code is running inside of the Rhino runtime environment.
-    "wsh"           : false,    // Enable globals available when your code is running as a script for the Windows Script Host.
-    "nomen"         : false,    // Prohibit use of initial or trailing underbars in names.
-    "onevar"        : false,    // Allow only one `var` statement per function.
-    "passfail"      : false,    // Stop on first error.
-    "white"         : false,    // Check against strict whitespace and indentation rules.
-    "maxerr"        : 100,      // Maximum errors before stopping.
-    "predef"        : [],       // Extra globals.
-    "indent"        : 4         // Specify indentation spacing
+	"boss": true,
+	"curly": true,
+	"eqeqeq": true,
+	"eqnull": true,
+	"es3": true,
+	"expr": true,
+	"immed": true,
+	"noarg": true,
+	"onevar": true,
+	"quotmark": "single",
+	"trailing": true,
+	"undef": true,
+	"unused": true,
+
+	"browser": true,
+
+	"globals": {
+		"_": false,
+		"Backbone": false,
+		"jQuery": false,
+		"wp": false
+	}
 }

+ 346 - 37
Gruntfile.js

@@ -3,7 +3,33 @@ module.exports = function(grunt) {
 	var SOURCE_DIR = 'wp/';
 	var BUILD_DIR = 'build/';
 
+	// Load tasks.
+	require('matchdep').filterDev('grunt-*').forEach( grunt.loadNpmTasks );
+
+	// Project configuration.
 	grunt.initConfig({
+		autoprefixer: {
+			options: {
+				browsers: ['Android >= 2.1', 'Chrome >= 21', 'Explorer >= 7', 'Firefox >= 17', 'Opera >= 12.1', 'Safari >= 6.0']
+			},
+			core: {
+				expand: true,
+				cwd: SOURCE_DIR,
+				dest: SOURCE_DIR,
+				src: [
+					'wp-admin/css/*.css',
+					'wp-includes/css/*.css'
+				]
+			},
+			colors: {
+				expand: true,
+				cwd: BUILD_DIR,
+				dest: BUILD_DIR,
+				src: [
+					'wp-admin/css/colors/*/colors.css'
+				]
+			}
+		},
 		clean: {
 			all: [BUILD_DIR],
 			dynamic: {
@@ -12,22 +38,72 @@ module.exports = function(grunt) {
 				cwd: BUILD_DIR,
 				src: []
 			},
-			svn: [SOURCE_DIR]
+			tinymce: ['<%= concat.tinymce.dest %>'],
+			qunit: ['tests/qunit/compiled.html']
 		},
 		copy: {
-			all: {
+			files: {
+				files: [
+					{
+						dot: true,
+						expand: true,
+						cwd: SOURCE_DIR,
+						src: [
+							'**',
+							'!**/.{svn,git}/**', // Ignore version control directories.
+							// Ignore unminified versions of external libs we don't ship:
+							'!wp-includes/js/backbone.js',
+							'!wp-includes/js/underscore.js',
+							'!wp-includes/version.php' // Exclude version.php
+						],
+						dest: BUILD_DIR
+					},
+					{
+						src: 'wp-config-sample.php',
+						dest: BUILD_DIR
+					}
+				]
+			},
+			version: {
+				options: {
+					processContent: function( src ) {
+						return src.replace( /^(\$wp_version.+?)-src';/m, '$1\';' );
+					}
+				},
+				files: [
+					{
+						src: SOURCE_DIR + 'wp-includes/version.php',
+						dest: BUILD_DIR + 'wp-includes/version.php'
+					}
+				]
+			},
+			dynamic: {
 				dot: true,
 				expand: true,
 				cwd: SOURCE_DIR,
-				src: ['**','!**/.{svn,git}/**'], // Ignore version control directories.
-				dest: BUILD_DIR
-		  },
-		  dynamic: {
-				dot: true,
+				dest: BUILD_DIR,
+				src: []
+			},
+			qunit: {
+				src: 'tests/qunit/index.html',
+				dest: 'tests/qunit/compiled.html',
+				options: {
+					processContent: function( src ) {
+						return src.replace( /([^\.])*\.\.\/src/ig , '/../build' );
+					}
+				}
+			}
+		},
+		sass: {
+			colors: {
 				expand: true,
 				cwd: SOURCE_DIR,
 				dest: BUILD_DIR,
-				src: []
+				ext: '.css',
+				src: ['wp-admin/css/colors/*/colors.scss'],
+				options: {
+					outputStyle: 'expanded'
+				}
 			}
 		},
 		cssmin: {
@@ -42,12 +118,157 @@ module.exports = function(grunt) {
 					// Exceptions
 					'!wp-admin/css/farbtastic.css'
 				]
+			},
+			rtl: {
+				expand: true,
+				cwd: BUILD_DIR,
+				dest: BUILD_DIR,
+				ext: '.min.css',
+				src: [
+					'wp-admin/css/*-rtl.css',
+					'wp-includes/css/*-rtl.css'
+				]
+			},
+			colors: {
+				expand: true,
+				cwd: BUILD_DIR,
+				dest: BUILD_DIR,
+				ext: '.min.css',
+				src: [
+					'wp-admin/css/colors/*/*.css'
+				]
 			}
 		},
-		svn: {
+		cssjanus: {
 			core: {
-				repository: 'https://core.svn.wordpress.org/trunk/',
-				dest: SOURCE_DIR
+				options: {
+					swapLtrRtlInUrl: false
+				},
+				expand: true,
+				cwd: SOURCE_DIR,
+				dest: BUILD_DIR,
+				ext: '-rtl.css',
+				src: [
+					'wp-admin/css/*.css',
+					'wp-includes/css/*.css'
+				]
+			},
+			colors: {
+				options: {
+					processContent: function( src ) {
+						return src.replace( /([^/]+)\.css/gi, '$1-rtl.css' );
+					}
+				},
+				expand: true,
+				cwd: BUILD_DIR,
+				dest: BUILD_DIR,
+				ext: '-rtl.css',
+				src: [
+					'wp-admin/css/colors/*/colors.css'
+				]
+			},
+			dynamic: {
+				expand: true,
+				cwd: SOURCE_DIR,
+				dest: BUILD_DIR,
+				ext: '-rtl.css',
+				src: []
+			}
+		},
+		jshint: {
+			options: grunt.file.readJSON('.jshintrc'),
+			grunt: {
+				src: ['Gruntfile.js']
+			},
+			tests: {
+				src: [
+					'tests/qunit/**/*.js',
+					'!tests/qunit/vendor/qunit.js',
+					'!tests/qunit/editor/**'
+				],
+				options: grunt.file.readJSON('tests/qunit/.jshintrc')
+			},
+			themes: {
+				expand: true,
+				cwd: SOURCE_DIR + 'wp-content/themes',
+				src: [
+					'**/*.js',
+					'!twenty{eleven,twelve,thirteen}/**',
+					// Third party scripts
+					'!twentyfourteen/js/html5.js'
+				]
+			},
+			core: {
+				expand: true,
+				cwd: SOURCE_DIR,
+				src: [
+					'wp-admin/js/*.js',
+					'wp-includes/js/*.js',
+					// WordPress scripts inside directories
+					'wp-includes/js/jquery/jquery.table-hotkeys.js',
+					'wp-includes/js/mediaelement/wp-mediaelement.js',
+					'wp-includes/js/plupload/handlers.js',
+					'wp-includes/js/plupload/wp-plupload.js',
+					'wp-includes/js/tinymce/plugins/wordpress/plugin.js',
+					'wp-includes/js/tinymce/plugins/wp*/plugin.js',
+					// Third party scripts
+					'!wp-admin/js/farbtastic.js',
+					'!wp-admin/js/iris.min.js',
+					'!wp-includes/js/backbone*.js',
+					'!wp-includes/js/swfobject.js',
+					'!wp-includes/js/underscore*.js',
+					'!wp-includes/js/zxcvbn.min.js',
+					'!wp-includes/js/colorpicker.js',
+					'!wp-includes/js/hoverIntent.js',
+					'!wp-includes/js/json2.js',
+					'!wp-includes/js/tw-sack.js'
+				],
+				// Remove once other JSHint errors are resolved
+				options: {
+					curly: false,
+					eqeqeq: false
+				},
+				// Limit JSHint's run to a single specified file
+				//     grunt jshint:core --file=filename.js
+				filter: function( filepath ) {
+					var index, file = grunt.option( 'file' );
+
+					// Don't filter when no target file is specified
+					if ( ! file ) {
+						return true;
+					}
+
+					// Normalize filepath for Windows
+					filepath = filepath.replace( /\\/g, '/' );
+					index = filepath.lastIndexOf( '/' + file );
+
+					// Match only the filename passed from cli
+					if ( filepath === file || ( -1 !== index && index === filepath.length - ( file.length + 1 ) ) ) {
+						return true;
+					}
+
+					return false;
+				}
+			}
+		},
+		qunit: {
+			files: [
+				'tests/qunit/**/*.html',
+				'!tests/qunit/editor/**'
+			]
+		},
+		phpunit: {
+			'default': {
+				cmd: 'phpunit',
+				args: ['-c', 'phpunit.xml.dist']
+			},
+			ajax: {
+				cmd: 'phpunit',
+				args: ['-c', 'phpunit.xml.dist', '--group', 'ajax']
+			},
+			multisite: {
+				cmd: 'phpunit',
+				args: ['-c', 'tests/phpunit/multisite.xml']
 			}
 		},
 		uglify: {
@@ -61,30 +282,70 @@ module.exports = function(grunt) {
 					'wp-includes/js/*.js',
 					'wp-includes/js/plupload/handlers.js',
 					'wp-includes/js/plupload/wp-plupload.js',
-					'wp-includes/js/tinymce/plugins/wp*/js/*.js',
+					'wp-includes/js/tinymce/plugins/wordpress/plugin.js',
+					'wp-includes/js/tinymce/plugins/wp*/plugin.js',
+
 					// Exceptions
 					'!wp-admin/js/custom-header.js', // Why? We should minify this.
 					'!wp-admin/js/farbtastic.js',
 					'!wp-admin/js/iris.min.js',
 					'!wp-includes/js/backbone.min.js',
 					'!wp-includes/js/swfobject.js',
-					'!wp-includes/js/underscore.min.js'
+					'!wp-includes/js/underscore.min.js',
+					'!wp-includes/js/zxcvbn.min.js'
 				]
-			},
+			}
+		},
+		concat: {
+			tinymce: {
+				options: {
+					separator: '\n',
+					process: function( src, filepath ) {
+						return '// Source: ' + filepath.replace( BUILD_DIR, '' ) + '\n' + src;
+					}
+				},
+				src: [
+					BUILD_DIR + 'wp-includes/js/tinymce/tinymce.min.js',
+					BUILD_DIR + 'wp-includes/js/tinymce/themes/modern/theme.min.js',
+					BUILD_DIR + 'wp-includes/js/tinymce/plugins/*/plugin.min.js'
+				],
+				dest: BUILD_DIR + 'wp-includes/js/tinymce/wp-tinymce.js'
+			}
+		},
+		compress: {
 			tinymce: {
+				options: {
+					mode: 'gzip',
+					level: 9
+				},
+				src: '<%= concat.tinymce.dest %>',
+				dest: BUILD_DIR + 'wp-includes/js/tinymce/wp-tinymce.js.gz'
+			}
+		},
+		jsvalidate:{
+			options: {
+				globals: {},
+				esprimaOptions:{},
+				verbose: false
+			},
+			build: {
+				files: {
+					src: [
+						BUILD_DIR + '/**/*.js',
+						'!' + BUILD_DIR + '/wp-content/**/*.js'
+					]
+				}
+			}
+		},
+		imagemin: {
+			core: {
 				expand: true,
 				cwd: SOURCE_DIR,
-				dest: BUILD_DIR,
 				src: [
-					'wp-includes/js/tinymce/plugins/wordpress/editor_plugin_src.js',
-					'wp-includes/js/tinymce/plugins/wp*/editor_plugin_src.js'
+					'wp-{admin,includes}/images/**/*.{png,jpg,gif,jpeg}',
+					'wp-includes/js/tinymce/skins/wordpress/images/*.{png,jpg,gif,jpeg}'
 				],
-				// TinyMCE plugins use a nonstandard naming scheme: plugin files are named
-				// `editor_plugin_src.js`, and are compressed into `editor_plugin.js`.
-				rename: function(destBase, destPath) {
-					destPath = destPath.replace('/editor_plugin_src.js', '/editor_plugin.js');
-					return path.join(destBase || '', destPath);
-				}
+				dest: SOURCE_DIR
 			}
 		},
 		watch: {
@@ -100,21 +361,64 @@ module.exports = function(grunt) {
 					spawn: false,
 					interval: 2000
 				}
+			},
+			colors: {
+				files: [SOURCE_DIR + 'wp-admin/css/colors/**'],
+				tasks: ['sass:colors']
+			},
+			rtl: {
+				files: [
+					SOURCE_DIR + 'wp-admin/css/*.css',
+					SOURCE_DIR + 'wp-includes/css/*.css'
+				],
+				tasks: ['cssjanus:dynamic'],
+				options: {
+					spawn: false,
+					interval: 2000
+				}
+			},
+			test: {
+				files: [
+					'tests/qunit/**',
+					'!tests/qunit/editor/**'
+				],
+				tasks: ['qunit']
 			}
 		}
 	});
 
-	// Load tasks.
-	grunt.loadNpmTasks('grunt-contrib-clean');
-	grunt.loadNpmTasks('grunt-contrib-copy');
-	grunt.loadNpmTasks('grunt-contrib-cssmin');
-	grunt.loadNpmTasks('grunt-contrib-uglify');
-	grunt.loadNpmTasks('grunt-contrib-watch');
-
 	// Register tasks.
-	grunt.registerTask('build', ['clean:all', 'copy:all', 'cssmin:core',
-		'uglify:core', 'uglify:tinymce']);
 
+	// Copy task.
+	grunt.registerTask('copy:all', ['copy:files', 'copy:version']);
+
+	// RTL task.
+	grunt.registerTask('rtl', ['cssjanus:core', 'cssjanus:colors']);
+
+	// Color schemes task.
+	grunt.registerTask('colors', ['sass:colors', 'autoprefixer:colors']);
+
+	// Pre-commit task.
+	grunt.registerTask('precommit', 'Runs front-end dev/test tasks in preparation for a commit.',
+		['autoprefixer:core', 'imagemin:core', 'jshint', 'qunit:compiled']);
+
+	// Build task.
+	grunt.registerTask('build', ['clean:all', 'copy:all', 'cssmin:core', 'colors', 'rtl', 'cssmin:rtl', 'cssmin:colors',
+		'uglify:core', 'concat:tinymce', 'compress:tinymce', 'clean:tinymce', 'jsvalidate:build']);
+
+	// Testing tasks.
+	grunt.registerMultiTask('phpunit', 'Runs PHPUnit tests, including the ajax and multisite tests.', function() {
+		grunt.util.spawn({
+			cmd: this.data.cmd,
+			args: this.data.args,
+			opts: {stdio: 'inherit'}
+		}, this.async());
+	});
+
+	grunt.registerTask('qunit:compiled', 'Runs QUnit tests on compiled as well as uncompiled scripts.',
+		['build', 'copy:qunit', 'qunit']);
+
+	grunt.registerTask('test', 'Runs all QUnit and PHPUnit tasks.', ['qunit:compiled', 'phpunit']);
 
 	// Default task.
 	grunt.registerTask('default', ['build']);
@@ -123,13 +427,18 @@ module.exports = function(grunt) {
 	//
 	// On `watch:all`, automatically updates the `copy:dynamic` and `clean:dynamic`
 	// configurations so that only the changed files are updated.
-	grunt.event.on('watch', function(action, filepath, target) {
-		if (target != 'all') return;
+	// On `watch:rtl`, automatically updates the `cssjanus:dynamic` configuration.
+	grunt.event.on('watch', function( action, filepath, target ) {
+		if ( target !== 'all' && target !== 'rtl' ) {
+			return;
+		}
+
+		var relativePath = path.relative( SOURCE_DIR, filepath ),
+			cleanSrc = ( action === 'deleted' ) ? [relativePath] : [],
+			copySrc = ( action === 'deleted' ) ? [] : [relativePath];
 
-		var relativePath = path.relative(SOURCE_DIR, filepath);
-		var cleanSrc = (action == 'deleted') ? [relativePath] : [];
-		var copySrc = (action == 'deleted') ? [] : [relativePath];
 		grunt.config(['clean', 'dynamic', 'src'], cleanSrc);
 		grunt.config(['copy', 'dynamic', 'src'], copySrc);
+		grunt.config(['cssjanus', 'dynamic', 'src'], copySrc);
 	});
 };