Skip to content

Commit a225477

Browse files
Validation and error notification improvements
Fixed validation of asset file name. Added additional validation and error notification functionality. Changed README.md reflecting additional validation and error notification functionality.
1 parent e00593d commit a225477

File tree

5 files changed

+131
-61
lines changed

5 files changed

+131
-61
lines changed

CHANGELOG.md

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
66

77
## [Unreleased]
88

9+
## [1.2.0]
10+
11+
### Fixed
12+
- Validation of asset file name.
13+
14+
### Added
15+
- Additional validation and error notification functionality.
16+
17+
### Changed
18+
- README.md reflecting additional validation and error notification functionality.
19+
920
## [1.1.1] - 2019-03-17
1021

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

1627
### Added
17-
- Added OpenSSL mask hash methods.
28+
- OpenSSL mask hash methods.
1829

1930
### Changed
20-
- Updated README.md reflecting additional mask hash methods.
31+
- README.md reflecting additional mask hash methods.
2132

2233
### Security
2334
- Removed dependency on 'md5-file' plugin.
2435

2536
## [1.0.2] - 2019-03-15
2637

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

3041
## [1.0.1] - 2019-03-14
3142

3243
### Fixed
3344
- Incorrect counter reference in loop.
3445

3546
### Changed
36-
- Updated README.md reflecting correct usage.
47+
- README.md reflecting correct usage.
3748

3849
## [1.0.0] - 2019-03-13
3950

README.md

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ Ever wanted to ensure that your most recently deployed asset files (eg: css, js,
44

55
Then look no further...!
66

7-
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).
7+
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).
88

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

1313
## Getting Started
1414

15-
This plugin requires Grunt `~1.0.3`
15+
This plugin requires Grunt `^1.0.3`
1616

1717
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:
1818

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

29-
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).
30-
29+
Alternatively, install the [load-grunt-tasks](https://www.npmjs.com/package/load-grunt-tasks) plugin to have cacheKiller load automatically.
30+
3131
## The "cacheKiller" task
3232

3333
### Overview
@@ -51,12 +51,14 @@ grunt.initConfig({
5151

5252
### Options
5353

54-
- `prepend` (string) - A string value that is used to add characters to the front of the `[mask]`. The default value is an empty string.
54+
- `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.
5555

56-
- `append` (string) - A string value that is used to add characters to the back of the `[mask]`. The default value is an empty string.
56+
- `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.
5757

5858
- `mask` (string) - A string value that is used to specify the passed in mask. The default value is `{md5}`.
59-
- If a **cacherKiller** mask function is used, then the string generated from that internal function is inserted. CacheKiller's mask functions include:
59+
- 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.
60+
61+
CacheKiller's mask functions include:
6062
- `{timestamp}` eg: `1551278199614`
6163
- `{datetimestamp}` eg: `20190228123639`
6264
- All [OpenSSL](https://www.openssl.org/) algorithms available on your system. Some common algorithims include:
@@ -65,10 +67,16 @@ grunt.initConfig({
6567
- `{sha1}` eg: `a20a181e3C2a813ae08c22fb9d61133c315517bb`
6668
- `{sha224}` eg: `d157aefcf36cdc966737aa0dc4ea85d720652185550c248de9d018f9`
6769
- `{sha256}` eg: `8736ba042ee82bc70676c964b6f7b05e063e1957c95Cb80e4f15f8b01e69c9ad`
70+
71+
**Tip:** Use one of the below listed commands at the command prompt for a full list of available algorithms on your system.
72+
```
73+
// For newer versions of OpenSSL.
74+
openssl list -digest-algorithms
6875
69-
For a full list of available algorithms, at the command prompt type `openssl list -digest-algorithms`.<br>
70-
For older versions of OpenSSL, at the command prompt type `openssl list-message-digest-algorithms`.<br>
71-
76+
// For older versions of OpenSSL.
77+
openssl list-message-digest-algorithms
78+
```
79+
7280
- If a **string** is used, then that string is inserted. eg: `mask: 'my-string'`
7381
7482
- `length` (number) - A number value that is used to set the length of the mask. The default value is `-1`.
@@ -78,9 +86,9 @@ grunt.initConfig({
7886
7987
### Usage
8088
81-
Within the cacheKiller's `files:` node, place the `[mask]` within the asset filename where you would like the mask to be added.
89+
Within the cacheKiller's `files:` node, place the `[mask]` placeholder within the asset filename where you would like the mask to be added.
8290
83-
> **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).
91+
> **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.
8492
8593
### Usage Examples
8694

package-lock.json

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "grunt-cache-killer",
33
"description": "Kill your asset cache file problems by updating their filenames and any references to them.",
4-
"version": "1.1.1",
4+
"version": "1.2.0",
55
"homepage": "https://github.com/midnight-coding/grunt-cache-killer",
66
"author": {
77
"name": "Matthew Rath",
@@ -23,7 +23,7 @@
2323
"grunt-cli": "^1.3.2",
2424
"grunt-contrib-clean": "^2.0.0",
2525
"grunt-contrib-copy": "^1.0.0",
26-
"grunt-contrib-jshint": "^2.0.0",
26+
"grunt-contrib-jshint": "^2.1.0",
2727
"grunt-contrib-nodeunit": "^2.0.0",
2828
"grunt-contrib-watch": "^1.1.0",
2929
"load-grunt-tasks": "^4.0.0"

tasks/cacheKiller.js

Lines changed: 84 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ module.exports = function (grunt) {
6565
/**
6666
* Get hash of file.
6767
*
68-
* @param $file {string}
68+
* @param $file {string}
6969
* @param $algorithm {string}
7070
* @returns {string}
7171
*/
@@ -90,31 +90,66 @@ module.exports = function (grunt) {
9090
return $hash.digest('hex');
9191
}
9292

93+
/**
94+
* Check if the mask if a function.
95+
*
96+
* @param $mask (string)
97+
* @returns {boolean}
98+
*/
99+
function isMaskFunction($mask) {
100+
return ($mask.substr(0, 1) === '{' && $mask.substr(-1) === '}');
101+
}
102+
103+
/**
104+
* Trim the curly braces from the mask function.
105+
*
106+
* @param $mask (string}
107+
* @returns {string}
108+
*/
109+
function trimMaskFunction($mask) {
110+
return $mask.slice(1, -1);
111+
}
112+
113+
/**
114+
* Check for a valid mask function.
115+
*
116+
* @param $maskFunction {string}
117+
* @param $maskFunctions {array}
118+
* @returns {boolean}
119+
*/
120+
function isValidMaskFunction($maskFunction, $maskFunctions) {
121+
return ($maskFunctions.indexOf($maskFunction)) > -1;
122+
}
123+
93124
/**
94125
* Get mask value.
95126
*
96-
* @param $maskType {string}
97-
* @param $file {string}
127+
* @param $mask {string}
128+
* @param $file {string}
98129
* @returns {string}
99130
*/
100-
function getMaskValue($maskType, $file) {
101-
// If using a timestamp.
102-
if ($maskType === '{timetsmap}') {
103-
return getTimeStamp.toString();
104-
}
131+
function getMaskValue($mask, $file) {
132+
// Check if a mask function is being used.
133+
if (isMaskFunction($mask)) {
134+
// Trim the curly braces from the mask function.
135+
$mask = trimMaskFunction($mask);
136+
137+
// If using a timestamp.
138+
if ($mask === 'timestamp') {
139+
return getTimeStamp().toString();
140+
}
105141

106-
// If using a datetime stamp.
107-
if($maskType === '{datetimestamp}') {
108-
return getDateTimeStamp();
109-
}
142+
// If using a datetime stamp.
143+
if ($mask === 'datetimestamp') {
144+
return getDateTimeStamp();
145+
}
110146

111-
// If using an OpenSSL digest algorithm.
112-
if (/{.*}/.test($maskType)) {
113-
return getHash($file, $maskType.replace(new RegExp(/[{}]/, 'g'), ""));
147+
// Using an OpenSSL digest algorithm.
148+
return getHash($file, $mask);
114149
}
115150

116151
// Just a string.
117-
return $maskType;
152+
return $mask;
118153
}
119154

120155
/**
@@ -143,13 +178,13 @@ module.exports = function (grunt) {
143178
// Iterate over the asset filename(s).
144179
for (var i = 0; i < $files.length; i++) {
145180
// Check if the pre and post strings match the start and end parts of the asset filename respectively.
146-
if ($pre === $files[i].substring(0, $pre.length) && $post === $files[i].substring($files[i].length - $post.length)) {
147-
// A match was found.
181+
if ($pre === $files[i].substr(0, $pre.length) && $post === $files[i].substr(-$post.length)) {
182+
// A matching asset was found.
148183
return $files[i];
149184
}
150185
}
151186

152-
// A match was not found.
187+
// A matching asset was not found.
153188
return null;
154189
}
155190

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

177-
// Validate the options.
212+
// Set the valid mask functions types.
213+
var $validMaskFunctionTypes = ['timestamp', 'datetimestamp'].concat(crypto.getHashes()).sort(function (a, b) {
214+
return a.localeCompare(b, undefined, {sensitivity: 'base'});
215+
});
216+
217+
// Validate the options types.
178218
for (var $key in $validOptionsTypes) {
179219
// Check if the option type is incorrect.
180220
if (typeof ($options[$key]) !== $validOptionsTypes[$key]) {
181-
grunt.fail.warn('cacheKiller -> ' + this.target + ' -> options -> ' + $key + ' must be a ' + $validOptionsTypes[$key] + '. ' + typeof ($options[$key]) + ' given.');
221+
// Capitalise the first letter.
222+
var $type = typeof ($options[$key]);
223+
$type = $type.charAt(0).toUpperCase() + $type.slice(1);
224+
225+
grunt.fail.warn(this.target + ' : The option \'' + $key + '\' must be a ' + $validOptionsTypes[$key] + '. ' + $type + ' given.');
182226
}
183227
}
184228

229+
// Validate the mask function type.
230+
if (isMaskFunction($options.mask) && !isValidMaskFunction(trimMaskFunction($options.mask), $validMaskFunctionTypes)) {
231+
grunt.fail.warn(this.target + ' : The options mask \'' + $options.mask + '\' is not a valid mask. Valid masks include ' + $validMaskFunctionTypes.join(', ') + '.');
232+
}
233+
185234
// Build the tasks list.
186235
var $tasks = {};
187236

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

254+
// Check the position of the mask placeholder within the asset filename.
255+
if ($tasks[i].asset.name.pre === '' || $tasks[i].asset.name.post === '') {
256+
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.');
257+
}
258+
205259
$tasks[i].asset.rename.from.file = findMatchingAsset($tasks[i].asset.name.base, $tasks[i].asset.name.pre, $tasks[i].asset.name.post);
206260
$tasks[i].asset.rename.from.full = $tasks[i].asset.name.base + $tasks[i].asset.rename.from.file;
207261

262+
// Check if the asset filename exists.
263+
if ($tasks[i].asset.rename.from.file === null) {
264+
grunt.fail.warn(this.target + ' : The masked asset file \'' + $tasks[i].asset.name.full + '\' does not exist.');
265+
}
266+
208267
$tasks[i].asset.mask.prepend = $options.prepend;
209268
$tasks[i].asset.mask.value = {};
210269
$tasks[i].asset.mask.value.raw = getMaskValue($options.mask, $tasks[i].asset.rename.from.full);
@@ -217,30 +276,22 @@ module.exports = function (grunt) {
217276

218277
// Let's begin.
219278
grunt.log.writeln('');
220-
grunt.log.writeln('-----------');
221-
grunt.log.writeln('cacheKiller');
222-
grunt.log.writeln('-----------');
223279

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

227-
// Check if the asset file exists.
228-
if ($tasks[j].asset.rename.from.full === null) {
229-
grunt.fail.warn('cacheKiller -> ' + this.target + ' : The masked asset file \'' + $tasks[j].asset.name.full + '\' does not exist.');
230-
}
231-
232-
// Check if the template file(s) exist.
283+
// Check if the template filename(s) exist.
233284
for (var k = 0; k < $tasks[j].templates.length; k++) {
234285
if (!fileSystem.existsSync($tasks[j].templates[k])) {
235-
grunt.fail.warn('cacheKiller -> ' + this.target + ' : The template file \'' + $tasks[j].templates[k] + '\' does not exist.');
286+
grunt.fail.warn(this.target + ' : The template file \'' + $tasks[j].templates[k] + '\' does not exist.');
236287
}
237288
}
238289

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

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

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

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

261312
// Add line between target(s) and goodbye.

0 commit comments

Comments
 (0)