d3e0b4bc16
This was previously attempted in [41043], which unfortunately had severe performance issues, the regex it used was fatally slow on long posts. This version now uses an array of all emoji that Twemoji supports, which maintains the accuracy of [41043], while being the same speed or only a few ms slower than the code prior to [41043]. As with [41043], the `grunt precommit:emoji` task detects when `twemoji.js` has changed, and regenerates the array. Props jmdodd for feedback, suggestions, and insults where appropriate. Fixes #35293. 🤞🏻 git-svn-id: https://develop.svn.wordpress.org/trunk@41701 602fd350-edb4-49c9-b593-d223f7449a82
986 lines
24 KiB
JavaScript
986 lines
24 KiB
JavaScript
/* jshint node:true */
|
|
/* globals Set */
|
|
module.exports = function(grunt) {
|
|
var path = require('path'),
|
|
fs = require( 'fs' ),
|
|
spawn = require( 'child_process' ).spawnSync,
|
|
SOURCE_DIR = 'src/',
|
|
BUILD_DIR = 'build/',
|
|
BANNER_TEXT = '/*! This file is auto-generated */',
|
|
autoprefixer = require('autoprefixer'),
|
|
mediaConfig = {},
|
|
mediaBuilds = ['audiovideo', 'grid', 'models', 'views'];
|
|
|
|
// Load tasks.
|
|
require('matchdep').filterDev(['grunt-*', '!grunt-legacy-util']).forEach( grunt.loadNpmTasks );
|
|
// Load legacy utils
|
|
grunt.util = require('grunt-legacy-util');
|
|
|
|
mediaBuilds.forEach( function ( build ) {
|
|
var path = SOURCE_DIR + 'wp-includes/js/media';
|
|
mediaConfig[ build ] = { files : {} };
|
|
mediaConfig[ build ].files[ path + '-' + build + '.js' ] = [ path + '/' + build + '.manifest.js' ];
|
|
} );
|
|
|
|
// Project configuration.
|
|
grunt.initConfig({
|
|
postcss: {
|
|
options: {
|
|
processors: [
|
|
autoprefixer({
|
|
browsers: [
|
|
'> 1%',
|
|
'ie >= 11',
|
|
'last 1 Android versions',
|
|
'last 1 ChromeAndroid versions',
|
|
'last 2 Chrome versions',
|
|
'last 2 Firefox versions',
|
|
'last 2 Safari versions',
|
|
'last 2 iOS versions',
|
|
'last 2 Edge versions',
|
|
'last 2 Opera versions'
|
|
],
|
|
cascade: false
|
|
})
|
|
]
|
|
},
|
|
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'
|
|
]
|
|
}
|
|
},
|
|
usebanner: {
|
|
options: {
|
|
position: 'top',
|
|
banner: BANNER_TEXT,
|
|
linebreak: true
|
|
},
|
|
files: {
|
|
src: [
|
|
BUILD_DIR + 'wp-admin/css/*.min.css',
|
|
BUILD_DIR + 'wp-includes/css/*.min.css',
|
|
BUILD_DIR + 'wp-admin/css/colors/*/*.css'
|
|
]
|
|
}
|
|
},
|
|
clean: {
|
|
all: [BUILD_DIR],
|
|
dynamic: {
|
|
dot: true,
|
|
expand: true,
|
|
cwd: BUILD_DIR,
|
|
src: []
|
|
},
|
|
tinymce: ['<%= concat.tinymce.dest %>'],
|
|
qunit: ['tests/qunit/compiled.html']
|
|
},
|
|
copy: {
|
|
files: {
|
|
files: [
|
|
{
|
|
dot: true,
|
|
expand: true,
|
|
cwd: SOURCE_DIR,
|
|
src: [
|
|
'**',
|
|
'!wp-includes/js/media/**',
|
|
'!**/.{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/js/jquery/jquery.masonry.js',
|
|
'!wp-includes/js/jquery/ui/*.js',
|
|
'!wp-includes/js/tinymce/tinymce.js',
|
|
'!wp-includes/version.php' // Exclude version.php
|
|
],
|
|
dest: BUILD_DIR
|
|
},
|
|
{
|
|
src: 'wp-config-sample.php',
|
|
dest: BUILD_DIR
|
|
}
|
|
]
|
|
},
|
|
'wp-admin-css-compat-rtl': {
|
|
options: {
|
|
processContent: function( src ) {
|
|
return src.replace( /\.css/g, '-rtl.css' );
|
|
}
|
|
},
|
|
src: SOURCE_DIR + 'wp-admin/css/wp-admin.css',
|
|
dest: BUILD_DIR + 'wp-admin/css/wp-admin-rtl.css'
|
|
},
|
|
'wp-admin-css-compat-min': {
|
|
options: {
|
|
processContent: function( src ) {
|
|
return src.replace( /\.css/g, '.min.css' );
|
|
}
|
|
},
|
|
files: [
|
|
{
|
|
src: SOURCE_DIR + 'wp-admin/css/wp-admin.css',
|
|
dest: BUILD_DIR + 'wp-admin/css/wp-admin.min.css'
|
|
},
|
|
{
|
|
src: BUILD_DIR + 'wp-admin/css/wp-admin-rtl.css',
|
|
dest: BUILD_DIR + 'wp-admin/css/wp-admin-rtl.min.css'
|
|
}
|
|
]
|
|
},
|
|
version: {
|
|
options: {
|
|
processContent: function( src ) {
|
|
return src.replace( /^\$wp_version = '(.+?)';/m, function( str, version ) {
|
|
version = version.replace( /-src$/, '' );
|
|
|
|
// If the version includes an SVN commit (-12345), it's not a released alpha/beta. Append a timestamp.
|
|
version = version.replace( /-[\d]{5}$/, '-' + grunt.template.today( 'yyyymmdd.HHMMss' ) );
|
|
|
|
/* jshint quotmark: true */
|
|
return "$wp_version = '" + version + "';";
|
|
});
|
|
}
|
|
},
|
|
src: SOURCE_DIR + 'wp-includes/version.php',
|
|
dest: BUILD_DIR + 'wp-includes/version.php'
|
|
},
|
|
dynamic: {
|
|
dot: true,
|
|
expand: true,
|
|
cwd: SOURCE_DIR,
|
|
dest: BUILD_DIR,
|
|
src: []
|
|
},
|
|
qunit: {
|
|
src: 'tests/qunit/index.html',
|
|
dest: 'tests/qunit/compiled.html',
|
|
options: {
|
|
processContent: function( src ) {
|
|
return src.replace( /(\".+?\/)src(\/.+?)(?:.min)?(.js\")/g , function( match, $1, $2, $3 ) {
|
|
// Don't add `.min` to files that don't have it.
|
|
return $1 + 'build' + $2 + ( /jquery$/.test( $2 ) ? '' : '.min' ) + $3;
|
|
} );
|
|
}
|
|
}
|
|
}
|
|
},
|
|
browserify: mediaConfig,
|
|
sass: {
|
|
colors: {
|
|
expand: true,
|
|
cwd: SOURCE_DIR,
|
|
dest: BUILD_DIR,
|
|
ext: '.css',
|
|
src: ['wp-admin/css/colors/*/colors.scss'],
|
|
options: {
|
|
outputStyle: 'expanded'
|
|
}
|
|
}
|
|
},
|
|
cssmin: {
|
|
options: {
|
|
compatibility: 'ie7'
|
|
},
|
|
core: {
|
|
expand: true,
|
|
cwd: SOURCE_DIR,
|
|
dest: BUILD_DIR,
|
|
ext: '.min.css',
|
|
src: [
|
|
'wp-admin/css/*.css',
|
|
'!wp-admin/css/wp-admin*.css',
|
|
'wp-includes/css/*.css',
|
|
'wp-includes/js/mediaelement/wp-mediaelement.css'
|
|
]
|
|
},
|
|
rtl: {
|
|
expand: true,
|
|
cwd: BUILD_DIR,
|
|
dest: BUILD_DIR,
|
|
ext: '.min.css',
|
|
src: [
|
|
'wp-admin/css/*-rtl.css',
|
|
'!wp-admin/css/wp-admin*.css',
|
|
'wp-includes/css/*-rtl.css'
|
|
]
|
|
},
|
|
colors: {
|
|
expand: true,
|
|
cwd: BUILD_DIR,
|
|
dest: BUILD_DIR,
|
|
ext: '.min.css',
|
|
src: [
|
|
'wp-admin/css/colors/*/*.css'
|
|
]
|
|
}
|
|
},
|
|
rtlcss: {
|
|
options: {
|
|
// rtlcss options
|
|
opts: {
|
|
clean: false,
|
|
processUrls: { atrule: true, decl: false },
|
|
stringMap: [
|
|
{
|
|
name: 'import-rtl-stylesheet',
|
|
priority: 10,
|
|
exclusive: true,
|
|
search: [ '.css' ],
|
|
replace: [ '-rtl.css' ],
|
|
options: {
|
|
scope: 'url',
|
|
ignoreCase: false
|
|
}
|
|
}
|
|
]
|
|
},
|
|
saveUnmodified: false,
|
|
plugins: [
|
|
{
|
|
name: 'swap-dashicons-left-right-arrows',
|
|
priority: 10,
|
|
directives: {
|
|
control: {},
|
|
value: []
|
|
},
|
|
processors: [
|
|
{
|
|
expr: /content/im,
|
|
action: function( prop, value ) {
|
|
if ( value === '"\\f141"' ) { // dashicons-arrow-left
|
|
value = '"\\f139"';
|
|
} else if ( value === '"\\f340"' ) { // dashicons-arrow-left-alt
|
|
value = '"\\f344"';
|
|
} else if ( value === '"\\f341"' ) { // dashicons-arrow-left-alt2
|
|
value = '"\\f345"';
|
|
} else if ( value === '"\\f139"' ) { // dashicons-arrow-right
|
|
value = '"\\f141"';
|
|
} else if ( value === '"\\f344"' ) { // dashicons-arrow-right-alt
|
|
value = '"\\f340"';
|
|
} else if ( value === '"\\f345"' ) { // dashicons-arrow-right-alt2
|
|
value = '"\\f341"';
|
|
}
|
|
return { prop: prop, value: value };
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
core: {
|
|
expand: true,
|
|
cwd: SOURCE_DIR,
|
|
dest: BUILD_DIR,
|
|
ext: '-rtl.css',
|
|
src: [
|
|
'wp-admin/css/*.css',
|
|
'wp-includes/css/*.css',
|
|
|
|
// Exceptions
|
|
'!wp-includes/css/dashicons.css',
|
|
'!wp-includes/css/wp-embed-template.css',
|
|
'!wp-includes/css/wp-embed-template-ie.css'
|
|
]
|
|
},
|
|
colors: {
|
|
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/*',
|
|
'!tests/qunit/editor/**'
|
|
],
|
|
options: grunt.file.readJSON('tests/qunit/.jshintrc')
|
|
},
|
|
themes: {
|
|
expand: true,
|
|
cwd: SOURCE_DIR + 'wp-content/themes',
|
|
src: [
|
|
'twenty*/**/*.js',
|
|
'!twenty{eleven,twelve,thirteen}/**',
|
|
// Third party scripts
|
|
'!twenty{fourteen,fifteen,sixteen}/js/html5.js',
|
|
'!twentyseventeen/assets/js/html5.js',
|
|
'!twentyseventeen/assets/js/jquery.scrollTo.js'
|
|
]
|
|
},
|
|
media: {
|
|
options: {
|
|
browserify: true
|
|
},
|
|
src: [
|
|
SOURCE_DIR + 'wp-includes/js/media/**/*.js'
|
|
]
|
|
},
|
|
core: {
|
|
expand: true,
|
|
cwd: SOURCE_DIR,
|
|
src: [
|
|
'wp-admin/js/**/*.js',
|
|
'wp-includes/js/*.js',
|
|
// Built scripts.
|
|
'!wp-includes/js/media-*',
|
|
// WordPress scripts inside directories
|
|
'wp-includes/js/jquery/jquery.table-hotkeys.js',
|
|
'wp-includes/js/mediaelement/wp-mediaelement.js',
|
|
'wp-includes/js/mediaelement/wp-playlist.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-includes/js/codemirror/*.js',
|
|
'!wp-admin/js/farbtastic.js',
|
|
'!wp-includes/js/backbone*.js',
|
|
'!wp-includes/js/swfobject.js',
|
|
'!wp-includes/js/underscore*.js',
|
|
'!wp-includes/js/colorpicker.js',
|
|
'!wp-includes/js/hoverIntent.js',
|
|
'!wp-includes/js/json2.js',
|
|
'!wp-includes/js/tw-sack.js',
|
|
'!wp-includes/js/twemoji.js',
|
|
'!**/*.min.js',
|
|
'!wp-includes/js/wp-hooks.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
|
|
//
|
|
// Optionally, include the file path:
|
|
//
|
|
// grunt jshint:core --file=path/to/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;
|
|
}
|
|
},
|
|
plugins: {
|
|
expand: true,
|
|
cwd: SOURCE_DIR + 'wp-content/plugins',
|
|
src: [
|
|
'**/*.js',
|
|
'!**/*.min.js'
|
|
],
|
|
// Limit JSHint's run to a single specified plugin directory:
|
|
//
|
|
// grunt jshint:plugins --dir=foldername
|
|
//
|
|
filter: function( dirpath ) {
|
|
var index, dir = grunt.option( 'dir' );
|
|
|
|
// Don't filter when no target folder is specified
|
|
if ( ! dir ) {
|
|
return true;
|
|
}
|
|
|
|
dirpath = dirpath.replace( /\\/g, '/' );
|
|
index = dirpath.lastIndexOf( '/' + dir );
|
|
|
|
// Match only the folder name passed from cli
|
|
if ( -1 !== index ) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
},
|
|
jsdoc : {
|
|
dist : {
|
|
dest: 'jsdoc',
|
|
options: {
|
|
configure : 'jsdoc.conf.json'
|
|
}
|
|
}
|
|
},
|
|
qunit: {
|
|
files: [
|
|
'tests/qunit/**/*.html',
|
|
'!tests/qunit/editor/**'
|
|
]
|
|
},
|
|
phpunit: {
|
|
'default': {
|
|
cmd: 'phpunit',
|
|
args: ['--verbose', '-c', 'phpunit.xml.dist']
|
|
},
|
|
ajax: {
|
|
cmd: 'phpunit',
|
|
args: ['--verbose', '-c', 'phpunit.xml.dist', '--group', 'ajax']
|
|
},
|
|
multisite: {
|
|
cmd: 'phpunit',
|
|
args: ['--verbose', '-c', 'tests/phpunit/multisite.xml']
|
|
},
|
|
'ms-files': {
|
|
cmd: 'phpunit',
|
|
args: ['--verbose', '-c', 'tests/phpunit/multisite.xml', '--group', 'ms-files']
|
|
},
|
|
'external-http': {
|
|
cmd: 'phpunit',
|
|
args: ['--verbose', '-c', 'phpunit.xml.dist', '--group', 'external-http']
|
|
},
|
|
'restapi-jsclient': {
|
|
cmd: 'phpunit',
|
|
args: ['--verbose', '-c', 'phpunit.xml.dist', '--group', 'restapi-jsclient']
|
|
}
|
|
},
|
|
uglify: {
|
|
options: {
|
|
ASCIIOnly: true,
|
|
screwIE8: false
|
|
},
|
|
core: {
|
|
expand: true,
|
|
cwd: SOURCE_DIR,
|
|
dest: BUILD_DIR,
|
|
ext: '.min.js',
|
|
src: [
|
|
'wp-admin/js/**/*.js',
|
|
'wp-includes/js/*.js',
|
|
'wp-includes/js/plupload/*.js',
|
|
'wp-includes/js/mediaelement/wp-mediaelement.js',
|
|
'wp-includes/js/mediaelement/wp-playlist.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.*',
|
|
'!wp-includes/js/masonry.min.js',
|
|
'!wp-includes/js/swfobject.js',
|
|
'!wp-includes/js/underscore.*',
|
|
'!wp-includes/js/zxcvbn.min.js',
|
|
'!wp-includes/js/wp-embed.js' // We have extra options for this, see uglify:embed
|
|
]
|
|
},
|
|
embed: {
|
|
options: {
|
|
compress: {
|
|
conditionals: false
|
|
}
|
|
},
|
|
expand: true,
|
|
cwd: SOURCE_DIR,
|
|
dest: BUILD_DIR,
|
|
ext: '.min.js',
|
|
src: ['wp-includes/js/wp-embed.js']
|
|
},
|
|
media: {
|
|
expand: true,
|
|
cwd: SOURCE_DIR,
|
|
dest: BUILD_DIR,
|
|
ext: '.min.js',
|
|
src: [
|
|
'wp-includes/js/media-audiovideo.js',
|
|
'wp-includes/js/media-grid.js',
|
|
'wp-includes/js/media-models.js',
|
|
'wp-includes/js/media-views.js'
|
|
]
|
|
},
|
|
jqueryui: {
|
|
options: {
|
|
// Preserve comments that start with a bang.
|
|
preserveComments: /^!/
|
|
},
|
|
expand: true,
|
|
cwd: SOURCE_DIR,
|
|
dest: BUILD_DIR,
|
|
ext: '.min.js',
|
|
src: ['wp-includes/js/jquery/ui/*.js']
|
|
},
|
|
masonry: {
|
|
options: {
|
|
// Preserve comments that start with a bang.
|
|
preserveComments: /^!/
|
|
},
|
|
src: SOURCE_DIR + 'wp-includes/js/jquery/jquery.masonry.js',
|
|
dest: SOURCE_DIR + 'wp-includes/js/jquery/jquery.masonry.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'
|
|
},
|
|
emoji: {
|
|
options: {
|
|
separator: '\n',
|
|
process: function( src, filepath ) {
|
|
return '// Source: ' + filepath.replace( BUILD_DIR, '' ) + '\n' + src;
|
|
}
|
|
},
|
|
src: [
|
|
BUILD_DIR + 'wp-includes/js/twemoji.min.js',
|
|
BUILD_DIR + 'wp-includes/js/wp-emoji.min.js'
|
|
],
|
|
dest: BUILD_DIR + 'wp-includes/js/wp-emoji-release.min.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 + 'wp-{admin,includes}/**/*.js',
|
|
BUILD_DIR + 'wp-content/themes/twenty*/**/*.js'
|
|
]
|
|
}
|
|
}
|
|
},
|
|
imagemin: {
|
|
core: {
|
|
expand: true,
|
|
cwd: SOURCE_DIR,
|
|
src: [
|
|
'wp-{admin,includes}/images/**/*.{png,jpg,gif,jpeg}',
|
|
'wp-includes/js/tinymce/skins/wordpress/images/*.{png,jpg,gif,jpeg}'
|
|
],
|
|
dest: SOURCE_DIR
|
|
}
|
|
},
|
|
includes: {
|
|
emoji: {
|
|
src: BUILD_DIR + 'wp-includes/formatting.php',
|
|
dest: '.'
|
|
},
|
|
embed: {
|
|
src: BUILD_DIR + 'wp-includes/embed.php',
|
|
dest: '.'
|
|
}
|
|
},
|
|
replace: {
|
|
emojiRegex: {
|
|
options: {
|
|
patterns: [
|
|
{
|
|
match: /\/\/ START: emoji arrays[\S\s]*\/\/ END: emoji arrays/g,
|
|
replacement: function () {
|
|
var regex, files,
|
|
partials, partialsSet,
|
|
entities, emojiArray;
|
|
|
|
grunt.log.writeln( 'Fetching list of Twemoji files...' );
|
|
|
|
// Fetch a list of the files that Twemoji supplies
|
|
files = spawn( 'svn', [ 'ls', 'https://github.com/twitter/twemoji.git/branches/gh-pages/2/assets' ] );
|
|
if ( 0 !== files.status ) {
|
|
grunt.fatal( 'Unable to fetch Twemoji file list' );
|
|
}
|
|
|
|
entities = files.stdout.toString();
|
|
|
|
// Tidy up the file list
|
|
entities = entities.replace( /\.ai/g, '' );
|
|
entities = entities.replace( /^$/g, '' );
|
|
|
|
// Convert the emoji entities to HTML entities
|
|
partials = entities = entities.replace( /([a-z0-9]+)/g, '&#x$1;' );
|
|
|
|
// Remove the hyphens between the HTML entities
|
|
entities = entities.replace( /-/g, '' );
|
|
|
|
// Sort the entities list by length, so the longest emoji will be found first
|
|
emojiArray = entities.split( '\n' ).sort( function ( a, b ) {
|
|
return b.length - a.length;
|
|
} );
|
|
|
|
// Convert the entities list to PHP array syntax
|
|
entities = '\'' + emojiArray.filter( function( val ) {
|
|
return val.length >= 8 ? val : false ;
|
|
} ).join( '\',\'' ) + '\'';
|
|
|
|
// Create a list of all characters used by the emoji list
|
|
partials = partials.replace( /-/g, '\n' );
|
|
|
|
// Set automatically removes duplicates
|
|
partialsSet = new Set( partials.split( '\n' ) );
|
|
|
|
// Convert the partials list to PHP array syntax
|
|
partials = '\'' + Array.from( partialsSet ).filter( function( val ) {
|
|
return val.length >= 8 ? val : false ;
|
|
} ).join( '\',\'' ) + '\'';
|
|
|
|
regex = '// START: emoji arrays\n';
|
|
regex += '\t$entities = array(' + entities + ');\n';
|
|
regex += '\t$partials = array(' + partials + ');\n';
|
|
regex += '\t// END: emoji arrays';
|
|
|
|
return regex;
|
|
}
|
|
}
|
|
]
|
|
},
|
|
files: [
|
|
{
|
|
expand: true,
|
|
flatten: true,
|
|
src: [
|
|
SOURCE_DIR + 'wp-includes/formatting.php'
|
|
],
|
|
dest: SOURCE_DIR + 'wp-includes/'
|
|
}
|
|
]
|
|
}
|
|
},
|
|
_watch: {
|
|
all: {
|
|
files: [
|
|
SOURCE_DIR + '**',
|
|
'!' + SOURCE_DIR + 'wp-includes/js/media/**',
|
|
// Ignore version control directories.
|
|
'!' + SOURCE_DIR + '**/.{svn,git}/**'
|
|
],
|
|
tasks: ['clean:dynamic', 'copy:dynamic'],
|
|
options: {
|
|
dot: true,
|
|
spawn: false,
|
|
interval: 2000
|
|
}
|
|
},
|
|
config: {
|
|
files: 'Gruntfile.js'
|
|
},
|
|
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: ['rtlcss:dynamic'],
|
|
options: {
|
|
spawn: false,
|
|
interval: 2000
|
|
}
|
|
},
|
|
test: {
|
|
files: [
|
|
'tests/qunit/**',
|
|
'!tests/qunit/editor/**'
|
|
],
|
|
tasks: ['qunit']
|
|
}
|
|
}
|
|
});
|
|
|
|
// Allow builds to be minimal
|
|
if( grunt.option( 'minimal-copy' ) ) {
|
|
var copyFilesOptions = grunt.config.get( 'copy.files.files' );
|
|
copyFilesOptions[0].src.push( '!wp-content/plugins/**' );
|
|
copyFilesOptions[0].src.push( '!wp-content/themes/!(twenty*)/**' );
|
|
grunt.config.set( 'copy.files.files', copyFilesOptions );
|
|
}
|
|
|
|
|
|
// Register tasks.
|
|
|
|
// RTL task.
|
|
grunt.registerTask('rtl', ['rtlcss:core', 'rtlcss:colors']);
|
|
|
|
// Color schemes task.
|
|
grunt.registerTask('colors', ['sass:colors', 'postcss:colors']);
|
|
|
|
// JSHint task.
|
|
grunt.registerTask( 'jshint:corejs', [
|
|
'jshint:grunt',
|
|
'jshint:tests',
|
|
'jshint:themes',
|
|
'jshint:core',
|
|
'jshint:media'
|
|
] );
|
|
|
|
grunt.registerTask( 'restapi-jsclient', [
|
|
'phpunit:restapi-jsclient',
|
|
'qunit:compiled'
|
|
] );
|
|
|
|
grunt.renameTask( 'watch', '_watch' );
|
|
|
|
grunt.registerTask( 'watch', function() {
|
|
if ( ! this.args.length || this.args.indexOf( 'browserify' ) > -1 ) {
|
|
grunt.config( 'browserify.options', {
|
|
browserifyOptions: {
|
|
debug: true
|
|
},
|
|
watch: true
|
|
} );
|
|
|
|
grunt.task.run( 'browserify' );
|
|
}
|
|
|
|
grunt.task.run( '_' + this.nameArgs );
|
|
} );
|
|
|
|
grunt.registerTask( 'precommit:image', [
|
|
'imagemin:core'
|
|
] );
|
|
|
|
grunt.registerTask( 'precommit:js', [
|
|
'browserify',
|
|
'jshint:corejs',
|
|
'uglify:masonry',
|
|
'qunit:compiled'
|
|
] );
|
|
|
|
grunt.registerTask( 'precommit:css', [
|
|
'postcss:core'
|
|
] );
|
|
|
|
grunt.registerTask( 'precommit:php', [
|
|
'phpunit'
|
|
] );
|
|
|
|
grunt.registerTask( 'precommit:emoji', [
|
|
'replace:emojiRegex'
|
|
] );
|
|
|
|
grunt.registerTask( 'precommit', 'Runs test and build tasks in preparation for a commit', function() {
|
|
var done = this.async();
|
|
var map = {
|
|
svn: 'svn status --ignore-externals',
|
|
git: 'git status --short'
|
|
};
|
|
|
|
find( [
|
|
__dirname + '/.svn',
|
|
__dirname + '/.git',
|
|
path.dirname( __dirname ) + '/.svn'
|
|
] );
|
|
|
|
function find( set ) {
|
|
var dir;
|
|
|
|
if ( set.length ) {
|
|
fs.stat( dir = set.shift(), function( error ) {
|
|
error ? find( set ) : run( path.basename( dir ).substr( 1 ) );
|
|
} );
|
|
} else {
|
|
grunt.fatal( 'This WordPress install is not under version control.' );
|
|
}
|
|
}
|
|
|
|
function run( type ) {
|
|
var command = map[ type ].split( ' ' );
|
|
|
|
grunt.util.spawn( {
|
|
cmd: command.shift(),
|
|
args: command
|
|
}, function( error, result, code ) {
|
|
var taskList = [];
|
|
|
|
if ( code !== 0 ) {
|
|
grunt.fatal( 'The `' + map[ type ] + '` command returned a non-zero exit code.', code );
|
|
}
|
|
|
|
// Callback for finding modified paths.
|
|
function testPath( path ) {
|
|
var regex = new RegExp( ' ' + path + '$', 'm' );
|
|
return regex.test( result.stdout );
|
|
}
|
|
|
|
// Callback for finding modified files by extension.
|
|
function testExtension( extension ) {
|
|
var regex = new RegExp( '\.' + extension + '$', 'm' );
|
|
return regex.test( result.stdout );
|
|
}
|
|
|
|
if ( [ 'package.json', 'Gruntfile.js' ].some( testPath ) ) {
|
|
grunt.log.writeln( 'Configuration files modified. Running `prerelease`.' );
|
|
taskList.push( 'prerelease' );
|
|
} else {
|
|
if ( [ 'png', 'jpg', 'gif', 'jpeg' ].some( testExtension ) ) {
|
|
grunt.log.writeln( 'Image files modified. Minifying.' );
|
|
taskList.push( 'precommit:image' );
|
|
}
|
|
|
|
[ 'js', 'css', 'php' ].forEach( function( extension ) {
|
|
if ( testExtension( extension ) ) {
|
|
grunt.log.writeln( extension.toUpperCase() + ' files modified. ' + extension.toUpperCase() + ' tests will be run.' );
|
|
taskList.push( 'precommit:' + extension );
|
|
}
|
|
} );
|
|
|
|
if ( [ 'twemoji.js' ].some( testPath ) ) {
|
|
grunt.log.writeln( 'twemoji.js has updated. Running `precommit:emoji.' );
|
|
taskList.push( 'precommit:emoji' );
|
|
}
|
|
}
|
|
|
|
grunt.task.run( taskList );
|
|
|
|
done();
|
|
} );
|
|
}
|
|
} );
|
|
|
|
grunt.registerTask( 'copy:all', [
|
|
'copy:files',
|
|
'copy:wp-admin-css-compat-rtl',
|
|
'copy:wp-admin-css-compat-min',
|
|
'copy:version'
|
|
] );
|
|
|
|
grunt.registerTask( 'build', [
|
|
'clean:all',
|
|
'copy:all',
|
|
'cssmin:core',
|
|
'colors',
|
|
'rtl',
|
|
'cssmin:rtl',
|
|
'cssmin:colors',
|
|
'uglify:core',
|
|
'uglify:embed',
|
|
'uglify:jqueryui',
|
|
'concat:tinymce',
|
|
'compress:tinymce',
|
|
'clean:tinymce',
|
|
'concat:emoji',
|
|
'includes:emoji',
|
|
'includes:embed',
|
|
'usebanner',
|
|
'jsvalidate:build'
|
|
] );
|
|
|
|
grunt.registerTask( 'prerelease', [
|
|
'precommit:php',
|
|
'precommit:js',
|
|
'precommit:css',
|
|
'precommit:image'
|
|
] );
|
|
|
|
// Testing tasks.
|
|
grunt.registerMultiTask('phpunit', 'Runs PHPUnit tests, including the ajax, external-http, 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']);
|
|
|
|
// Travis CI tasks.
|
|
grunt.registerTask('travis:js', 'Runs Javascript Travis CI tasks.', [ 'jshint:corejs', 'qunit:compiled' ]);
|
|
grunt.registerTask('travis:phpunit', 'Runs PHPUnit Travis CI tasks.', 'phpunit');
|
|
|
|
// Patch task.
|
|
grunt.renameTask('patch_wordpress', 'patch');
|
|
|
|
// Add an alias `apply` of the `patch` task name.
|
|
grunt.registerTask('apply', 'patch');
|
|
|
|
// Default task.
|
|
grunt.registerTask('default', ['build']);
|
|
|
|
/*
|
|
* Automatically updates the `:dynamic` configurations
|
|
* so that only the changed files are updated.
|
|
*/
|
|
grunt.event.on('watch', function( action, filepath, target ) {
|
|
var src;
|
|
|
|
if ( [ 'all', 'rtl', 'browserify' ].indexOf( target ) === -1 ) {
|
|
return;
|
|
}
|
|
|
|
src = [ path.relative( SOURCE_DIR, filepath ) ];
|
|
|
|
if ( action === 'deleted' ) {
|
|
grunt.config( [ 'clean', 'dynamic', 'src' ], src );
|
|
} else {
|
|
grunt.config( [ 'copy', 'dynamic', 'src' ], src );
|
|
|
|
if ( target === 'rtl' ) {
|
|
grunt.config( [ 'rtlcss', 'dynamic', 'src' ], src );
|
|
}
|
|
}
|
|
});
|
|
};
|