How can I trigger an error from inside gulp-esdoc? - javascript

I am using gulp-esdoc to generate my documentation (and it already works).
Today I added a git pre-commit hook, it launches multiples gulp tasks and prevent any commit if one of the tasks returns an error.
I works for most of my tasks, but for gulp-esdoc, I don't know how to return such an error to prevent the commit.
I configured my esdoc this way :
gulp.task('documentation', function() {
gulp.src("./client/")
.pipe(esdoc({
destination: "./docs",
"title": "SOMETHING",
index: "./README.md",
"plugins": [{
"name": "./README/docplugins/on-complete.js"
}]
}));
});
As you can see, I am using an esdoc plugin to do some code once the documentation has been generated, here is the code for the plugin :
var colors = require('colors'),
gutil = require('gulp-util');
exports.onComplete = function(ev) {
var output = require('../../docs/coverage.json');
var expectedCoverage = 100; // todo : get from option instead
var percentCovered = (output.actualCount / output.expectCount) * 100;
if (percentCovered < expectedCoverage) {
console.log('Code coverage is not sufficient (expected ' + expectedCoverage + '%, received only ' + percentCovered + '%) !!! Write some documentation or get out !'.red);
// return false; // todo
} else {
console.log('Code coverage is complete, well done :)'.green);
// return true;
}
};
The main goal here is to return an error if my code documentation is not 100% covered (the code logic is working, if a comment is missing in my JS code, I go into the line with the "todo".
Finally, here is my (simplified) git-hook (in my gulpfile) :
gulp.task('pre-commit', function () {
gulp.start('lint');
gulp.start('documentation');
});
The 'lint' part works, it prevent commit if I have an error in my code. But the 'documentation' code, using gulp-esdoc, doesn't return any error, so the commit is done :( I don't know what to do to return an error and prevent the git commit.
I need to do this because I want the junior developers joining my team to be forced to document their code :p
Thanks for helping !

One option is to throw a PluginError:
throw new gutil.PluginError('esdoc', 'Something broke');
This will cause your gulp process to exit with a non-zero exit code. It will however leave a rather ugly stack trace on STDERR (especially since gulp-esdoc rethrows errors from plugins).
Another option then is to explicitly exit the process with a specific exit code:
process.exit(1);
The process object in Node.js is a global object and can be accessed from anywhere without having to require() it.

Related

Accessing data parsed by readline & fs in node.js outside of the callback function

This question is different from the one linked as already having an answer. It is specifically this piece of code adapted from node.js documentation regarding the use of fs and readfile and looking for an end of file flag, which I've learned is readfile.close method. Thanks for the answer.
I wrote a small utility locally to try to convert a text file of key:value pairs with a blank line separating programs into a JSON file to use in a React project.
I got the foundation of the readline function directly from node.js documentation. I'm using node 6.9.0 on my mac
here is the full script:
const readline = require('readline');
const fs = require('fs');
const rl = readline.createInterface({
input: fs.createReadStream('usat-ncaa-programs.txt')
});
var newPairs=["test"];
rl.on('line',
function (line) {
if (line===null){
newPairs.push("}], [ {")
} else if (line) {
var keyValue = line.match(/^(.*):(.*)/)
var newKeyValuePair = "'" + keyValue[1].trim() + "': '" + keyValue[2].trim() + "'"
newPairs.push(newKeyValuePair)
//console.log (newKeyValuePair)
}
})
console.log(newPairs)
The input file looks like this (there are about 12 programs), i've only included 2 1/2 so you can see the format:
University: Arizona State University
Division: I
University Home Page: http://www.asu.edu/
Recruiting Link: https://questionnaire.acsathletics.com/Questionnaire/Questionnaire.aspx?&SPSID=1061112&SPID=177408&DB_LANG=C&DB_OEM_ID=30300&q=2015&s=159130&o=143
Team Homepage: http://www.thesundevils.com/index.aspx?path=triathlon
Head Coach: Cliff English
w: 480.965.0546
e: cliff.endlish#asu.edu
bg-color: #990033
color: #FFB310
University: Belmont Abby College
Division: II
University Home Page: http://belmontabbeycollege.edu/
Recruiting Link: https://coach.scoutforce.com/p/414f3219dd
Team Homepage: http://abbeyathletics.com/sports/wtri/index
Head Coach: Nick Radkewich
w: 704.461.5010
e: NicholasRadewich#bac.edu
Twitter: https://twitter.com/AbbeyTri
bg-color: #FFFDD0
color: #DC143C
University:Black Hills State University
Division: II
University Home Page: http://www.bhsu.edu/
...
My problem is that while I can read the text file line by line and parse some information that looks like a JSON file, I am unable to access that data outside of the callback function.
I don't know how to save this data into a new file, or even just output the object to my console for a cut & paste and manually edit.
In teh above script the logged output of the variable newPairs is ["test"] rather than the line by line parsing that I'm trying to acccomplish.
If I place the console.log inside the callback, I get information logged with every iteration of the file read. I only want to work with the data when the file is done.
I did not find an EOF or similar flag in the node documentation for either fs or readline.
Additionally, if there is an easier way to get the data I am inputting into JSON format, I'd love to hear. Thanks in advance.
You have to understand that the callback function is executed asynchronously. This means that console.log(newPairs) gets executed before your callback, therefore it only results in "test".
You should listen to Readline's close event, like so:
rl.on('close', function() {
console.log(newPairs);
});
As the documentation states:
The 'close' event is emitted when one of the following occur:
The rl.close() method is called and the readline.Interface instance
has relinquished control over the input and output streams;
The input stream receives its 'end' event; The input stream receives -D to signal end-of-transmission (EOT);
The input stream receives -C to signal SIGINT and there is no SIGINT event listener registered on the readline.Interface instance.
The listener function is called without passing any arguments.
The readline.Interface instance should be considered to be "finished"
once the 'close' event is emitted.
So this would be the 'EOF' you're looking for :-)
i know its an old question but the answer didn't help me. You can use an promisse like this:
function readLineAsync(){
var data = [];
var i = 0;
return new Promise((resolve,reject)=>{
var lineRead = readLine.createInterface({
input:fs.createReadStream('path.to.file')
})
lineRead.on('line',(line)=>{
data[i] = line;
i++;
})
lineRead.on('close',()=>{
resolve(dataCsv);
})
})
}
(async function(){ console.log(await readLineAsync())}())

Error during synchronous write using Node.js

I have written code that parses a dictionary returned from Firebase containing images encoded using base64. I want it to simply write these images to file, and it does, but I receive the following error after my writes finish:
smalloc.cc:280: void node::smalloc::SliceOnto(const v8::FunctionCallbackInfo<v8::Value>&): Assertion `end <= source_len' failed.
This is my code:
// Iterate through each key in each page if each request
for (var key in request) {
var obj = request[key];
if (typeof (obj) == "object") {
for (var prop in obj) {
item++;
if(obj.hasOwnProperty(prop)) {
switch (prop) {
case "img":
var media = new ReceivedMedia(obj[prop]);
var filename = transaction.tid + "-" + item + "." + media.extension;
filename = filename.slice(10);
require('fs').writeFileSync(filename, media.b64, 'base64', function(err) {
if (err) throw err;
});
break;
}
}
}
}
}
My images come out fine, but the error is a little weird and I would prefer to not to occur. Would anyone have an idea as to why this is happening? That would be super helpful :)
Note: ReceivedMedia is a class I defined as:
function ReceivedMedia(media) {
this.b64 = media.b64;
this.extension = media.extension;
this.posx = media.posx;
this.posy = media.posy;
}
Side question: If I use writeFile instead of writeFileSync one of my images is corrupted and the other contains no data. If after that happens I run my node script again, the files save correctly. I would also like some explanation as to why that happens, from my understanding one of these is synchronous (writeFileSync I am guessing) and the other is asynchronous (writeFile I am assuming).
A Google search for your error message description found this discussion of the issue in io.js and this discussion in node.js and it sounds like it is a bug that has been fixed (not sure if the fix has been released in a full build yet).
The node.js fix is here.
If you were desparate to fix it now in your own build, you'd have to apply the fix to your own code tree and rebuild it. Otherwise, you'll have to investigate or inquire when this fix will get into an official release (I'm not personally sure how that process works for node.js).

Windows 8 Metro Inapp purchases for Dummies

am ready to deploy my second windows 8 metro style javascript app and i would love to include in app purchases.
I tried implementing it with the following code i got from here
http://msdn.microsoft.com/en-us/library/windows/apps/hh694067.aspx
function appInit()
{
// some app initialization functions
// Get current product object
// Execute only one of these statements.
// The next line is commented out for testing.
// currentApp = Windows.ApplicationModel.Store.CurrentApp;
// The next line is commented out for production/release.
currentApp = Windows.ApplicationModel.Store.CurrentAppSimulator;
// We should have either a real or a simulated CurrentProduct object here.
// Get the license info
licenseInformation = currentApp.licenseInformation;
// other app initializations function
}
function buyFeature1() {
if (!licenseInformation.productLicenses.lookup("featureName").isActive)
{
currentApp.requestProductPurchaseAsync("featureName", false).then(
function () {
// the in-app purchase was successful
},
function () {
// The in-app purchase was not completed because // there was an error.
});
}
else
{
// The customer already owns this feature.
}
}
But nothing seems to happen.i know this is a novice question. but i'l be glad if someone can provide a full simple working solution.Btw i've read the docs and downloaded the sample.i also have my storeproxy.xml file setup.
You might try changing:
currentApp.requestProductPurchaseAsync("featureName", false).then(
Into:
currentApp.requestProductPurchaseAsync("featureName", false).done(
That is what I use and it works for me.

Tridion 2011 SP1 : Tridion GUI Javascript error with Translation Manager and Powertools 2011 installed

I recently installed Tridion 2011 SP1 with SDL module Translation Manager enabled.
Everything was working fine. Then I installed the Tridion 2011 Powertools, following the installation procedure.
When trying to reload the GUI (browser cache emptied and modification parameter instanciated for server element in WebRoot\Configuration\System.Config) I'm getting the following Javascript error :
SCRIPT5007: Unable to get value of the property 'getItemType': object is null or undefined
Dashboard_v6.1.0.55920.18_.aspx?mode=js, line 528 character 851
And here is the concerned JS line:
Tridion.TranslationManager.Commands.Save.prototype._isAvailable=function(c,a){var
e=c.getItem(0),f=$models.getItem(e),b=f.getItemType(),d=$models.getItem(this.getTmUri ())
The preceding Javascript lines are dealing with other TranslationManager commands, so I suppose it is a kind of TranslationManager commands registration or somehting.
Trying to browse my Tridion publications by selecting any folder/strucutreGroup will also give the same error and the right frame (content frame) will not display any Tridion items but simply display:
Loading ...
Has anyone already experienced similar issue ?
For now I have no other choice than commenting out the Powertools sections file
Tridion_Home\web\WebUI\WebRoot\Configuration\System.Config
Thank you,
François
Strange thing here is that it refers to Save command which is not intended to be called or used from Dashboard.
I`d suggest to disable JS minification (JScriptMinifier filter in System.config), as it will probably show more correct details.
Another useful thing would be this error call stack.
--
I was not able to reproduce an issue from initial question, but had following error when I installed PT:
PowerTools is not defined
which appears in
*\PowerTools\Editor\PowerTools\Client\Shared\Scripts\ProgressDialog\ProgressDialog.js where it tries to register PowerToolsBase namespace, instead of PowerTools.
I`ll be surprised if adding
Type.registerNamespace("PowerTools");
at the top of the file will fix a problem, as in my case it was breaking entire GUI no matter if TM included or no.
I did check *\PowerTools\Editor\PowerTools\Client\Shared\Scripts\ProgressDialog\ProgressDialog.js, but the line
Type.registerNamespace("PowerTools");
was already there, so not the problem here.
Also, I disabled the JS minification. Here are the main methods the UI is loading before getting the error:
...
PowerTools.Commands.ItemCommenting.prototype.isValidSelection = function (selection) {
//Use the existing Save command from the CME
return $cme.getCommand("Save")._isEnabled(selection);
}
...
/**
* Executes this command on the selection.
* Override this method to implement the actual functionality.
* #param {Tridion.Core.Selection} selection The current selection.
*/
Tridion.TranslationManager.Commands.SendForTranslation.prototype._execute = function SendForTranslation$_execute(selection)
{
var selectedItems = selection.getItems();
if (selectedItems.length == 1)
{
var job = $models.getItem(selectedItems[0]);
if (job)
{
if (job.isLoaded())
{
job.saveAndSend();
}
else
{
$log.warn("Unable to send an unloaded job?! {0}".format(job.getId()));
}
}
else
{
$log.warn("Unable to execute save-and-send-for-translation for this selection: {0}".format(selectedItems));
}
}
else
{
$log.warn("Unable to save-and-send-for-translation multiple items at a time.");
}
};
...
Tridion.TranslationManager.Commands.Save.prototype._isAvailable = function Save$_isAvailable(selection, pipeline)
{
var itemUri = selection.getItem(0);
var item = $models.getItem(itemUri);
var itemType = item.getItemType(); !!!!!!!!! fails on this line !!!!!! item is null or not an object
var config = $models.getItem(this.getTmUri());
if (pipeline)
{
pipeline.stop = false;
}
if (config && config.hasChanged() && (itemType == $const.ItemType.CATEGORY || itemType == $const.ItemType.FOLDER || itemType == $const.ItemType.STRUCTURE_GROUP || itemType == $const.ItemType.PUBLICATION))
{
if (pipeline)
{
pipeline.stop = true;
}
return true;
}
return this.callBase("Tridion.Cme.Command", "_isAvailable", [selection, pipeline]);
};
Ok. It`s clear now.
PowerTools.Commands.ItemCommenting is used in Dashboard Toolbar.
This command uses Save to check its availability.
In the same time TM thinks that "Save" will only be used on an ItemToolbar.
The difference between this toolbars which cause an issue is that Dashboard view could have any-length selection, when Item view will always have selection having one item (currently opened).
Opening empty dashboard selection is not yet made, ItemCommenting tries to check its availability, by calling Save, which calls all its extensions. And so far as selection is empty
var itemUri = selection.getItem(0);
will return null, as well as
$models.getItem(null)
What you can do, is to remove ItemCommenting extension command as it is done in tridion powertool trunk editor.config.
http://code.google.com/p/tridion-2011-power-tools/source/browse/trunk/PowerTools.Editor/Configuration/editor.config?spec=svn942&r=903 [592]

Node.js - Ensuring a non-blocking call finishes

I'm using the pg postgres node module to interact with my database. The code works without an issue when I use pg's evented API. Below is an example of the code:
Migration.js
exports.up = function(logger){
var pg = require("pg")
, connectionString = //process.env.CONNECTIONSTRING
, client = new pg.Client(connectionString);
client.connect();
var cmd = "CREATE TABLE users( "
+ "id SERIAL NOT NULL, "
+ "firstName VARCHAR(50) NOT NULL, "
+ "lastName VARCHAR(50) NOT NULL, "
+ "CONSTRAINT pk_userid PRIMARY KEY (id) "
+ ")";
var query = client.query(cmd);
query.on("end", function(){
client.end();
logger.log("complete");
});
};
I'm using commander.js to write a command line utility around this migration script; however, the non-blocking call of the pg snippet is freeing up the command line interface script to finish before the database updates have been done. Below is an example commander snippet:
MyCliTool
var program = require('commander');
program
.version('1.0.2');
program
.command("up")
.description("Migrates up")
.action(function(){
require("../src/migration").up();
});
// Additional code removed for brevity
Is there a way that I can change the migration (or the commander.js app) script to ensure that the migration's up() function will finish prior to my cli script finishing? I have tried using callbacks but that appears to not be working.
UPDATE
Another example to illustrate this point. Below is a unit test (written with mocha) concerning the issue.
Up-test.js
describe("feature", function(){
it("should finish", function(){
var logger = {};
var finished = false;
logger.log = function(){finished = true;};
var migration = require("../src/migration.js");
migration.up(logger);
assert(finished, "function didn't finish"); // finished is false when this gets called.
});
});
Looks like your original script has a pain point around program.action(function () {});:
program
.command("up")
.description("Migrates up")
.action(function(){
require("../src/migration").up();
// nothing preventing this function from exiting immediately
});
I poked around a bit in commander.js docs and couldn't find anything regarding supplying a callback to your .action() program. If I were writing it, the code would look something like this:
program
.command("up")
.description("Migrates up")
.action(function (completedCallback) {
require("../src/migration").up(function () {
// migration is complete
completedCallback();
});
});
Your postgre-related script looks fine, though. A somewhat unrelated note might be to have require("../src/migration").up(); return an instance of require("events").EventEmitter and emit events you'd like to have visibility into, instead of using a logger variable. But that's just preference.
Try setting timers (http://nodejs.org/api/timers.html). We do this within our Azure CLI tool to have a spinner that runs when you are doing long running operations.
You can drill into the code here to see how we do it: https://github.com/WindowsAzure/azure-sdk-for-node/blob/master/lib/cli/cli.js. Search for the progress() function.

Categories