Grunt task for making sure you have copyrights on each file - gruntjs

I need to make sure there's copyrights notice at the beginning of each file.
How can I use grunt to fail my build in case the copyrights statement is missing?

First of all, I'm assuming you are referring to *.js or *.html or other similar work files, and not to graphic or binary files.
This can be done, with a grunt.registerTask which will:
1. loop through all relevant files
2. Read and compare first line to copyright line
3. If different - re-write file but a new first line which will be the copyright info
Pretty simple. Again - this will not work on binary files. I wrote this for you but it seems very useful, I might consider adding it as a plugin. Field tested:
run it by grunt verifyCopyright and also make sure that if your files are in a different directory your change it, and also if you want to process other files add them to the list as well. good luck...
grunt.registerTask('verifyCopyright', function () {
var fileRead, firstLine, counter = 0, fileExtension, commentWrapper;
copyrightInfo = 'Copyright by Gilad Peleg #2013';
//get file extension regex
var re = /(?:\.([^.]+))?$/;
grunt.log.writeln();
// read all subdirectories from your modules folder
grunt.file.expand(
{filter: 'isFile', cwd: 'public/'},
["**/*.js", ['**/*.html']])
.forEach(function (dir) {
fileRead = grunt.file.read('public/' + dir).split('\n');
firstLine = fileRead[0];
if (firstLine.indexOf(copyrightInfo > -1)) {
counter++;
grunt.log.write(dir);
grunt.log.writeln(" -->doesn't have copyright. Writing it.");
//need to be careful about:
//what kind of comment we can add to each type of file. i.e /* <text> */ to js
fileExtension = re.exec(dir)[1];
switch (fileExtension) {
case 'js':
commentWrapper = '/* ' + copyrightInfo + ' */';
break;
case 'html':
commentWrapper = '<!-- ' + copyrightInfo + ' //-->';
break;
default:
commentWrapper = null;
grunt.log.writeln('file extension not recognized');
break;
}
if (commentWrapper) {
fileRead.unshift(commentWrapper);
fileRead = fileRead.join('\n');
grunt.file.write( 'public/' + dir, fileRead);
}
}
});
grunt.log.ok('Found', counter, 'files without copyright');
})

Instead of checking to see if it's there and failing, why not just have a task that automatically injects it? See grunt-banner.

https://github.com/thekua/grunt-regex-check could be what you want. You define the regex to check for and if it finds it then the task fails.

Related

SyntaxError: Parse error - Wkhtmltopdf with react-pdf-js lib

I am using wkhtmltopdf version 0.12.2.1 (with patched qt) to render my reactJs app! It worked fine, until I added the react-pdf-js lib to render the pdf generated inside my app. I followed the code described on react-pdf-js documentation (see https://www.npmjs.com/package/react-pdf-js) to make it work.
The pdf is rendered inside my page, and it looks pretty cool indeed. But when I try to run wkhtmltopdf again, to generate a pdf of any page of my app, the following error is returned:
desenv01#desenv01-PC:~$ wkhtmltopdf -O Landscape --print-media-type --debug-javascript http://localhost:3000/report/1 report.pdfLoading pages (1/6)
Warning: undefined:0 ReferenceError: Can't find variable: Float64Array
Warning: http://localhost:3000/assets/js/app.js:46789 SyntaxError: Parse error
Counting pages (2/6)
Resolving links (4/6)
Loading headers and footers (5/6)
Printing pages (6/6)
Done
Then, I went to my app.js to see what's on line 46789:
set href(href) {
clear.call(this);
parse.call(this, href);
},
get protocol() {
return this._scheme + ':';
},
set protocol(protocol) {
if (this._isInvalid)
return;
parse.call(this, protocol + ':', 'scheme start');
},
The error happens on the line that says parse.call(this, href);, which is part of pdf.combined.js script.
I could not find any solution online so I wondered if there is anyone who might know if I did something wrong or a way to work around it.
Thanks..
I ran into this using wkthmltopdf 12.3 and 12.4 because I have my IDE set to nag me for using var instead of let. The problem is the older Qt engine powering those versions of the program doesn't recognize new-style, ES6 keywords. Not sure if you can down-convert React. Otherwise you can try the bleeding edge versions which use a newer Qt.
I have same problem. I fixed it by modify some code that i think it is new in JS. let keyword (ES5) and template literals (ES6).
generateRandomColor= function () {
let maxVal = 0xFFFFFF; // 16777215
let randomNumber = Math.random() * maxVal;
randomNumber = Math.floor(randomNumber);
randomNumber = randomNumber.toString(16);
let randColor = randomNumber.padStart(6, 0);
return `#${randColor.toUpperCase()}`
}
I modify above code into below
generateRandomColor = function () {
var maxVal = 0xFFFFFF;
var randomNumber = Math.random() * maxVal;
randomNumber = Math.floor(randomNumber);
randomNumber = randomNumber.toString(16);
var randColor = randomNumber.padStart(6, 0);
return "#" + randColor.toUpperCase();
}

Getting errors when Browsery bundle with SquishIt

I am currently refactoring the javascript portions of a web site, and now I have bundled some scripts together using Browserify. The resulting script is bundled along with other resources using SquishIt. In Debug mode, when SquishIt is not bundling all the scripts together everything seems to work just fine, but when running in Production, and SquishIt bundles everything together I get errors from the Browserify part of my bundle. The error is complaining that r has no length property (see line 18) below. This part of the code is created by Browserify when bundling the scripts.
(function e(t, n, r) {
function s(o, u) {
if (!n[o]) {
if (!t[o]) {
var a = typeof require == "function" && require;
if (!u && a) return a(o, !0);
if (i) return i(o, !0);
var f = new Error("Cannot find module '" + o + "'");
throw f.code = "MODULE_NOT_FOUND", f
}
var l = n[o] = {
exports: {}
};
t[o][0].call(l.exports, function(e) {
var n = t[o][1][e];
return s(n ? n : e)
}, l, l.exports, e, t, n, r)
}
return n[o].exports
}
var i = typeof require == "function" && require;
for (var o = 0; o < r.length; o++) s(r[o]);
return s
})({
I really can't think of anything that using SquishIt to bundle all the scripts would break the logic of the browserified scripts. What could be the cause of this? This gist shows the entire source code, in case that is relevant.
I have not changed anything on the ASP.NET side (in the bundling), and the relevant part of my ´Head.ascx´ looks like this:
Bundle.JavaScript()
.Add(Assets.JavaScript.GetUrl("main.js").ToString())
.Add(Assets.JavaScript.GetUrl("Plugins/raphael-min.js").ToString())
.Add(Assets.JavaScript.GetUrl("Plugins/vector_map.js").ToString())
// more ...
.Render("~/Content/"+Assets.VersionString+"/Scripts/Combined/combined.js")
Have a look at this comment it may help https://github.com/jetheredge/SquishIt/issues/320#issuecomment-139921409
Is there a reason you need to use two different bundling solutions?

It is possible to compile less file to less with compression and without comments?

i have much more less files that are imported in a main.less file. Now i wanna to make a main.min.less file with imported files and compressed and without any comments. what command i used is:
lessc main.less > main.min.less -x
This command compress the file but can't remove the restricted comments(/*! comments */).
Keep in mind i wanna to make another .less file and not .css file. Any idea?
Because of Less code is very similar to CSS code, you should be able to (re)use many methods of for instance clean-css.
Create a file called clean-less and write down the following content into it:
#!/usr/bin/env node
var path = require('path'),
CommentsProcessor = require('clean-css/lib/text/comments'),
fs = require('fs');
var args = process.argv.slice(1);
var input = args[1];
if (input && input != '-') {
input = path.resolve(process.cwd(), input);
}
var parseFile = function (e, data) {
var lineBreak = process.platform == 'win32' ? '\r\n' : '\n';
var commentsProcessor = new CommentsProcessor(0,false,lineBreak);
//single line comments
var regex = /\/\/ .*/;
data = data.replace(/\/{2,}.*/g,"");
/*
methods from clean css, see https://github.com/jakubpawlowicz/clean-css/
*/
var replace = function() {
if (typeof arguments[0] == 'function')
arguments[0]();
else
data = data.replace.apply(data, arguments);
};
//multi line comments
replace(function escapeComments() {
data = commentsProcessor.escape(data);
});
// whitespace inside attribute selectors brackets
replace(/\[([^\]]+)\]/g, function(match) {
return match.replace(/\s/g, '');
});
// line breaks
replace(/[\r]?\n/g, ' ');
// multiple whitespace
replace(/[\t ]+/g, ' ');
// multiple semicolons (with optional whitespace)
replace(/;[ ]?;+/g, ';');
// multiple line breaks to one
replace(/ (?:\r\n|\n)/g, lineBreak);
replace(/(?:\r\n|\n)+/g, lineBreak);
// remove spaces around selectors
replace(/ ([+~>]) /g, '$1');
// remove extra spaces inside content
replace(/([!\(\{\}:;=,\n]) /g, '$1');
replace(/ ([!\)\{\};=,\n])/g, '$1');
replace(/(?:\r\n|\n)\}/g, '}');
replace(/([\{;,])(?:\r\n|\n)/g, '$1');
replace(/ :([^\{\};]+)([;}])/g, ':$1$2');
process.stdout.write(data);
}
if (input != '-') {
fs.readFile(input, 'utf8', parseFile);
}
Than make the clean-less file executable on your system (chmod +x clean-css).
You should probably also run npm install path and npm install css. After that you should be able to run:
./cleanless input.less > input-clean.less
The input-clean.less file will be some kind of minimized and not contain comments any more.
In the comments #seven-phases-max wonders if minifying reduces client side compile time. Well the client side compiler loads the Less files over a XMLHttpRequest. Reduce the number of bytes will give faster loading. I can not say that is a bottleneck or not.
When i try the above code with the navbar.less file from Bootstrap i found:
8.0K navbar-clean.less
16K navbar.less

Batch for downloading most recent file (where filename changes on new version) from http website

i need a batch for downloading files from a http website (http://www.rarlab.com/download.htm).
From this website i only need the most recent version for the 32bit and 64bit english
program which is always listed at the top of this website.
Problem 1: There are more than this two files for download on the website
Problem 2: The name of the file changes with every new version
How can i download these 2 files (the most recent version) without knowing the exact file name
(and without first visiting the web page to find out the file name) ??
Maybe i can use wget, curl or aria2 for that task but i don't know the parameters/options.
Can anyone help me solving this problem ?
(Please only batch solutions - no vbs, java, jscript, powershell etc.)
thank you.
Sorry, i forgot to say that i use windows 7 32bit. And i prefer batch because the script should be able to run on all windows versions without having to download extra programs or resource kits for different windows version (as of powershell which must be downloaded for windows xp etc.) - and because i only understand batch scripting.
Here's a batch + JScript hybrid script. I know you said no vbs, java, jscript, etc, but you're going to have an awfully hard time scraping HTML with pure batch. But this does meet your other criteria -- running on all Windows versions without having to rely on optional software (like powershell or .Net).* And with JScript's XMLHTTP object you don't even need a 3rd party app to fetch web content.
As for not understanding JScript, aside from a few proprietary ActiveX objects it's just like JavaScript. In case you aren't familiar with JavaScript or regular expressions, I added copious amounts of comments to help you out. Hopefully whatever I didn't bother commenting is pretty obvious what it does.
Update
The script now detects the system locale, matches it with a language on the WinRAR download page, and downloads that language release.
Anyway, save this with a .bat extension and run it as you would any other batch script.
#if (#a==#b) #end /*
:: batch script portion
#echo off
setlocal
set "url=http://www.rarlab.com/download.htm"
set /p "savepath=Location to save? [%cd%] "
if "%savepath%"=="" set "savepath=%cd%"
cscript /nologo /e:jscript "%~f0" "%url%" "%savepath%"
goto :EOF
:: JScript portion */
// populate translation from locale identifier hex value to WinRAR language label
// http://msdn.microsoft.com/en-us/library/dd318693.aspx
var abbrev={}, a=function(arr,val){for(var i=0;i<arr.length;i++)abbrev[arr[i]]=val};
a(['1401','3c01','0c01','0801','2001','4001','2801','1c01','3801','2401'],'Arabic');
a(['042b'],'Armenian');
a(['082c','042c'],'Azerbaijani');
a(['0423'],'Belarusian');
a(['0402'],'Bulgarian');
a(['0403'],'Catalan');
a(['7c04'],'Chinese Traditional');
a(['0c04','1404','1004','0004'],'Chinese Simplified');
a(['101a'],'Croatian');
a(['0405'],'Czech');
a(['0406'],'Danish');
a(['0813','0413'],'Dutch');
a(['0425'],'Estonian');
a(['040b'],'Finnish');
a(['080c','0c0c','040c','140c','180c','100c'],'French');
a(['0437'],'Georgian');
a(['0c07','0407','1407','1007','0807'],'German');
a(['0408'],'Greek');
a(['040d'],'Hebrew');
a(['040e'],'Hungarian');
a(['0421'],'Indonesian');
a(['0410','0810'],'Italian');
a(['0411'],'Japanese');
a(['0412'],'Korean');
a(['0427'],'Lithuanian');
a(['042f'],'Macedonian');
a(['0414','0814'],'Norwegian');
a(['0429'],'Persian');
a(['0415'],'Polish');
a(['0816'],'Portuguese');
a(['0416'],'Portuguese Brazilian');
a(['0418'],'Romanian');
a(['0419'],'Russian');
a(['7c1a','1c1a','0c1a'],'Serbian Cyrillic');
a(['181a','081a'],'Serbian Latin');
a(['041b'],'Slovak');
a(['0424'],'Slovenian');
a(['2c0a','400a','340a','240a','140a','1c0a','300a','440a','100a','480a','080a','4c0a','180a','3c0a','280a','500a','0c0a','040a','540a','380a','200a'],'Spanish');
a(['081d','041d'],'Swedish');
a(['041e'],'Thai');
a(['041f'],'Turkish');
a(['0422'],'Ukranian');
a(['0843','0443'],'Uzbek');
a(['0803'],'Valencian');
a(['042a'],'Vietnamese');
function language() {
var os = GetObject('winmgmts:').ExecQuery('select Locale from Win32_OperatingSystem');
var locale = new Enumerator(os).item().Locale;
// default to English if locale is not in abbrev{}
return abbrev[locale.toLowerCase()] || 'English';
}
function fetch(url) {
var xObj = new ActiveXObject("Microsoft.XMLHTTP");
xObj.open("GET",url,true);
xObj.setRequestHeader('User-Agent','XMLHTTP/1.0');
xObj.send('');
while (xObj.readyState != 4) WSH.Sleep(50);
return(xObj);
}
function save(xObj, file) {
var stream = new ActiveXObject("ADODB.Stream");
with (stream) {
type = 1; // binary
open();
write(xObj.responseBody);
saveToFile(file, 2); // overwrite
close();
}
}
// fetch the initial web page
var x = fetch(WSH.Arguments(0));
// make HTML response all one line
var html = x.responseText.split(/\r?\n/).join('');
// create array of hrefs matching *.exe where the link text contains system language
var r = new RegExp('<a\\s*href="[^"]+\\.exe(?=[^\\/]+' + language() + ')', 'g');
var anchors = html.match(r)
// use only the first two
for (var i=0; i<2; i++) {
// use only the stuff after the quotation mark to the end
var dl = '' + /[^"]+$/.exec(anchors[i]);
// if the location is a relative path, prepend the domain
if (dl.substring(0,1) == '/') dl = /.+:\/\/[^\/]+/.exec(WSH.Arguments(0)) + dl;
// target is path\filename
var target=WSH.Arguments(1) + '\\' + /[^\/]+$/.exec(dl)
// echo without a new line
WSH.StdOut.Write('Saving ' + target + '... ');
// fetch file and save it
save(fetch(dl), target);
WSH.Echo('Done.');
}
Update 2
Here's the same script with a few minor tweaks to have it also detect the architecture (32/64-bitness) of Windows, and only download one installer instead of two:
#if (#a==#b) #end /*
:: batch script portion
#echo off
setlocal
set "url=http://www.rarlab.com/download.htm"
set /p "savepath=Location to save? [%cd%] "
if "%savepath%"=="" set "savepath=%cd%"
cscript /nologo /e:jscript "%~f0" "%url%" "%savepath%"
goto :EOF
:: JScript portion */
// populate translation from locale identifier hex value to WinRAR language label
// http://msdn.microsoft.com/en-us/library/dd318693.aspx
var abbrev={}, a=function(arr,val){for(var i=0;i<arr.length;i++)abbrev[arr[i]]=val};
a(['1401','3c01','0c01','0801','2001','4001','2801','1c01','3801','2401'],'Arabic');
a(['042b'],'Armenian');
a(['082c','042c'],'Azerbaijani');
a(['0423'],'Belarusian');
a(['0402'],'Bulgarian');
a(['0403'],'Catalan');
a(['7c04'],'Chinese Traditional');
a(['0c04','1404','1004','0004'],'Chinese Simplified');
a(['101a'],'Croatian');
a(['0405'],'Czech');
a(['0406'],'Danish');
a(['0813','0413'],'Dutch');
a(['0425'],'Estonian');
a(['040b'],'Finnish');
a(['080c','0c0c','040c','140c','180c','100c'],'French');
a(['0437'],'Georgian');
a(['0c07','0407','1407','1007','0807'],'German');
a(['0408'],'Greek');
a(['040d'],'Hebrew');
a(['040e'],'Hungarian');
a(['0421'],'Indonesian');
a(['0410','0810'],'Italian');
a(['0411'],'Japanese');
a(['0412'],'Korean');
a(['0427'],'Lithuanian');
a(['042f'],'Macedonian');
a(['0414','0814'],'Norwegian');
a(['0429'],'Persian');
a(['0415'],'Polish');
a(['0816'],'Portuguese');
a(['0416'],'Portuguese Brazilian');
a(['0418'],'Romanian');
a(['0419'],'Russian');
a(['7c1a','1c1a','0c1a'],'Serbian Cyrillic');
a(['181a','081a'],'Serbian Latin');
a(['041b'],'Slovak');
a(['0424'],'Slovenian');
a(['2c0a','400a','340a','240a','140a','1c0a','300a','440a','100a','480a','080a','4c0a','180a','3c0a','280a','500a','0c0a','040a','540a','380a','200a'],'Spanish');
a(['081d','041d'],'Swedish');
a(['041e'],'Thai');
a(['041f'],'Turkish');
a(['0422'],'Ukranian');
a(['0843','0443'],'Uzbek');
a(['0803'],'Valencian');
a(['042a'],'Vietnamese');
function language() {
var os = GetObject('winmgmts:').ExecQuery('select Locale from Win32_OperatingSystem');
var locale = new Enumerator(os).item().Locale;
// default to English if locale is not in abbrev{}
return abbrev[locale.toLowerCase()] || 'English';
}
function fetch(url) {
var xObj = new ActiveXObject("Microsoft.XMLHTTP");
xObj.open("GET",url,true);
xObj.setRequestHeader('User-Agent','XMLHTTP/1.0');
xObj.send('');
while (xObj.readyState != 4) WSH.Sleep(50);
return(xObj);
}
function save(xObj, file) {
var stream = new ActiveXObject("ADODB.Stream");
with (stream) {
type = 1; // binary
open();
write(xObj.responseBody);
saveToFile(file, 2); // overwrite
close();
}
}
// fetch the initial web page
var x = fetch(WSH.Arguments(0));
// make HTML response all one line
var html = x.responseText.split(/\r?\n/).join('');
// get OS architecture (This method is much faster than the Win32_Processor.AddressWidth method)
var os = GetObject('winmgmts:').ExecQuery('select OSArchitecture from Win32_OperatingSystem');
var arch = /\d+/.exec(new Enumerator(os).item().OSArchitecture) * 1;
// get link matching *.exe where the link text contains system language and architecture
var r = new RegExp('<a\\s*href="[^"]+\\.exe(?=[^\\/]+' + language() + '[^<]+' + arch + '\\Wbit)');
var link = r.exec(html)
// use only the stuff after the quotation mark to the end
var dl = '' + /[^"]+$/.exec(link);
// if the location is a relative path, prepend the domain
if (dl.substring(0,1) == '/') dl = /.+:\/\/[^\/]+/.exec(WSH.Arguments(0)) + dl;
// target is path\filename
var target=WSH.Arguments(1) + '\\' + /[^\/]+$/.exec(dl)
// echo without a new line
WSH.StdOut.Write('Saving ' + target + '... ');
// fetch file and save it
save(fetch(dl), target);
WSH.Echo('Done.');

How to remove the full file path from YSOD?

In the YSOD below, the stacktrace (and the source file line) contain the full path to the source file. Unfortunately, the full path to the source file name contains my user name, which is firstname.lastname.
I want to keep the YSOD, as well as the stack trace including the filename and line number (it's a demo and testing system), but the username should vanish from the sourcefile path. Seeing the file's path is also OK, but the path should be truncated at the solution root directory.
(without me having to copy-paste the solution every time to another path before publishing it...)
Is there any way to accomplish this ?
Note: Custom error pages aren't an option.
Path is embedded in .pdb files, which are produced by the compiler. The only way to change this is to build your project in some other location, preferably somewhere near the build server.
Never mind, I found it out myself.
Thanks to Anton Gogolev's statement that the path is in the pdb file, I realized it is possible.
One can do a binary search-and-replace on the pdb file, and replace the username with something else.
I quickly tried using this:
https://codereview.stackexchange.com/questions/3226/replace-sequence-of-strings-in-binary-file
and it worked (on 50% of the pdb files).
So mind the crap, that code-snippet in the link seems to be buggy.
But the concept seems to work.
I now use this code:
public static void SizeUnsafeReplaceTextInFile(string strPath, string strTextToSearch, string strTextToReplace)
{
byte[] baBuffer = System.IO.File.ReadAllBytes(strPath);
List<int> lsReplacePositions = new List<int>();
System.Text.Encoding enc = System.Text.Encoding.UTF8;
byte[] baSearchBytes = enc.GetBytes(strTextToSearch);
byte[] baReplaceBytes = enc.GetBytes(strTextToReplace);
var matches = SearchBytePattern(baSearchBytes, baBuffer, ref lsReplacePositions);
if (matches != 0)
{
foreach (var iReplacePosition in lsReplacePositions)
{
for (int i = 0; i < baReplaceBytes.Length; ++i)
{
baBuffer[iReplacePosition + i] = baReplaceBytes[i];
} // Next i
} // Next iReplacePosition
} // End if (matches != 0)
System.IO.File.WriteAllBytes(strPath, baBuffer);
Array.Clear(baBuffer, 0, baBuffer.Length);
Array.Clear(baSearchBytes, 0, baSearchBytes.Length);
Array.Clear(baReplaceBytes, 0, baReplaceBytes.Length);
baBuffer = null;
baSearchBytes = null;
baReplaceBytes = null;
} // End Sub ReplaceTextInFile
Replace firstname.lastname with something that has equally many characters, for example "Poltergeist".
Now I only need to figure out how to run the binary search and replace as a post-build action.

Resources