Skip to content

Commit

Permalink
Added support for verifying if all SVG files are optimized.
Browse files Browse the repository at this point in the history
Added SVG files validator on CI.
  • Loading branch information
psmyrek committed Oct 24, 2023
1 parent 73f49bf commit 2f4737e
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 25 deletions.
6 changes: 5 additions & 1 deletion .circleci/template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ commands:
echo "Running full flow due to nightly build, despite detecting '[short flow]'."
exit 0
fi
if [[ "$COMMIT_MESSAGE" == *"[short flow]" ]]; then
echo "Skipping, because the commit message contains '[short flow]'."
circleci step halt
Expand Down Expand Up @@ -105,6 +105,10 @@ jobs:
when: always
name: Validate icons specified in "ckeditor5-metadata.json" files
command: node scripts/ci/validate-metadata-icons.js
- run:
when: always
name: Check if all SVG files are optimized
command: yarn run clean-up-svg-icons --verify-only
- run:
when: always
name: Validate manual test directories
Expand Down
114 changes: 90 additions & 24 deletions scripts/clean-up-svg-icons.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,37 @@
// Cleans up and optimizes SVG files using the SVGO utility. The configuration file is located in svgo.config.json.
//
// Usage:
// yarn run clean-up-svg-icons <path/to/icons>
// yarn run clean-up-svg-icons [<option>...] [<path>...]
//
// yarn run clean-up-svg-icons <path/to/icons> <another/path/to/icons>
//
// The <path/to/icons> can be either a direct path to a SVG file, or a path to a directory. Glob patterns in path are supported.
// The <path> can be either a direct path to a SVG file, or a path to a directory. Glob patterns in path are supported.
// Multiple arguments (paths) in one call are supported.
//
// To optimize the entire project run:
// yarn run clean-up-svg-icons
// Options:
// --verify-only
// If set, the script does not modify any SVG file, but it checks whether all files are already optimized.
// If any file is not optimized, the script ends with an error code.
//
// Examples:
// To optimize the entire project, run:
// yarn run clean-up-svg-icons
//
// To optimize single file, run:
// yarn run clean-up-svg-icons <path/to/icon>
//
// To optimize single directory, run:
// yarn run clean-up-svg-icons <path/to/directory>
//
// To optimize multiple directories, run:
// yarn run clean-up-svg-icons <path/to/directory> <another/path/to/directory>
//
// To check if single file is already optimized, run:
// yarn run clean-up-svg-icons --verify-only <path/to/icon>

'use strict';

const chalk = require( 'chalk' );
const upath = require( 'upath' );
const fs = require( 'fs-extra' );
const minimist = require( 'minimist' );
const { globSync } = require( 'glob' );
const { execSync } = require( 'child_process' );
Expand All @@ -38,33 +55,82 @@ const EXCLUDED_ICONS = [
// A pattern to match all the icons.
const ALL_ICONS_PATTERN = 'packages/**/theme/icons';

const globPattern = parseArguments( process.argv.slice( 2 ) )
.map( pathToIcon => pathToIcon.endsWith( '.svg' ) ? pathToIcon : pathToIcon + '/*.svg' );
const { paths, verifyOnly } = parseArguments( process.argv.slice( 2 ) );

const globPattern = paths.map( pathToIcon => {
return pathToIcon.endsWith( '.svg' ) ? pathToIcon : pathToIcon + '/*.svg';
} );

let statusCode = 0;

globSync( globPattern )
.map( upath.toUnix )
.filter( pathToIcon => {
const iconName = upath.basename( pathToIcon );
const isExcluded = EXCLUDED_ICONS.includes( iconName );
.filter( filterExcludedIcons )
.forEach( processIcon );

if ( verifyOnly && statusCode ) {
console.log( chalk.red.bold( '\nSome SVG files are not optimized.' ) );
console.log( chalk.red(
'Execute "yarn run clean-up-svg-icons" to optimize them or add them to exceptions in "scripts/clean-up-svg-icons.js" file.\n'
) );

process.exit( statusCode );
}

function parseArguments( args ) {
const config = {
boolean: [
'verify-only'
],

if ( isExcluded ) {
console.log( chalk.yellow( `The "${ pathToIcon }" icon is excluded.` ) );
default: {
'verify-only': false
}
};

return !isExcluded;
} )
.forEach( pathToIcon => {
console.log( chalk.green( `Processing "${ pathToIcon }" icon...` ) );
const {
'verify-only': verifyOnly,
_: paths
} = minimist( args, config );

execSync( `svgo --config=./scripts/svgo.config.js -i ${ pathToIcon }` );
} );
return {
verifyOnly,
paths: paths.length > 0 ? paths : [ ALL_ICONS_PATTERN ]
};
}

function parseArguments( args ) {
const paths = minimist( args )._;
function filterExcludedIcons( pathToIcon ) {
const iconName = upath.basename( pathToIcon );
const isExcluded = EXCLUDED_ICONS.includes( iconName );

if ( paths.length > 0 ) {
return paths;
if ( isExcluded ) {
console.log( chalk.yellow( `The "${ pathToIcon }" icon is excluded.` ) );
}

return [ ALL_ICONS_PATTERN ];
return !isExcluded;
}

function processIcon( pathToIcon ) {
console.log( chalk.green( `Processing "${ pathToIcon }" icon...` ) );

const svgoOptions = [
'--config=./scripts/svgo.config.js',
`-i ${ pathToIcon }`
];

if ( verifyOnly ) {
svgoOptions.push( '-o -' );
}

const result = execSync( `svgo ${ svgoOptions.join( ' ' ) }`, { encoding: 'utf-8' } ).trim();

if ( verifyOnly ) {
const iconFile = fs.readFileSync( pathToIcon, 'utf-8' ).trim();

if ( result !== iconFile ) {
statusCode = 1;

console.log( chalk.red( `Icon "${ pathToIcon }" is not optimized.` ) );
}
}
}

0 comments on commit 2f4737e

Please sign in to comment.