Skip to content

Commit

Permalink
Validation and error notification improvements
Browse files Browse the repository at this point in the history
Fixed validation of asset file name.
Added additional validation and error notification functionality.
Changed README.md reflecting additional validation and error notification functionality.
  • Loading branch information
midnight-coding committed Mar 18, 2019
1 parent e00593d commit a225477
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 61 deletions.
19 changes: 15 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a

## [Unreleased]

## [1.2.0]

### Fixed
- Validation of asset file name.

### Added
- Additional validation and error notification functionality.

### Changed
- README.md reflecting additional validation and error notification functionality.

## [1.1.1] - 2019-03-17

### Fixed
Expand All @@ -14,26 +25,26 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
## [1.1.0] - 2019-03-16

### Added
- Added OpenSSL mask hash methods.
- OpenSSL mask hash methods.

### Changed
- Updated README.md reflecting additional mask hash methods.
- README.md reflecting additional mask hash methods.

### Security
- Removed dependency on 'md5-file' plugin.

## [1.0.2] - 2019-03-15

### Added
- Added ability to replace asset name in template(s) even when asset name is out of sync.
- Ability to replace asset name in template(s) even when asset name is out of sync.

## [1.0.1] - 2019-03-14

### Fixed
- Incorrect counter reference in loop.

### Changed
- Updated README.md reflecting correct usage.
- README.md reflecting correct usage.

## [1.0.0] - 2019-03-13

Expand Down
32 changes: 20 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ Ever wanted to ensure that your most recently deployed asset files (eg: css, js,

Then look no further...!

This grunt plugin inserts a **cache avoiding** string into your asset filename, then looks for and updates any reference to it within your template file(s).
This [Grunt](https://gruntjs.com/) plugin inserts a **cache avoiding** string into your asset filename, then looks for and updates any reference to it within your template file(s).

Find this plugin at:
- [https://www.npmjs.com/package/grunt-cache-killer](https://www.npmjs.com/package/grunt-cache-killer).
- [https://github.com/midnight-coding/grunt-cache-killer](https://github.com/midnight-coding/grunt-cache-killer).

## Getting Started

This plugin requires Grunt `~1.0.3`
This plugin requires Grunt `^1.0.3`

If you haven't used [Grunt](http://gruntjs.com/) before, be sure to check out the [Getting Started](http://gruntjs.com/getting-started) guide, as it explains how to create a [Gruntfile](http://gruntjs.com/sample-gruntfile) as well as how to install and use Grunt plugins. Once you're familiar with that process, you may install this plugin with this command:

Expand All @@ -26,8 +26,8 @@ Once the plugin has been installed, it may be enabled inside your Gruntfile with
grunt.loadNpmTasks('grunt-cache-killer');
```

Alternatively, install the 'load-grunt-tasks' plug (`npm install --save-dev load-grunt-tasks`) and add the following line of code to your gruntfile.js `require('load-grunt-tasks')(grunt);` to automatically load your plugin(s).

Alternatively, install the [load-grunt-tasks](https://www.npmjs.com/package/load-grunt-tasks) plugin to have cacheKiller load automatically.
## The "cacheKiller" task

### Overview
Expand All @@ -51,12 +51,14 @@ grunt.initConfig({

### Options

- `prepend` (string) - A string value that is used to add characters to the front of the `[mask]`. The default value is an empty string.
- `prepend` (string) - A string value that is used to add characters to the front of the `[mask]` placeholder. The default value is an empty string.

- `append` (string) - A string value that is used to add characters to the back of the `[mask]`. The default value is an empty string.
- `append` (string) - A string value that is used to add characters to the back of the `[mask]` placeholder. The default value is an empty string.

- `mask` (string) - A string value that is used to specify the passed in mask. The default value is `{md5}`.
- If a **cacherKiller** mask function is used, then the string generated from that internal function is inserted. CacheKiller's mask functions include:
- If a **cacherKiller** mask function is used, then the string generated from that function will be inserted. If an invalid mask function is used, then an error message along with a full list of valid mask functions will be shown.

CacheKiller's mask functions include:
- `{timestamp}` eg: `1551278199614`
- `{datetimestamp}` eg: `20190228123639`
- All [OpenSSL](https://www.openssl.org/) algorithms available on your system. Some common algorithims include:
Expand All @@ -65,10 +67,16 @@ grunt.initConfig({
- `{sha1}` eg: `a20a181e3C2a813ae08c22fb9d61133c315517bb`
- `{sha224}` eg: `d157aefcf36cdc966737aa0dc4ea85d720652185550c248de9d018f9`
- `{sha256}` eg: `8736ba042ee82bc70676c964b6f7b05e063e1957c95Cb80e4f15f8b01e69c9ad`

**Tip:** Use one of the below listed commands at the command prompt for a full list of available algorithms on your system.
```
// For newer versions of OpenSSL.
openssl list -digest-algorithms
For a full list of available algorithms, at the command prompt type `openssl list -digest-algorithms`.<br>
For older versions of OpenSSL, at the command prompt type `openssl list-message-digest-algorithms`.<br>

// For older versions of OpenSSL.
openssl list-message-digest-algorithms
```
- If a **string** is used, then that string is inserted. eg: `mask: 'my-string'`
- `length` (number) - A number value that is used to set the length of the mask. The default value is `-1`.
Expand All @@ -78,9 +86,9 @@ grunt.initConfig({
### Usage
Within the cacheKiller's `files:` node, place the `[mask]` within the asset filename where you would like the mask to be added.
Within the cacheKiller's `files:` node, place the `[mask]` placeholder within the asset filename where you would like the mask to be added.
> **Warning** - Do not place the `[mask]` at the very beginning or very end of the asset filename. Doing so prevents cacheKiller from properly determining where the start or end of the asset filename exists within the template file(s).
> **Note** - Do not place the `[mask]` placeholder at the very beginning or very end of the asset filename. (eg: `public/css/[mask].website.min.css`). Doing so would mangle the template file(s). CacheKiller prevents this from happening by showing an error message and terminating the script.
### Usage Examples
Expand Down
20 changes: 10 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "grunt-cache-killer",
"description": "Kill your asset cache file problems by updating their filenames and any references to them.",
"version": "1.1.1",
"version": "1.2.0",
"homepage": "https://github.com/midnight-coding/grunt-cache-killer",
"author": {
"name": "Matthew Rath",
Expand All @@ -23,7 +23,7 @@
"grunt-cli": "^1.3.2",
"grunt-contrib-clean": "^2.0.0",
"grunt-contrib-copy": "^1.0.0",
"grunt-contrib-jshint": "^2.0.0",
"grunt-contrib-jshint": "^2.1.0",
"grunt-contrib-nodeunit": "^2.0.0",
"grunt-contrib-watch": "^1.1.0",
"load-grunt-tasks": "^4.0.0"
Expand Down
117 changes: 84 additions & 33 deletions tasks/cacheKiller.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ module.exports = function (grunt) {
/**
* Get hash of file.
*
* @param $file {string}
* @param $file {string}
* @param $algorithm {string}
* @returns {string}
*/
Expand All @@ -90,31 +90,66 @@ module.exports = function (grunt) {
return $hash.digest('hex');
}

/**
* Check if the mask if a function.
*
* @param $mask (string)
* @returns {boolean}
*/
function isMaskFunction($mask) {
return ($mask.substr(0, 1) === '{' && $mask.substr(-1) === '}');
}

/**
* Trim the curly braces from the mask function.
*
* @param $mask (string}
* @returns {string}
*/
function trimMaskFunction($mask) {
return $mask.slice(1, -1);
}

/**
* Check for a valid mask function.
*
* @param $maskFunction {string}
* @param $maskFunctions {array}
* @returns {boolean}
*/
function isValidMaskFunction($maskFunction, $maskFunctions) {
return ($maskFunctions.indexOf($maskFunction)) > -1;
}

/**
* Get mask value.
*
* @param $maskType {string}
* @param $file {string}
* @param $mask {string}
* @param $file {string}
* @returns {string}
*/
function getMaskValue($maskType, $file) {
// If using a timestamp.
if ($maskType === '{timetsmap}') {
return getTimeStamp.toString();
}
function getMaskValue($mask, $file) {
// Check if a mask function is being used.
if (isMaskFunction($mask)) {
// Trim the curly braces from the mask function.
$mask = trimMaskFunction($mask);

// If using a timestamp.
if ($mask === 'timestamp') {
return getTimeStamp().toString();
}

// If using a datetime stamp.
if($maskType === '{datetimestamp}') {
return getDateTimeStamp();
}
// If using a datetime stamp.
if ($mask === 'datetimestamp') {
return getDateTimeStamp();
}

// If using an OpenSSL digest algorithm.
if (/{.*}/.test($maskType)) {
return getHash($file, $maskType.replace(new RegExp(/[{}]/, 'g'), ""));
// Using an OpenSSL digest algorithm.
return getHash($file, $mask);
}

// Just a string.
return $maskType;
return $mask;
}

/**
Expand Down Expand Up @@ -143,13 +178,13 @@ module.exports = function (grunt) {
// Iterate over the asset filename(s).
for (var i = 0; i < $files.length; i++) {
// Check if the pre and post strings match the start and end parts of the asset filename respectively.
if ($pre === $files[i].substring(0, $pre.length) && $post === $files[i].substring($files[i].length - $post.length)) {
// A match was found.
if ($pre === $files[i].substr(0, $pre.length) && $post === $files[i].substr(-$post.length)) {
// A matching asset was found.
return $files[i];
}
}

// A match was not found.
// A matching asset was not found.
return null;
}

Expand All @@ -174,14 +209,28 @@ module.exports = function (grunt) {
// Set the default mask placeholder.
var $maskPlaceholder = '[mask]';

// Validate the options.
// Set the valid mask functions types.
var $validMaskFunctionTypes = ['timestamp', 'datetimestamp'].concat(crypto.getHashes()).sort(function (a, b) {
return a.localeCompare(b, undefined, {sensitivity: 'base'});
});

// Validate the options types.
for (var $key in $validOptionsTypes) {
// Check if the option type is incorrect.
if (typeof ($options[$key]) !== $validOptionsTypes[$key]) {
grunt.fail.warn('cacheKiller -> ' + this.target + ' -> options -> ' + $key + ' must be a ' + $validOptionsTypes[$key] + '. ' + typeof ($options[$key]) + ' given.');
// Capitalise the first letter.
var $type = typeof ($options[$key]);
$type = $type.charAt(0).toUpperCase() + $type.slice(1);

grunt.fail.warn(this.target + ' : The option \'' + $key + '\' must be a ' + $validOptionsTypes[$key] + '. ' + $type + ' given.');
}
}

// Validate the mask function type.
if (isMaskFunction($options.mask) && !isValidMaskFunction(trimMaskFunction($options.mask), $validMaskFunctionTypes)) {
grunt.fail.warn(this.target + ' : The options mask \'' + $options.mask + '\' is not a valid mask. Valid masks include ' + $validMaskFunctionTypes.join(', ') + '.');
}

// Build the tasks list.
var $tasks = {};

Expand All @@ -202,9 +251,19 @@ module.exports = function (grunt) {
$tasks[i].asset.name.pre = $tasks[i].asset.name.file.split($maskPlaceholder)[0];
$tasks[i].asset.name.post = $tasks[i].asset.name.file.split($maskPlaceholder)[1];

// Check the position of the mask placeholder within the asset filename.
if ($tasks[i].asset.name.pre === '' || $tasks[i].asset.name.post === '') {
grunt.fail.warn(this.target + ' : The position of the [mask] placeholder cannot be at the very beginning or very end of the asset filename. \'' + $tasks[i].asset.name.full + '\' given.');
}

$tasks[i].asset.rename.from.file = findMatchingAsset($tasks[i].asset.name.base, $tasks[i].asset.name.pre, $tasks[i].asset.name.post);
$tasks[i].asset.rename.from.full = $tasks[i].asset.name.base + $tasks[i].asset.rename.from.file;

// Check if the asset filename exists.
if ($tasks[i].asset.rename.from.file === null) {
grunt.fail.warn(this.target + ' : The masked asset file \'' + $tasks[i].asset.name.full + '\' does not exist.');
}

$tasks[i].asset.mask.prepend = $options.prepend;
$tasks[i].asset.mask.value = {};
$tasks[i].asset.mask.value.raw = getMaskValue($options.mask, $tasks[i].asset.rename.from.full);
Expand All @@ -217,30 +276,22 @@ module.exports = function (grunt) {

// Let's begin.
grunt.log.writeln('');
grunt.log.writeln('-----------');
grunt.log.writeln('cacheKiller');
grunt.log.writeln('-----------');

// Iterate over the tasks list.
for (var j = 0; j < Object.keys($tasks).length; j++) {

// Check if the asset file exists.
if ($tasks[j].asset.rename.from.full === null) {
grunt.fail.warn('cacheKiller -> ' + this.target + ' : The masked asset file \'' + $tasks[j].asset.name.full + '\' does not exist.');
}

// Check if the template file(s) exist.
// Check if the template filename(s) exist.
for (var k = 0; k < $tasks[j].templates.length; k++) {
if (!fileSystem.existsSync($tasks[j].templates[k])) {
grunt.fail.warn('cacheKiller -> ' + this.target + ' : The template file \'' + $tasks[j].templates[k] + '\' does not exist.');
grunt.fail.warn(this.target + ' : The template file \'' + $tasks[j].templates[k] + '\' does not exist.');
}
}

// Synchronously rename the asset file.
fileSystem.renameSync($tasks[j].asset.rename.from.full, $tasks[j].asset.rename.to.full);

// Show the successful asset renaming message.
grunt.log.ok(this.target + ' : Asset file \'' + $tasks[j].asset.rename.from.file + '\' renamed to \'' + $tasks[j].asset.rename.to.file + '\'');
grunt.log.ok(this.target + ' : Asset file \'' + $tasks[j].asset.rename.from.file + '\' renamed to \'' + $tasks[j].asset.rename.to.file + '\'.');

// Update any reference to the asset file in the template file(s).
for (var l = 0; l < $tasks[j].templates.length; l++) {
Expand All @@ -255,7 +306,7 @@ module.exports = function (grunt) {
fileSystem.writeFileSync($tasks[j].templates[l], result, 'utf8');

// Show the successful template update message.
grunt.log.ok(this.target + ' : Reference updated in template file \'' + $tasks[j].templates[l] + '\'.');
grunt.log.ok(this.target + ' : Reference(s) updated in template file \'' + $tasks[j].templates[l] + '\'.');
}

// Add line between target(s) and goodbye.
Expand Down

0 comments on commit a225477

Please sign in to comment.