From f0f6877dc47035f59ad10f12ab05809290929003 Mon Sep 17 00:00:00 2001 From: NickCrews Date: Sat, 21 Nov 2020 20:32:17 -0700 Subject: [PATCH] Add format and format-all tasks to grunt `grunt format` now runs js-beautify and sortImports on all js files in a given repo (or the current one if none is given). In addition, you can use `grunt format --verify` to just check that the files are formatted, but not actually modify them. This could be useful for a pre-commit hook. The `grunt format-all` variation is similar to lint-all in that it runs format on all the repos that are libraries of the supplied repo. --- js/grunt/Gruntfile.js | 17 ++++++++ js/grunt/format.js | 90 +++++++++++++++++++++++++++++++++++++++++ js/grunt/sortImports.js | 15 ++++--- package.json | 1 + 4 files changed, 118 insertions(+), 5 deletions(-) create mode 100644 js/grunt/format.js diff --git a/js/grunt/Gruntfile.js b/js/grunt/Gruntfile.js index 6f62e3c95..c769fa856 100644 --- a/js/grunt/Gruntfile.js +++ b/js/grunt/Gruntfile.js @@ -22,6 +22,7 @@ const generateTestHTML = require( './generateTestHTML' ); const generateThumbnails = require( './generateThumbnails' ); const generateTwitterCard = require( './generateTwitterCard' ); const getPhetLibs = require( './getPhetLibs' ); +const format = require( './format' ); const lint = require( './lint' ); const fixEOL = require( './fixEOL' ); const migrate = require( './migrate' ); @@ -275,6 +276,22 @@ module.exports = function( grunt ) { lint( getPhetLibs( repo ), cache ); } ) ); + grunt.registerTask( 'format', 'format js files that are specific to this repository', wrapTask( async () => { + + //Don't actually modify the files, just verify them? + const verifyOnly = !!grunt.option( 'verify' ); + + format( [ repo ], verifyOnly ); + } ) ); + + grunt.registerTask( 'format-all', 'format all js files that are required to build this repository (for all supported brands)', wrapTask( async () => { + + //Don't actually modify the files, just verify them? + const verifyOnly = !!grunt.option( 'verify' ); + + format( getPhetLibs( repo ), verifyOnly ); + } ) ); + grunt.registerTask( 'generate-development-html', 'Generates top-level SIM_en.html file based on the preloads in package.json.', wrapTask( async () => { diff --git a/js/grunt/format.js b/js/grunt/format.js new file mode 100644 index 000000000..66190a60d --- /dev/null +++ b/js/grunt/format.js @@ -0,0 +1,90 @@ +// Copyright 2020, Nick Crews + +/** + * Runs the formatting rules on the specified files. + * + * @author @NickCrews + */ + +'use strict'; + +// modules +const beautify = require( 'js-beautify' ); +const fs = require( 'fs' ); +const grunt = require( 'grunt' ); +const sortImports = require( './sortImports' ); + +const OPTIONS = { + "html": { + "allowed_file_extensions": [ "htm", "html", "xhtml", "shtml", "xml", "svg" ], + "brace_style": "collapse", + "end_with_newline": false, + "indent_char": " ", + "indent_handlebars": false, + "indent_inner_html": false, + "indent_size": 2, + "indent_scripts": "keep", + "max_preserve_newlines": 1, + "preserve_newlines": true, + "unformatted": [ "a", "span", "img", "code", "pre", "sub", "sup", "em", "strong", "b", "i", "u", "strike", "big", "small", "pre", "h1", "h2", "h3", "h4", "h5", "h6" ], + "wrap_line_length": 0 + }, + "css": { + "allowed_file_extensions": [ "css", "scss", "sass", "less" ], + "end_with_newline": false, + "newline_between_rules": true, + "indent_char": " ", + "indent_size": 2, + "selector_separator": " ", + "selector_separator_newline": true + }, + "js": { + "allowed_file_extensions": [ "js", "json", "jshintrc", "jsbeautifyrc", "sublime-settings" ], + "brace_style": "collapse-preserve-inline", + "break_chained_methods": false, + "e4x": false, + "end_with_newline": true, + "indent_char": " ", + "indent_level": 0, + "indent_size": 2, + "indent_with_tabs": false, + "jslint_happy": false, + "keep_array_indentation": false, + "keep_function_indentation": false, + "max_preserve_newlines": 0, + "preserve_newlines": true, + "space_after_anon_function": false, + "space_before_conditional": true, + "space_in_empty_paren": false, + "space_in_paren": true, + "unescape_strings": false, + "wrap_line_length": 0 + } +} + +function formatFile( absPath, verifyOnly = false ) { + let before = fs.readFileSync( absPath, 'utf-8' ); + const formatted = beautify.js( before, OPTIONS ); + if ( !verifyOnly ){ + fs.writeFileSync( absPath, formatted, 'utf-8' ); + } + const alreadySorted = sortImports( absPath, verifyOnly ); + return alreadySorted && ( before == formatted ); +} + +/** + * Formats the specified repositories. + * @public + * + * @param {Array.} repos + * @param {boolean} verifyOnly - Don't rewrite files + */ +module.exports = function( repos, verifyOnly = false) { + + repos.forEach( repo => { + grunt.file.recurse( + `../${repo}/js`, + absPath => formatFile( absPath, verifyOnly ) + ) } ); + +} diff --git a/js/grunt/sortImports.js b/js/grunt/sortImports.js index 0fcb43d86..cb46608cb 100644 --- a/js/grunt/sortImports.js +++ b/js/grunt/sortImports.js @@ -28,10 +28,12 @@ const isImport = line => line.startsWith( 'import ' ); /** * @param {string} file + * @param {boolean} verifyOnly - Don't rewrite file, just verify already sorted + * @returns {boolean} - Was the file properly sorted to begin with? */ -module.exports = function( file ) { - let contents = fs.readFileSync( file, 'utf-8' ); - let lines = contents.split( /\r?\n/ ); +module.exports = function( file, verifyOnly = false ) { + const before = fs.readFileSync( file, 'utf-8' ); + let lines = before.split( /\r?\n/ ); // remove the grouping comments lines = lines.filter( ( line, i ) => { @@ -67,6 +69,9 @@ module.exports = function( file ) { firstImportIndex--; } - contents = lines.join( '\n' ); - fs.writeFileSync( file, contents, 'utf-8' ); + const after = lines.join( '\n' ); + if (!verifyOnly){ + fs.writeFileSync( file, after, 'utf-8' ); + } + return (after == before); }; diff --git a/package.json b/package.json index 4ef34e3bd..794596e8f 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "eslint": "^6.8.0", "eslint-plugin-react": "^7.18.0", "grunt": "~1.1.0", + "grunt-jsbeautifier": "^0.2.13", "jimp": "^0.2.0", "jpeg-js": "~0.1.1", "jscpd": "^0.6.18",