Prevent require.js to log itself to console - javascript

When I run this code in Chrome DevTool,
require(['common'], function (common) { common.getProfilPic(123); })
It always print the whole chunk of requirejs code,
function localRequire(deps, callback, errback) {
var id, map, requireMod;
if (options.enableBuildCallback && callback && isFunction(callback)) {
callback.__requireJsBuild = true;
}
if (typeof deps === 'string') {
if (isFunction(callback)) {
//Invalid call
return onError(makeError('requireargs', 'Invalid require call'), errback);
}
//If require|exports|module are requested, get the
//value for them from the special handlers. Caveat:
//this only works while module is being defined.
if (relMap && hasProp(handlers, deps)) {
return handlers[deps](registry[relMap.id]);
}
//Synchronous access to one module. If require.get is
//available (as in the Node adapter), prefer that.
if (req.get) {
return req.get(context, deps, relMap, localRequire);
}
//Normalize module name, if it contains . or ..
map = makeModuleMap(deps, relMap, false, true);
id = map.id;
if (!hasProp(defined, id)) {
return onError(makeError('notloaded', 'Module name "' +
id +
'" has not been loaded yet for context: ' +
contextName +
(relMap ? '' : '. Use require([])')));
}
return defined[id];
}
//Grab defines waiting in the global queue.
intakeDefines();
//Mark all the dependencies as needing to be loaded.
context.nextTick(function () {
//Some defines could have been added since the
//require call, collect them.
intakeDefines();
requireMod = getModule(makeModuleMap(null, relMap));
//Store if map config should be applied to this require
//call for dependencies.
requireMod.skipMap = options.skipMap;
requireMod.init(deps, callback, errback, {
enabled: true
});
checkLoaded();
});
return localRequire;
} require.js:1361
require(['common'], function (common) { console.log(common.getProfilPic(123)); })
function localRequire(deps, callback, errback) {
var id, map, requireMod;
if (options.enableBuildCallback && callback && isFunction(callback)) {
callback.__requireJsBuild = true;
}
if (typeof deps === 'string') {
if (isFunction(callback)) {
//Invalid call
return onError(makeError('requireargs', 'Invalid require call'), errback);
}
//If require|exports|module are requested, get the
//value for them from the special handlers. Caveat:
//this only works while module is being defined.
if (relMap && hasProp(handlers, deps)) {
return handlers[deps](registry[relMap.id]);
}
//Synchronous access to one module. If require.get is
//available (as in the Node adapter), prefer that.
if (req.get) {
return req.get(context, deps, relMap, localRequire);
}
//Normalize module name, if it contains . or ..
map = makeModuleMap(deps, relMap, false, true);
id = map.id;
if (!hasProp(defined, id)) {
return onError(makeError('notloaded', 'Module name "' +
id +
'" has not been loaded yet for context: ' +
contextName +
(relMap ? '' : '. Use require([])')));
}
return defined[id];
}
//Grab defines waiting in the global queue.
intakeDefines();
//Mark all the dependencies as needing to be loaded.
context.nextTick(function () {
//Some defines could have been added since the
//require call, collect them.
intakeDefines();
requireMod = getModule(makeModuleMap(null, relMap));
//Store if map config should be applied to this require
//call for dependencies.
requireMod.skipMap = options.skipMap;
requireMod.init(deps, callback, errback, {
enabled: true
});
checkLoaded();
});
return localRequire;
}
and and me from seeing the log result, and idea how to stop requirejs to print itself?

Run this instead:
(function(){ require(['common'], function (common) { common.getProfilPic(123); }) })()

What happens is that the console is printing out the value of the expression. The value of a function call is what the call returns. You can easily work around it with something like:
require(['common'], function (common) { common.getProfilPic(123); }); 1
Adding ; 1 will make the expression evaluate to 1. So you'll get 1 on the console but at least it won't push diagnostic messages off the screen.

Related

Adding [0] causes callback to be called twice?

I'm writing utility for some minecraft stuff, whatever... So, first of all I have a code that can extract specified files from archive and give there content in callback:
const unzip = require("unzip-stream");
const Volume = require("memfs").Volume;
const mfs = new Volume();
const fs = require("fs");
function getFile(archive, path, cb) {
let called = false;
fs.createReadStream(archive)
.pipe(unzip.Parse())
.on("entry", function(entity) {
if (path.includes(entity.path)) {
entity.pipe(mfs.createWriteStream("/" + path))
.on("close", function() {
mfs.readFile("/" + path, function(err, content) {
if (!called) cb(content);
called = true;
mfs.reset();
});
}).on("err", () => {});
} else {
entity.autodrain();
}
});
}
module.exports = { getFile };
It works perfect when I test it in interactive console:
require("./zip").getFile("minecraft-mod.jar", ["mcmod.info", "cccmod.info"], console.log); // <= Works fine! Calls callback ONCE!
When I started to develop utility using this code I discovered a VERY strange thing.
So I have filenames in files array.
I'm using async/eachSeries to iterate over it. I have no callback function - only iterate one.
I have this code to parse .json files in mods:
let modinfo = Object.create(JSON.parse(content.replace(/(\r\n|\n|\r)/gm,"")));
It also works fine. But here comes magic...
So, .json files can contain array or object. If it's array we need to take first element of it:
if (modinfo[0]) modinfo = modinfo[0];
It works.
But, if it's object we need to take first element of modlist property in in:
else modinfo = modinfo.modlist[0];
And if modinfo was and object boom - callback now fires TWICE! WHAT?
But, if I remove [0] from else condition:
else modinfo = moninfo.modlist; // <= No [0]
Callback will be called ONCE! ???
If I try to do something like this:
if (modinfo[0]) modinfo = modinfo[0];
else {
const x = modinfo.modlist;
modinfo = x[0];
}
Same thing happens...
Also, it's called without arguments.
I tried to investigate - where callback is called twice. Read the zip extractor code again... It has those lines:
This:
let called = false;
And those:
if (!called) cb(content);
called = true;
So, if for some reason even this condition fires up two times:
if (path.includes(entity.path)) {
It should not call callback, right? No! Not only that, but if I try to
console.log(called);
It will log false two times!
NodeJS version: v8.0.0
Full code:
function startSignCheck() {
clear();
const files = fs.readdirSync("../mods");
async.eachSeries(files, function(file, cb) {
console.log("[>]", file);
zip.getFile("../mods/" + file, ["mcmod.info", "cccmod.info"], function(content) {
console.log(content);
console.log(Buffer.isBuffer(content));
if (content != undefined) content = content.toString();
if (!content) return cb();
let modinfo = Object.create(JSON.parse(content.replace(/(\r\n|\n|\r)/gm, "")));
if (modinfo[0]) modinfo = modinfo[0];
else modinfo = modinfo.modlist[0];
//if (!modinfo.name) return cb();
/*curse.searchMod(modinfo.name, modinfo.version, curse.versions[modinfo.mcversion], function(link) {
if (!link) return cb();
signature.generateMD5("../mods/" + file, function(localSignature) {
signature.URLgenerateMD5(link, function(curseSignature) {
if (localSignature === curseSignature) {
console.log(file, "- Подпись верна".green);
} else {
console.log(file.bgWhite.red + " - Подпись неверна".bgWhite.red);
}
cb();
});
});
});*/
});
});
}
Example contents of mcmod.info is:
{
"modListVersion": 2,
"modList": [{
"modid": "journeymap",
"name": "JourneyMap",
"description": "JourneyMap Unlimited Edition: Real-time map in-game or in a web browser as you explore.",
"version": "1.7.10-5.1.4p2",
"mcversion": "1.7.10",
"url": "http://journeymap.info",
"updateUrl": "",
"authorList": ["techbrew", "mysticdrew"],
"logoFile": "assets/journeymap/web/img/ico/journeymap144.png",
"screenshots": [],
"dependants":[],
"dependencies": ["Forge#[10.13.4.1558,)"],
"requiredMods": ["Forge#[10.13.4.1558,)"],
"useDependencyInformation": true
}]
}
Problem was that I was using modlist instead of modList. Not it works! Thanks for solution, Barmar

Access function in module with similar name of function in another module

Code:
for (var i in RESTCalls_GET) {
describe('Retrieve all Product Component names and their IDs', function() {
var restCalls;
beforeEach(function() {
RESTCalls_GET.setClient(mockClient);
restCalls = new Rest_calls(mockClient);
});
describe(i + '()', function() {
it('should return data if response code is 200', function(done) {
mockClient.mockURLForSucceed(eval('restCalls.' + i + "_RESTCall"), eval('RESTCalls_GET_ExampleData.' + i + "_ExampleData"), 200);
eval('RESTCalls_GET.' + i)(function(result) {
result.should.equal(eval('RESTCalls_GET_ExampleData.' + i + "_ExampleData"));
done();
});
}),
it('should return error if response code is NOT 200', function(done) {
mockClient.mockURLForError(eval('restCalls.' + i + "_RESTCall"), null, TestData.RESTCallResponseError_Test);
eval('RESTCalls_GET.' + i)(function(errorObj) {
errorObj.should.have.property('errorCode');
done();
});
});
});
});
}
I am looping though functions in RESTCalls_GET. Say, for example, i = getComponent, a function called getComponent_RESTCall will be in module restCalls
I have been told that one way to accomplish this is by using eval() (even though it is not recommended). This way is not working and when I debug, the parameters which use eval() in mockURLForSucceed are undefined.
This obviously causes all my tests to fail.
Any suggestions appreciated.
EDIT: (additional information)
var mockClient = function() {
var urlMap = {};
return {
get: function(url, callback) {
var entry = urlMap[url];
if (entry) {
callback(entry[0], entry[1]);
} else {
console.error("Unable to match URL " + url);
}
return {
on: function() {
//Ignore
}
};
},
mockURLForSucceed: function(URLofRESTCall, succeedData, succeedRes) {
urlMap[URLofRESTCall] = [succeedData, {statusCode: succeedRes}];
},
mockURLForError: function(URLofRESTCall, errorData, errorRes) {
urlMap[URLofRESTCall] = [errorData, errorRes];
}
}
}();
EDIT: (half way there)
I've resorted back to eval() an got the function/variable name required in format file.functionName by this:
var RESTCallURL = eval('"restCalls." + i + "_RESTCall"');
var RESTCallData = eval('"RESTCalls_GET_ExampleData." + i + "_ExampleData"');
The problem I'm having now if that these are strings. So when I pass them into a function, it gets that string value and not the one it equals in it's own function, does that make sense?
What I mean is that if I passed in RESTCallURL into a function now, then the value of that parameter would be restCalls.whatever_RESTCall whereas before it got the URL of the REST Call I am calling (http://whatever). Since I now have the name of the function, am I able to search for functions in my project by that name?
This task seems so simple to do and I think I am over thinking it.
I don't think you need eval there, what about using
RESTCalls_GET[i](function(result) {
result.should.equal(RESTCalls_GET_ExampleData[i + '_ExampleData']));
done();
});
You could easily test this behaviour by defining the following in your browser console
var test = {
'some-function': function() { console.log('works'); }
};
test['some-function']();

Display deferred data in template

Problem
I'm using this 20 line router to do my routing and templating.
What I am struggling with is using data in the template.
My templating engine is https://github.com/trix/nano.
What I have
I have a function that gets the users data (at the moment I am just trying to show a message):
adrLoadAddressBooks:function() {
var deferred = new $.Deferred();
var return_response = {};
data = {
country_code:config.country_code,
language_code:config.language_code,
source:config.source,
usr_id:app.getCookie('usr_id'),
login_token:app.getCookie('login_token')
};
app.api('adr/list',data,function(data) {
var response = JSON.parse(data);
return_response.msg = 'This user has address books.';
if(!response.result) {
return_response.msg = 'No address books found.'
}
deferred.resolve(return_response);
},'post');
return deferred.promise();
},
In my router, I get the data like so:
jsRouter.route('/adr','adr/index',function() {
console.log('In route function');
this.response = events.adrLoadAddressBooks().done(function(response) {
console.log(response);
return response;
});
});
The console.log returns the following:
Object {msg: "This user has address books."} // correct
And in my template file I have the following:
<h4>Address Books</h4>
Message: {response.msg}
Create Address Book
Question
It currently only displays the template, no msg. If I change {response.msg} to just {response}, it displays [Object object] which is the response object so it is sending something.
How do I access the msg?
I fixed it by changing my router quite a bit. I have a loadPage() function that looks like this:
loadPage:function(page,element,bindData) {
$.get(page,function(data) {
element.html(nano(data, bindData));
app.setPageListeners();
});
},
This was called at the end of my router() function (after the template has been found).
router:function() {
app.resetResponse();
jsRouter.el = jsRouter.el || $('#view');
var url = $.urlHash() || '/';
if(typeof route == 'undefined' || typeof route == null) {
route = jsRouter.routes['404'];
}
auth.isLoggedIn();
if(jsRouter.el && route.controller) {
jsRouter.loadPage(config.templates + route.template + '.html',jsRouter.el,new route.controller);
}
},
Firstly, what I did was changed my actual route() function like so:
route:function(path,template,callback) {
jsRouter.routes[path] = {template: template, callback: callback };
},
So now I can pass a callback by setting up my route like this:
jsRouter.route('/adr','adr/index',events.adrLoadAddressBooks);
I then changed the end of my router to this:
if(jsRouter.el) {
if(route.callback) {
jsRouter.loadData(config.templates + route.template + '.html',jsRouter.el,route.callback);
} else {
jsRouter.loadPage(config.templates + route.template + '.html',jsRouter.el,"");
}
}
And then created a loadData function that waits for a deferred object before continuing, like so:
loadData:function(page,element,callback) {
if(typeof callback !== 'undefined') {
if (typeof callback === "function") {
callback().done(function(data) {
jsRouter.loadPage(page,element,data);
});
} else {
alert("Could not call " + endpoint);
}
} else {
jsRouter.loadPage(page,element,this);
}
},
My callback, in this case, looks like this:
adrLoadAddressBooks:function() {
var deferred = new $.Deferred();
//do stuff
app.api('adr/list',data,function(data) {
var response = JSON.parse(data);
return_response.msg = 'Below is a list of all your address books.';
if(!response.result) {
return_response.msg = 'This user has no address books.';
deferred.resolve(return_response);
}
//build response
deferred.resolve(return_response);
},'post');
return deferred.promise();
},
And it works quite well. :) Obviously, if there's stuff that I can improve, add a comment
EDIT 1
Added extra step after route function.
EDIT 2
Full router available on Pastebin

Uglify JS - compressing unused variables

Uglify has a "compression" option that can remove unused variables...
However, if I stored some functions in an object like this....
helpers = {
doSomething: function () { ... },
doSomethingElese: function () { ... }
}
... is there a way to remove helpers.doSomething() if it's never accessed?
Guess I want to give the compressor permission to change my object.
Any ideas if it's possible? Or any other tools that can help?
Using a static analyzer like Uglify2 or Esprima to accomplish this task is somewhat nontrivial, because there are lots of situations that will call a function that are difficult to determine. To show the complexity, there's this website:
http://sevinf.github.io/blog/2012/09/29/esprima-tutorial/
Which attempts to at least identify unused functions. However the code as provided on that website will not work against your example because it is looking for FunctionDeclarations and not FunctionExpressions. It is also looking for CallExpression's as Identifiers while ignoring CallExpression's that are MemberExpression's as your example uses. There's also a problem of scope there, it doesn't take into account functions in different scopes with the same name - perfectly legal Javascript, but you lose fidelity using that code as it'll miss some unused functions thinking they were called when they were not.
To handle the scope problem, you might be able to employ ESTR (https://github.com/clausreinke/estr), to help figure out the scope of the variables and from there the unused functions. Then you'll need to use something like escodegen to remove the unused functions.
As a starting point for you I've adapted the code on that website to work for your very specific situation provided, but be forwarned, it will have scope issue.
This is written for Node.js, so you'll need to get esprima with npm to use the example as provided, and of course execute it with node.
var fs = require('fs');
var esprima = require('esprima');
if (process.argv.length < 3) {
console.log('Usage: node ' + process.argv[1] + ' <filename>');
process.exit(1);
}
notifydeadcode = function(data){
function traverse(node, func) {
func(node);
for (var key in node) {
if (node.hasOwnProperty(key)) {
var child = node[key];
if (typeof child === 'object' && child !== null) {
if (Array.isArray(child)) {
child.forEach(function(node) {
traverse(node, func);
});
} else {
traverse(child, func);
}
}
}
}
}
function analyzeCode(code) {
var ast = esprima.parse(code);
var functionsStats = {};
var addStatsEntry = function(funcName) {
if (!functionsStats[funcName]) {
functionsStats[funcName] = {calls: 0, declarations:0};
}
};
var pnode = null;
traverse(ast, function(node) {
if (node.type === 'FunctionExpression') {
if(pnode.type == 'Identifier'){
var expr = pnode.name;
addStatsEntry(expr);
functionsStats[expr].declarations++;
}
} else if (node.type === 'FunctionDeclaration') {
addStatsEntry(node.id.name);
functionsStats[node.id.name].declarations++;
} else if (node.type === 'CallExpression' && node.callee.type === 'Identifier') {
addStatsEntry(node.callee.name);
functionsStats[node.callee.name].calls++;
}else if (node.type === 'CallExpression' && node.callee.type === 'MemberExpression'){
var lexpr = node.callee.property.name;
addStatsEntry(lexpr);
functionsStats[lexpr].calls++;
}
pnode = node;
});
processResults(functionsStats);
}
function processResults(results) {
//console.log(JSON.stringify(results));
for (var name in results) {
if (results.hasOwnProperty(name)) {
var stats = results[name];
if (stats.declarations === 0) {
console.log('Function', name, 'undeclared');
} else if (stats.declarations > 1) {
console.log('Function', name, 'decalred multiple times');
} else if (stats.calls === 0) {
console.log('Function', name, 'declared but not called');
}
}
}
}
analyzeCode(data);
}
// Read the file and print its contents.
var filename = process.argv[2];
fs.readFile(filename, 'utf8', function(err, data) {
if (err) throw err;
console.log('OK: ' + filename);
notifydeadcode(data);
});
So if you plop that in a file like deadfunc.js and then call it like so:
node deadfunc.js test.js
where test.js contains:
helpers = {
doSomething:function(){ },
doSomethingElse:function(){ }
};
helpers.doSomethingElse();
You will get the output:
OK: test.js
Function doSomething declared but not called
One last thing to note: attempting to find unused variables and functions might be a rabbit hole because you have situations like eval and Functions created from strings. You also have to think about apply and call etc, etc. Which is why, I assume, we don't have this capability in the static analyzers today.

JQuery Terminal term.echo from another function?

I am trying to use: http://terminal.jcubic.pl/
I want to be able to call term.echo from another function to be able to place data inside the terminal, but I can not reference it.
Heres the code below:
jQuery(document).ready(function($) {
var id = 1;
$('body').terminal(function(command, term) {
if (command == 'help') {
term.echo("available commands are mysql, js, test");
} else{
term.echo("entered: " + command);
}
}, {
greetings: "Shell",
onBlur: function() {
return false;
}
});
});
How can I access term.echo externally, so I can from like a button click call term.echo to add in data?
Simplest way is to use global variable as a reference for a term object. In your example that can look like follows:
// global placeholder for term object
var terminal = null;
jQuery(document).ready(function($) {
var id = 1;
$('body').terminal(function(command, term) {
// setting up global reference
terminal = term;
if (command == 'help') {
term.echo("available commands are mysql, js, test");
} else{
term.echo("entered: " + command);
}
}, {
greetings: "Shell",
onBlur: function() {
return false;
}
});
});
The issue with this code is that it will load terminal after the ready event fired on document and you are never sure when that happens.
After document.ready fired you will be able to use terminal.echo(''); anywhere.
The value returned by the terminal is the same object as in interpter parameter (in both cases is jQuery object with additional terminal methods), so you can do something like this:
jQuery(function($) {
var terminal = $('body').terminal(function(command, term) {
if (command == 'help') {
term.echo("available commands are mysql, js, test");
} else{
term.echo("entered: " + command);
}
}, {
greetings: "Shell",
onBlur: function() {
return false;
}
});
terminal.echo("Some text");
});

Categories

Resources