"use strict";

module.exports = function( grunt ) {

const { gzipSync } = require( "node:zlib" );

// files
const coreFiles = [
	"widget.js",
	"widgets/mouse.js",
	"widgets/draggable.js",
	"widgets/droppable.js",
	"widgets/resizable.js",
	"widgets/selectable.js",
	"widgets/sortable.js",
	"effect.js"
];

const uiFiles = coreFiles.map( function( file ) {
	return "ui/" + file;
} ).concat( expandFiles( "ui/**/*.js" ).filter( function( file ) {
	return coreFiles.indexOf( file.substring( 3 ) ) === -1;
} ) );

const allI18nFiles = expandFiles( "ui/i18n/*.js" );

const cssFiles = [
	"core",
	"accordion",
	"autocomplete",
	"button",
	"checkboxradio",
	"controlgroup",
	"datepicker",
	"dialog",
	"draggable",
	"menu",
	"progressbar",
	"resizable",
	"selectable",
	"selectmenu",
	"sortable",
	"slider",
	"spinner",
	"tabs",
	"tooltip",
	"theme"
].map( function( component ) {
	return "themes/base/" + component + ".css";
} );

// minified files
const minify = {
	options: {
		preserveComments: false
	},
	main: {
		options: {
			banner: createBanner( uiFiles )
		},
		files: {
			"dist/jquery-ui.min.js": "dist/jquery-ui.js"
		}
	},
	i18n: {
		options: {
			banner: createBanner( allI18nFiles )
		},
		files: {
			"dist/i18n/jquery-ui-i18n.min.js": "dist/i18n/jquery-ui-i18n.js"
		}
	}
};

const compareFiles = {
	all: [
		"dist/jquery-ui.js",
		"dist/jquery-ui.min.js"
	],
	options: {
		compress: {
			gz: function( contents ) {
				return gzipSync( contents ).length;
			}
		},
		cache: "build/.sizecache.json"
	}
};

const htmllintBad = [
	"demos/tabs/ajax/content*.html",
	"demos/tooltip/ajax/content*.html",
	"tests/unit/core/core.html",
	"tests/unit/tabs/data/test.html"
];

function mapMinFile( file ) {
	return "dist/" + file.replace( /ui\//, "minified/" );
}

function expandFiles( files ) {
	return grunt.util._.map( grunt.file.expandMapping( files ), "src" ).map( function( values ) {
		return values[ 0 ];
	} );
}

uiFiles.concat( allI18nFiles ).forEach( function( file ) {
	minify[ file ] = {
		options: {
			banner: createBanner()
		},
		files: {}
	};
	minify[ file ].files[ mapMinFile( file ) ] = file;
} );

uiFiles.forEach( function( file ) {
	compareFiles[ file ] = [ file, mapMinFile( file ) ];
} );

function stripDirectory( file ) {
	return file.replace( /.+\/(.+?)>?$/, "$1" );
}

function createBanner( files ) {

	// strip folders
	const fileNames = files && files.map( stripDirectory );
	return "/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - " +
		"<%= grunt.template.today('isoDate') %>\n" +
		"<%= pkg.homepage ? '* ' + pkg.homepage + '\\n' : '' %>" +
		( files ? "* Includes: " + fileNames.join( ", " ) + "\n" : "" ) +
		"* Copyright <%= pkg.author.name %>;" +
		" Licensed <%= _.map(pkg.licenses, 'type').join(', ') %> */\n";
}

grunt.initConfig( {
	pkg: grunt.file.readJSON( "package.json" ),
	files: {
		dist: "<%= pkg.name %>-<%= pkg.version %>"
	},
	compare_size: compareFiles,
	concat: {
		css: {
			options: {
				banner: createBanner( cssFiles ),
				stripBanners: {
					block: true
				}
			},
			src: cssFiles,
			dest: "dist/jquery-ui.css"
		}
	},
	requirejs: {
		js: {
			options: {
				baseUrl: "./",
				paths: {
					jquery: "./external/jquery/jquery",
					external: "./external/"
				},
				preserveLicenseComments: false,
				optimize: "none",
				findNestedDependencies: true,
				skipModuleInsertion: true,
				exclude: [ "jquery" ],
				include: expandFiles( [ "ui/**/*.js", "!ui/i18n/*" ] ),
				out: "dist/jquery-ui.js",
				wrap: {
					start: createBanner( uiFiles )
				}
			}
		}
	},

	uglify: minify,
	htmllint: {
		good: {
			options: {
				ignore: [
					/The text content of element “script” was not in the required format: Expected space, tab, newline, or slash but found “.” instead/,
					/This document appears to be written in .*. Consider using “lang=".*"” \(or variant\) instead/
				]
			},
			src: [
				"{demos,tests}/**/*.html",
				...htmllintBad.map( pattern => `!${ pattern }` )
			]
		},
		bad: {
			options: {
				ignore: [
					/Start tag seen without seeing a doctype first/,
					/Element “head” is missing a required instance of child element “title”/,
					/Element “object” is missing one or more of the following/,
					/The “codebase” attribute on the “object” element is obsolete/,
					/Consider adding a “lang” attribute to the “html” start tag/,
					/This document appears to be written in .*. Consider (?:adding|using) “lang=".*"” \(or variant\)/
				]
			},
			src: htmllintBad
		}
	},
	eslint: {
		all: [
			"ui/**/*.js",
			"!ui/vendor/**/*.js",
			"Gruntfile.js",
			"build/**/*.js",
			"tests/unit/**/*.js",
			"tests/lib/**/*.js",
			"demos/**/*.js"
		]
	},
	csslint: {
		base_theme: {
			src: "themes/base/*.css",
			options: {
				csslintrc: ".csslintrc"
			}
		}
	},

	bowercopy: {
		inlineVendors: {
			options: {
				clean: true,
				destPrefix: "ui/vendor"
			},
			files: {
				"jquery-color/jquery.color.js": "jquery-color/dist/jquery.color.js",
				"jquery-color/LICENSE.txt": "jquery-color/LICENSE.txt"
			}
		},

		all: {
			options: {
				clean: true,
				ignore: [ "jquery" ],
				destPrefix: "external"
			},
			files: {
				"qunit/qunit.js": "qunit/qunit/qunit.js",
				"qunit/qunit.css": "qunit/qunit/qunit.css",
				"qunit/LICENSE.txt": "qunit/LICENSE.txt",

				"requirejs/require.js": "requirejs/require.js",

				"jquery-mousewheel/jquery.mousewheel.js": "jquery-mousewheel/jquery.mousewheel.js",
				"jquery-mousewheel/LICENSE.txt": "jquery-mousewheel/LICENSE.txt",

				"jquery-simulate/jquery.simulate.js": "jquery-simulate/jquery.simulate.js",
				"jquery-simulate/LICENSE.txt": "jquery-simulate/LICENSE.txt",

				"jquery/jquery.js": "jquery-3.x/dist/jquery.js",
				"jquery/LICENSE.txt": "jquery-3.x/LICENSE.txt",

				"jquery-1.12.4/jquery.js": "jquery-1.12.4/dist/jquery.js",
				"jquery-1.12.4/LICENSE.txt": "jquery-1.12.4/LICENSE.txt",

				"jquery-2.2.4/jquery.js": "jquery-2.2.4/dist/jquery.js",
				"jquery-2.2.4/LICENSE.txt": "jquery-2.2.4/LICENSE.txt",

				"jquery-3.0.0/jquery.js": "jquery-3.0.0/dist/jquery.js",
				"jquery-3.0.0/LICENSE.txt": "jquery-3.0.0/LICENSE.txt",

				"jquery-3.1.0/jquery.js": "jquery-3.1.0/dist/jquery.js",
				"jquery-3.1.0/LICENSE.txt": "jquery-3.1.0/LICENSE.txt",

				"jquery-3.1.1/jquery.js": "jquery-3.1.1/dist/jquery.js",
				"jquery-3.1.1/LICENSE.txt": "jquery-3.1.1/LICENSE.txt",

				"jquery-3.2.0/jquery.js": "jquery-3.2.0/dist/jquery.js",
				"jquery-3.2.0/LICENSE.txt": "jquery-3.2.0/LICENSE.txt",

				"jquery-3.2.1/jquery.js": "jquery-3.2.1/dist/jquery.js",
				"jquery-3.2.1/LICENSE.txt": "jquery-3.2.1/LICENSE.txt",

				"jquery-3.3.0/jquery.js": "jquery-3.3.0/dist/jquery.js",
				"jquery-3.3.0/LICENSE.txt": "jquery-3.3.0/LICENSE.txt",

				"jquery-3.3.1/jquery.js": "jquery-3.3.1/dist/jquery.js",
				"jquery-3.3.1/LICENSE.txt": "jquery-3.3.1/LICENSE.txt",

				"jquery-3.4.0/jquery.js": "jquery-3.4.0/dist/jquery.js",
				"jquery-3.4.0/LICENSE.txt": "jquery-3.4.0/LICENSE.txt",

				"jquery-3.4.1/jquery.js": "jquery-3.4.1/dist/jquery.js",
				"jquery-3.4.1/LICENSE.txt": "jquery-3.4.1/LICENSE.txt",

				"jquery-3.5.0/jquery.js": "jquery-3.5.0/dist/jquery.js",
				"jquery-3.5.0/LICENSE.txt": "jquery-3.5.0/LICENSE.txt",

				"jquery-3.5.1/jquery.js": "jquery-3.5.1/dist/jquery.js",
				"jquery-3.5.1/LICENSE.txt": "jquery-3.5.1/LICENSE.txt",

				"jquery-3.6.0/jquery.js": "jquery-3.6.0/dist/jquery.js",
				"jquery-3.6.0/LICENSE.txt": "jquery-3.6.0/LICENSE.txt",

				"jquery-3.6.1/jquery.js": "jquery-3.6.1/dist/jquery.js",
				"jquery-3.6.1/LICENSE.txt": "jquery-3.6.1/LICENSE.txt",

				"jquery-3.6.2/jquery.js": "jquery-3.6.2/dist/jquery.js",
				"jquery-3.6.2/LICENSE.txt": "jquery-3.6.2/LICENSE.txt",

				"jquery-3.6.3/jquery.js": "jquery-3.6.3/dist/jquery.js",
				"jquery-3.6.3/LICENSE.txt": "jquery-3.6.3/LICENSE.txt",

				"jquery-3.6.4/jquery.js": "jquery-3.6.4/dist/jquery.js",
				"jquery-3.6.4/LICENSE.txt": "jquery-3.6.4/LICENSE.txt",

				"jquery-3.7.0/jquery.js": "jquery-3.7.0/dist/jquery.js",
				"jquery-3.7.0/LICENSE.txt": "jquery-3.7.0/LICENSE.txt",

				"jquery-3.7.1/jquery.js": "jquery-3.7.1/dist/jquery.js",
				"jquery-3.7.1/LICENSE.txt": "jquery-3.7.1/LICENSE.txt",

				"jquery-migrate-1.x/jquery-migrate.js":
					"jquery-migrate-1.x/dist/jquery-migrate.js",
				"jquery-migrate-1.x/LICENSE.txt": "jquery-migrate-1.x/LICENSE.txt",

				"jquery-migrate-3.x/jquery-migrate.js":
					"jquery-migrate-3.x/dist/jquery-migrate.js",
				"jquery-migrate-3.x/LICENSE.txt": "jquery-migrate-3.x/LICENSE.txt"
			}
		}
	},

	authors: {
		prior: [
			"Paul Bakaus <paul.bakaus@gmail.com>",
			"Richard Worth <rdworth@gmail.com>",
			"Yehuda Katz <wycats@gmail.com>",
			"Sean Catchpole <sean@sunsean.com>",
			"John Resig <jeresig@gmail.com>",
			"Tane Piper <piper.tane@gmail.com>",
			"Dmitri Gaskin <dmitrig01@gmail.com>",
			"Klaus Hartl <klaus.hartl@gmail.com>",
			"Stefan Petre <stefan.petre@gmail.com>",
			"Gilles van den Hoven <gilles@webunity.nl>",
			"Micheil Bryan Smith <micheil@brandedcode.com>",
			"Jörn Zaefferer <joern.zaefferer@gmail.com>",
			"Marc Grabanski <m@marcgrabanski.com>",
			"Keith Wood <kbwood@iinet.com.au>",
			"Brandon Aaron <brandon.aaron@gmail.com>",
			"Scott González <scott.gonzalez@gmail.com>",
			"Eduardo Lundgren <eduardolundgren@gmail.com>",
			"Aaron Eisenberger <aaronchi@gmail.com>",
			"Joan Piedra <theneojp@gmail.com>",
			"Bruno Basto <b.basto@gmail.com>",
			"Remy Sharp <remy@leftlogic.com>",
			"Bohdan Ganicky <bohdan.ganicky@gmail.com>"
		]
	}
} );

// grunt plugins
require( "load-grunt-tasks" )( grunt );

// local tasks
grunt.loadTasks( "build/tasks" );

grunt.registerTask( "update-authors", function() {
	const getAuthors = require( "grunt-git-authors" ).getAuthors;
	const done = this.async();

	getAuthors( {
		priorAuthors: grunt.config( "authors.prior" )
	}, function( error, authors ) {
		if ( error ) {
			grunt.log.error( error );
			return done( false );
		}

		authors = authors.map( function( author ) {
			if ( author.match( /^Jacek Jędrzejewski </ ) ) {
				return "Jacek Jędrzejewski (https://jacek.jedrzejewski.name)";
			} else if ( author.match( /^Pawel Maruszczyk </ ) ) {
				return "Pawel Maruszczyk (http://hrabstwo.net)";
			} else {
				return author;
			}
		} );

		grunt.file.write( "AUTHORS.txt",
			"Authors ordered by first contribution\n" +
			"A list of current team members is available at https://jqueryui.com/about\n\n" +
			authors.join( "\n" ) + "\n" );
		done();
	} );
} );

grunt.registerTask( "print_old_node_message", ( ...args ) => {
	const task = args.join( ":" );
	grunt.log.writeln( "Old Node.js detected, running the task \"" + task + "\" skipped..." );
} );

// Keep this task list in sync with the testing steps in our GitHub action test workflow file!
grunt.registerTask( "lint", [
	"asciilint",
	"eslint",
	"csslint",
	"htmllint"
] );
grunt.registerTask( "build", [ "requirejs", "concat" ] );
grunt.registerTask( "default", [ "lint", "build" ] );
grunt.registerTask( "sizer", [ "requirejs:js", "uglify:main", "compare_size:all" ] );
grunt.registerTask( "sizer_all", [ "requirejs:js", "uglify", "compare_size" ] );

};