Trouble understanding the node.js walker - javascript

Im having trouble understanding how the signature/header of the node.js walker works. I understand, that a walker can iterate through a folder and you can set filters etc. But i dont really understand how the signature of the .on works.
As an example:
Walker('/etc/')
.filterDir(function(dir, stat) {
if (dir === '/etc/pam.d') {
console.warn('Skipping /etc/pam.d and children')
return false
}
return true
})
.on('entry', function(entry, stat) {
console.log('Got entry: ' + entry)
})
.on('dir', function(dir, stat) {
console.log('Got directory: ' + dir)
})
At the .on signatures,
-What do the 'dir/entry' parts do?
EDIT
I specifically mean what .on(**this part**, function(entry, stat)) {...} This part is doing

'dir', 'file', 'symlink', 'blockDevice' and so on are simply different things that act like files in the UNIX "everything is a file" design philosophy. For instance, you can list the devices connected to the system such as hard drives by running ls /dev/
The events in walker are simply filtered by "file type". 'entry' will trigger the callback function on every filesystem object, 'file' will only trigger for files, etc.

The walker, I assume, asynchronously accesses files starting from your defined folder, /etc/, and as it access files and folders as it's walking, it fires events.
Every time it accesses any element, whether its a file or a folder or whatever, I would imagine it fires the 'entry' event.
Every time it accesses a file, it fires the 'file' event.
Every time it accesses a directory, it fires the 'dir' event.
The first parameter to .on defines what events you want to register a callback to, and the second one is the callback itself, which takes as its first argument the element in question, or the path to it.

Those are function parameters. They define variable names that get values when the function is called.
const myFunction = function(dir, stat) {
console.log('Got directory: ' + dir)
};
myFunction("Foo", "Bar");
It is just that the function is called by code you did not write yourself.

Related

How to pass arguments/parameters to mocha tests invoked via Grunt

I have a Gruntfile.js through which i'm invoking mochaTest using grunt-mocha-test module. I can pass an argument/parameter to the gruntTask from command line but i'm struggling to pass the same parameter into the spec file running via the above module. The code looks like below,
mochaTest: {
test: {
options: {
reporter: 'spec',
quiet: false,
clearRequireCache: false,
clearCacheFilter: (key) => true,
noFail: false
},
src: [
'test/createSpec.js'
]
}
}
Task is registered like below,
grunt.registerTask('e2etest', function(scope) {
console.log(scope); // logs user/session based on the parameter passed
grunt.task.run('mochaTest');
});
// Above task is invoked like,
grunt e2etest:user
(or)
grunt e2etest:session
I need to pass this value (user/session) into mochaTest so it can be accessed inside the spec file. Fundamentally the aim is to run the createSpec.js file both for user and session, this values is parametrized inside the spec file and based on the value passed the suite would run.
Is there a possibility to do this? Please advise.
Please refer to this issue for detail, and I think the solution you need here is:
node <node flags here> node_modules/mocha/bin/_mocha <mocha arguments here>
You can utilize nodes process.argv to read the argument (i.e. user or session) from within the file named createSpec.js.
To better understand how, follow these steps:
At the top of createSpec.js add the following line of code:
console.log(process.argv);
Then run grunt e2etest:user via your CLI and you should see the following logged to your console:
[ 'node', '/usr/local/bin/grunt', 'e2etest:user' ]
Note: the information you want is positioned at index two of the array.
Now, delete the line we just added which reads console.log(process.argv); from createSpec.js.
createSpec.js
So, the steps above (1-3) illustrated that the arguments (user or session) can be accessed in createSpec.js utilizing process.argv. In which case you could do something like the following inside createSpec.js.
const argument = process.argv[2].split(':').pop();
if (argument === 'user') {
// Run `user` specific tests here...
} else if (argument === 'session') {
// Run `session` specific tests here...
}
Note, we're using process.argv[2].split(/:/).pop(); to extract either user or session from the array item positioned at index two, whose initial value will be either e2etest:user or e2etest:session respectively.
Gruntfile
Your createSpec.js file is now somewhat dependent on the grunt task named e2etest being invoked correctly. For example, if a user were to run grunt e2etest without providing the arguments then createSpec.js is not going to do much.
To enforce the correct usage of the e2etest task (i.e. it must be run using either grunt e2etest:user or grunt e2etest:session), you could change your task in your Gruntfile as follows:
grunt.registerTask('e2etest', function(scope) {
if (!scope || !(scope === 'user' || scope === 'session')) {
grunt.warn(`Must be invoked with: ${this.name}:user or ${this.name}:session`);
}
grunt.task.run('mochaTest');
});
The gist above initially checks that an argument has been provided and is either user or session. If the argument is incorrect or missing then grunt.warn is utilized to warn the user.
If your version of nodejs does not support ES6 Template literals then use grunt.warn as follows instead:
grunt.warn('Must be invoked with: ' + this.name + ':user or ' + this.name + ':session');
Additional comment
The code/gist shown in the createSpec.js section above will work if your use-case is exactly as you mention in your question. I.e. you invoke via the commandline using grunt e2etest:user or grunt e2etest:session. However, if that changes and you cannot guarantee that e2etest:user or e2etest:session will be exactly positioned at index two of the process.argv array, then you may need to do the following at the top of createSpec.js instead:
// Return the value in the array which starts with
// `e2etest` then extract the string after the colon `:`
const argument = process.argv.filter(arg => {
return arg.match(/^e2etest:.*/);
}).toString().split(':').pop();
if (argument === 'user') {
// Run `user` specific tests here...
} else if (argument === 'session') {
// Run `session` specific tests here...
}

In Node.js, asking for a value using Prompt, and using that value in a main js file

I'm pretty new to node.js and it seems fairly easy to use but when it comes to getting a value using the command line and returning that value to be used in another package or .js, it seems harder than I expected.
Long story short, I've used a npm package (akamai-ccu-purge), to enter a file to purge on the akamai network successfully.
I want to make it more dynamic though by prompting the user to enter the file they want purged and then using that in the akamai package.
After making a few tries using var stdin = process.openStdin(); I actually found another npm package called Prompt that seemed to be easier. Both ways seem to have the same problem though.
Node doesn't seem to want to stop for the input. It seems to want to automatically make the purge without waiting for input even though I've called that module first. It actually gets to the point where I should enter the file but it doesn't wait.
I am definitely missing something in my understanding or usage here, what am I doing wrong?
My code so far is:
var purgeUrl = require('./getUrl2');
var PurgerFactory = require('../../node_modules/akamai-ccu-purge/index'); // this is the directory where the index.js of the node module was installed
// area where I placed the authentication tokens
var config = {
clientToken: //my tokens and secrets akamai requires
};
// area where urls are placed. More than one can be listed with comma separated values
var objects = [
purgeUrl // I am trying to pull this from the getUrl2 module
];
// Go for it!
var Purger = PurgerFactory.create(config);
Purger.purgeObjects(objects, function(err, res) {
console.log('------------------------');
console.log('Purge Result:', res.body);
console.log('------------------------');
Purger.checkPurgeStatus(res.body.progressUri, function(err, res) {
console.log('Purge Status', res.body);
console.log('------------------------');
Purger.checkQueueLength(function(err, res) {
console.log('Queue Length', res.body);
console.log('------------------------');
});
});
});
The getUrl2 module looks like this:
var prompt = require('../../node_modules/prompt');
//
// Start the prompt
//
prompt.start();
//
// Get property from the user
//
prompt.get(['newUrl'], function (err, result) {
//
// Log the results.
//
console.log('Command-line input received:');
console.log(' http://example.com/custom/' + result.newUrl);
var purgeUrl = 'http://example.com/custom/' + result.newUrl;
console.log(purgeUrl);
module.exports = purgeUrl;
});
Thanks again for the help!
I would probably just allow getURL2 to expose a method that will be invoked in the main module. For example:
// getURL2
var prompt = require('../../node_modules/prompt');
module.exports = {
start: function(callback) {
prompt.start();
prompt.get(['newUrl'], function (err, result) {
// the callback is defined in your main module
return callback('http://example.com/custom/' + result.newUrl);
});
}
}
Then in your main module:
require('./getUrl2').start(function(purgeURL) {
// do stuff with the purgeURL defined in the other module
});
The implementation may differ, but conceptually, you need to make your second module, which requires some sort of input from the user, happen as a result of that input. Callbacks are a common way to do this (as are Promises). However, as prompt is not necessarily exposing a method that would necessitate a Promise, you can do it with plain old callbacks.
You might also want to search around for articles on writing command line tools (sometimes referenced as CLIs) or command line apps with Node. I found the following article to be helpful when trying to figure this out myself:
http://javascriptplayground.com/blog/2015/03/node-command-line-tool/
Also, the command-line-args module worked well for me (though there's a number of other modules out there to choose from):
https://www.npmjs.com/package/command-line-args
Good luck!

Is it possible to create a require.js module that decides for itself when it is done loading?

In a "normal" require.js function module, the module is considered "loaded" as soon as the module function returns:
define(function() {
// As soon as this function returns, the module is "loaded"
});
But I have a module that needs to do some asynchronous script loading (specifically including some Google Javascript API-s) and I don't want my module to be considered "loaded" until I say it is.
When creating a loader plugin for require.js, you are supplied with an "onload" function that you can call when the plugin is done loading. This would be perfect for my case, but I don't want my Google API wrapper to be a plugin, I want it to appear to be a "normal" module. Plugins are treated differently by the optimizer and I don't want that headache. Also plugins must be required using special syntax, and I'd like to avoid having to remember that every time I use it.
I have combed through the API several times without finding a way to accomplish what I'm trying to do. Is there an undocumented (or poorly documented) method of defining a module, where the module itself gets to decide when it should be considered "loaded"?
As an example, an implementation like this would be awesome, if it existed:
define(["onload"], function(onload) {
setTimeout(onload, 5000);
});
The first time this module was required, it should take 5 seconds to "load".
We bootstrap a lot of stuff using the convention below which is based on early releases (0.3.x) of the MEAN stack and uses the awesome async library.
Using your example, it might look something like this:
// bootstrap.js
// Array of tasks to pass to async to execute.
var tasks = [];
// Require path
var thePath = __dirname + '/directoryContainingRequires';
// Build array of tasks to be executed in parallel.
fs.readdirSync(thePath).forEach(function (file) {
if (~file.indexOf('.js')) {
var filePath = thePath + '/' + file;
tasks.push(function(callback) {
require(filePath)(callback);
});
}
});
// Execute parallel methods.
async.parallel(
tasks,
function(err) {
if(err) console.error(err);
console.log('All modules loaded!');
process.exit(0);
}
);
The file being required looks similar to this:
// yourModule.js
module.exports = function(moduleCallback) {
setTimeout(function() {
console.log('5 seconds elapsed');
moduleCallback(null);
}, 5000);
};

Understanding node `tmp` package

I'm not sure how to use the tmp package of node correctly. Maybe someone can give me an example
Filename generation
It is possible with this library to generate a unique filename in the
specified directory.
var tmp = require('tmp');
tmp.tmpName(function _tempNameGenerated(err, path) {
if (err) throw err;
console.log("Created temporary filename: ", path);
});
But what and how do I pass path. As I understand it, it makes sure, that in my desired directory are just unique filenames. So do I have to pass my for example upload directory as path? (But how syntax wise?)
Documentation
You don't.
You call tmpName, it calls its callback with an error (err, null if there isn't one) and the path.
Inside the callback you do what you want to do with the temporary filename, like write something to it.

Implementing logging in Metro Application developed using Html/WinJS

I need to provide with error logging in my Windows 8 Metro application developed in Html/WinJS
so that user can get to know what went wrong from a log file located in the app's local folder.
I have checked WinJS.log(message, tags, type); which will write to the console but not able to find anything via which i can get it on a local file.
What is the best way to do the same and if there are any 3rd party libraries/js available for error logging in metro applications developed in WinJS ?
Thanks in advance.
WinJS.log is just a placeholder. Without proper initialization it does nothing (in fact, it's not set at all). If you just call WinJS.Utilities.startLog() at your application startup, it defaults to wiring up a logger for the console.
If you want something more complete, you'll need to build it. I've built a small sample below.
function startFileLog() {
// choose where the file will be stored:
var fileDestination = Windows.Storage.ApplicationData.current.localFolder;
var logger = new WinJS.Promise(function (complete) {
var logfilename = new Date().toISOString().replace(/[:-]/g, "");
logfilename = "log-" + logfilename + ".log";
fileDestination.createFileAsync(logfilename,
Windows.Storage.CreationCollisionOption.generateUniqueName)
.done(function (file) {
complete(file);
});
});
var actionFn = function (message, tag, type) {
logger.then(function (file) {
var m = WinJS.Utilities.formatLog(message, tag, type);
Windows.Storage.FileIO.appendTextAsync(file, m).done();
});
};
WinJS.Utilities.startLog({ action: actionFn });
}
By calling the startFileLog function above, it creates a new log file (by using the current Date/time as part of the file name) within a promise. Then, a function called actionFn is passed to the startLog function. By passing an optional property of the options named action, the default "write to console" behavior is overwritten (if you didn't want it overwritten, you could call startLog without the action, then copy the function reference from WinJS.log and replace it with your own function, and call it as well). When the log function is called, it now calls actionFn which uses the promise created earlier to verify that the log file is in fact available for writing before continuing. If it's not ready yet, it will be queued. So, this means that even though the file may not be ready immediately, the log will, in the end, contain the results you'd expect. There would be a short period of time where, due to async nature of WinJS, if the application crashed before the file completely opened, that logged items will be missed. You could delay the application startup if you wanted until the file was opened by returning the logger promise:
function startFileLog() {
/// ... etc..
return logger;
}
startFileLog().then(function() {
// the application can now be assured that the log file is ready to accept
// writes ... (but again, it's all async, so a write may be missed in
// extreme cases)
});
You'd likely want to create a function at the end of your application to clean/close the log file.

Categories

Resources