Is there anyway to define an undefined object in Visual Studio intellisense? - javascript

Lets say I have a controller in AngularJS:
myApp.controller('SearchController',
function ($scope, UserService) {
// for intellisense, UserService is undefined here
var user = UserService.getUsers().then(function(data){
// yada yada
}, function(err){
// yada yada
});
});
However, in my intellisense file, I can dynamically inject UserService to get its functions like this:
intellisense.addEventListener('statementcompletion', function (event) {
// tried doing this, but doesn't work!
// event.target = {};
var injector = angular.injector(['ng', 'myApp']);
var dependency = injector.get(event.targetName);
event.items = [];
for (method in dependency) {
intellisense.logMessage(method);
event.items.push({ name: method, kind: 'field', value: function () { } });
}
});
Now, if I have a global variable (or function variable) defined as UserService = {} and inside my controller function I type UserService. I will get a pop up of all the functions in the service. But if I don't have it defined, since it is interpreted as undefined by intellisense, it can't show me the options even though statementcompletion is working (as seen in the Javascript Language Service console).
My question is, apart from annotating the function, is there anyway to define UserService as an object in the intellisense file? Defining event.target = {} does not work (see intellisense code above).

One way that works is to "call" the component functions (controller, services, etc) from intellisense code with empty objects.
I am sure this can be a lot cleaner but here's what I've done:
https://github.com/diwasbhattarai/angularjs-intellisense
By John Bledsoe: https://github.com/jmbledsoe/angularjs-visualstudio-intellisense/
references.js - add this file as reference in Tools>Options>TextEditor>Javascript>Intellisense>References
/// <reference path="../source/lib/assetBundle.js" />
/// <reference path="_moduleDecorator.js" />
/// <reference path="_componentDecorator.js" />
/// <reference path="../source/app/appBundle.js" />
intellisense.addEventListener('statementcompletion', function (event) {
// for core angular objects
addComponentToIntellisense('ng');
// for custom objects in application modules
for (var moduleIndex in modules) {
addComponentToIntellisense(modules[moduleIndex]);
}
function addComponentToIntellisense(module) {
var $injector = angular.injector(['ng', module]),
dependency = $injector.get(event.targetName),
dep;
if (typeof dependency === "function") dep = new dependency();
else dep = dependency;
for (var method in dep) {
event.items.push({ name: method, kind: 'field', value: dependency[method] });
}
}
});
_moduleDecorator.js - to keep track of all the modules in your app
//_moduleDecorator
(function () {
var originalModule = angular.module;
// TODO change to array
modules = {};
var rep = false;
var count = 0;
angular.module = function () {
for (var k in modules) {
if (modules[k] === arguments[0]) {
rep = true;
break;
}
}
if (!rep) modules[count++] = arguments[0];
return originalModule.apply(angular, arguments);
};
})();
_componentDecorator.js - to "call" component functions with empty object parameter
(function () {
// pick all the components in all modules and initialize them for intellisense
for (var moduleIndex in modules) {
var currentModule = angular.module(modules[moduleIndex]),
queue = currentModule._invokeQueue,
// add other components such as value, provider, etc later
angularComponents = ['controller', 'factory', 'service', 'value'];
for (var i = 0; i < angularComponents.length; i++) {
var currentComponent = angularComponents[i],
originalComponentFn = currentModule[currentComponent];
currentModule[currentComponent] = (function (currentModule, queue, originalComponentFn) {
return function () {
originalComponentFn.apply(currentModule, arguments);
initializeComponents(queue);
};
})(currentModule, queue, originalComponentFn);
}
}
function initializeComponents(queue) {
var elem = queue.filter(function (element) {
var componentName = element[2][0].toLowerCase();
return (componentName.indexOf(componentName) !== -1);
});
for (var i = 0; i < elem.length; i++) {
var tempComp = elem[i][2][1],
compFunc;
// for array notation for DI
if (typeof tempComp !== "function") {
compFunc = tempComp[tempComp.length - 1];
} else {
compFunc = tempComp;
}
// 10 parameter dependencies initialization for now
compFunc({}, {}, {}, {}, {}, {}, {}, {}, {}, {});
}
}
})();

Related

Converting code to ES6 modules

I have just started learning es6 module system. I have some es5 javascript code which I want to transform to es6 modules. There are 3 javascript files
workflow-designer.js
var WorkflowDesigner = (function () {
var constructor = function (element, options) {
var component = this;
if ($(element).hasClass('panel')) {
component.panel = $(element);
} else {
component.panel = $(element).closest('.panel');
}
};
extend(Object, constructor, {
getWorkflowName: function () {
return 'WorkflowName001';
},
nextStep: function () {
var o = {};
o['id'] = -1;
//some code here
return o;
},
prevStep: function () {
var o = {};
o['id'] = -1;
//some code here
return o;
}
});
return constructor;
})();
(function ($) {
$.fn.createWorkflowDesigner = function (options) {
debugger;
return this.map(function (index, element) {
return new WorkflowDesigner($(element), options);
});
};
}(jQuery));
extend.js
function extend(parent, child, methods) {
debugger;
let Surrogate = function () {};
Surrogate.prototype = parent.prototype;
child.prototype = new Surrogate();
child.prototype.constructor = child;
// Add a reference to the parent's constructor
child.parentConstructor = parent;
// Copy the methods passed in to the prototype
for (let name in methods) {
if (methods.hasOwnProperty(name)) {
child.prototype[name] = methods[name];
}
}
// so we can define the constructor inline
return child;
}
There a third file utils.js which contain extension methods like
if (!Array.prototype.find) {
Array.prototype.find = function (predicate) {
//some code here
}
}
if (!Array.prototype.doSomething) {
Array.prototype.doSomething = function (predicate) {
//some code here
}
}
$(document).keyup(function (event) {
//somthing here.
});
I know that to convert the code to es6 modules, I can simply export the extend function like export function extend(.....) in the extend.js file. However, I am not 100% sure how to convert the workflow-designer and utils.js to es6 modules.
I suspect that I need to something like below to convert my workflow-designer.js to es6 module:
export default function workflowDesigner() {
let constructor = function (element, options) {
options = options || {};
let component = this;
if ($(element).hasClass('panel')) {
component.panel = $(element);
} else {
component.panel = $(element).closest('.panel');
}
};
//rest of the code here....
return constructor;
};
Please let me know if I am moving into the right direction or not.
UPDATE:
As per #Bergi's suggesion I changed the extend function like below:
export default function extend(parent, child, methods) {
child.prototype = Object.create(parent.prototype);
child.prototype.constructor = child;
// Add a reference to the parent's constructor
child.parentConstructor = parent;
// Copy the methods passed in to the prototype
Object.assign(child, methods);
// so we can define the constructor inline
return child;
}
However, now I am getting error message that "workflowDesigner.getWorkflowName is not a function"
In the debug mode I can see that this function is available at workflowDesigner.__proto__.constructor.getWorkflowName. With the old code it works fine.
Just drop the IIFE from your module pattern - ES6 modules come with their own scope.
import extend from './extend.js';
export default function WorkflowDesigner(element, options) {
if ($(element).hasClass('panel')) {
this.panel = $(element);
} else {
this.panel = $(element).closest('.panel');
}
}
extend(Object, WorkflowDesigner, {
getWorkflowName: () => 'WorkflowName001',
…
});
const $ = jQuery; // you might want to solve this with a proper `import`
$.fn.createWorkflowDesigner = function (options) {
debugger;
return this.map(function (index, element) {
return new WorkflowDesigner($(element), options);
});
};

Automatically generate stubbed modules in node.js

I'm moving my JavaScript test code from Jest to Mocha. One nice feature of Jest is that it automatically generated stubs for your modules. These stubs implement the same API as the originals, but all their functions return undefined. Exported classes are also stubbed, i.e. they have all the same methods as the original, but the return undefined:
// mymodule.js
var MyClass = function() { this.foo = 42; };
MyClass.prototype.getFoo = function() { return this.foo; };
module.exports = {
myclass: MyClass,
myfunction: function() { return 42; }
};
// __tests__/mymodule-test.js
var mm = require('../mymodule'); // Jest auto-mocks this module.
describe('test', function() {
it('functions and constructors are mocked', function() {
expect(mm.myfunction()).toEqual(undefined); // function is stubbed
var mc = new mm.myclass();
expect(mc.getFoo()).toEqual(undefined); // fn on prototype is stubbed.
});
});
For various reasons, I'm moving over to MochaJS but I'd like to keep this stubbing behavior. I can inject stubs for modules using proxyquire. But I need to define the stubs myself.
What I'd like is a function which which takes a Node module and returns something like the Jest auto-mocked version of the module. Jest's code to do this is in moduleMocker.js. I've written some code of my own to do this (included below). But it's quite tricky and doesn't feel like code I should be writing.
Is there a standard library for doing this?
Here's what I've written:
// stubber.js
var U = require('underscore');
function replaceFunctionsWithStubs(rootObj) {
var replacedObjs = []; // array of [original, replacement] pairs.
function previousReplacement(obj) {
for (var i = 0; i < replacedObjs.length; i++) {
if (replacedObjs[i][0] == obj) {
return replacedObjs[i][1];
}
}
return null;
}
function replacer(obj) {
var t = typeof(obj);
if (t != 'function' && t != 'object') {
// Simple data.
return obj;
}
// Return previous mock to break circular references.
var prevRep = previousReplacement(obj);
if (prevRep) return prevRep;
if (t == 'function') {
var f = function() {};
replacedObjs.push([obj, f]);
if (!U.isEmpty(obj.prototype)) {
// This might actually be a class. Need to stub its prototype, too.
var newPrototype = replacer(obj.prototype);
for (var k in newPrototype) {
f.prototype[k] = newPrototype[k];
}
}
// Stub any properties the function might have.
for (var k in obj) {
f[k] = replacer(obj[k]);
}
return f;
} else if (typeof(obj) == 'object') {
// TODO: Do I need to handle arrays differently?
var newObj = {};
replacedObjs.push([obj, newObj]);
for (var k in obj) {
newObj[k] = replacer(obj[k]);
}
return newObj;
} else {
return obj; // string, number, null, undefined, ...
}
}
return replacer(rootObj);
}
module.exports = function(m) {
return replaceFunctionsWithStubs(m);
};

Multiple Factories in Node?

Trying to create multiple factories in Node. Do they have to be in separate files? If they are, how do I make sure to access both?
index.js
var myFunc = function () {
this.data = {
thingOne: null,
thingTwo: null,
thingThree: null
};
this.fill = function (info) {
for (var prop in this.data) {
if (this.data[prop] !== 'undefined') {
this.data[prop] = info[prop];
}
}
};
this.triggerAction = function () {
//make some action happen!
};
module.exports = function (info) {
var instance = new myFunc();
instance.fill(info);
return instance;
};
When I add another function below that it breaks the existing code with an object [object Object] has no method 'triggerAction:'
var myFunc2 = function () {
this.data = {
thingOne: null,
thingTwo: null,
thingThree: null
};
this.fill = function (info) {
for (var prop in this.data) {
if (this.data[prop] !== 'undefined') {
this.data[prop] = info[prop];
}
}
};
this.triggerAction2 = function () {
//make some action happen!
};
};
module.exports = function (info) {
var instance = new myFunc2();
instance.fill(info);
return instance;
};
So do I have to put the second function in a separate file? And if I do, how do I modify package.json to make sure it sees the second file? Thanks!
The short answer is no.
The error you are seeing is caused because you are overwriting the value of the exports property of the module - effectively replacing the first assignment with the last.
If you want these to be in the same module, you would need to export them separately:
module.exports.factoryA = function(...) {...}
module.exports.factoryB = function(...) {...}
To reference these from another module either of these patterns would work:
var factories = require('./myfactories');
var factoryAResult = factories.factoryA(...);
var factoryBResult = factories.factoryB(...);
or
var factoryA = require('./myfactories').factoryA;
var factoryAResult = factoryA(...);

How to stub require() / expect calls to the "root" function of a module?

Consider the following jasmine spec:
describe("something.act()", function() {
it("calls some function of my module", function() {
var mod = require('my_module');
spyOn(mod, "someFunction");
something.act();
expect(mod.someFunction).toHaveBeenCalled();
});
});
This is working perfectly fine. Something like this makes it green:
something.act = function() { require('my_module').someFunction(); };
Now have a look at this one:
describe("something.act()", function() {
it("calls the 'root' function of my module", function() {
var mod = require('my_module');
spyOn(mod); // jasmine needs a property name
// pointing to a function as param #2
// therefore, this call is not correct.
something.act();
expect(mod).toHaveBeenCalled(); // mod should be a spy
});
});
This is the code I'd like to test with this spec:
something.act = function() { require('my_module')(); };
This has bogged me down several times in the last few months. One theoretical solution would be to replace require() and return a spy created with createSpy(). BUT require() is an unstoppable beast: it is a different "copy" of the function in each and every source file/module. Stubbing it in the spec won't replace the real require() function in the "testee" source file.
An alternative is to add some fake modules to the load path, but it looks too complicated to me.
Any idea?
rewire is awesome for this
var rewire = require('rewire');
describe("something.act()", function() {
it("calls the 'root' function of my module", function() {
var mod = rewire('my_module');
var mockRootFunction = jasmine.createSpy('mockRootFunction');
var requireSpy = {
mockRequire: function() {
return mockRootFunction;
}
};
spyOn(requireSpy, 'mockRequire').andCallThrough();
origRequire = mod.__get__('require');
mod.__set__('require', requireSpy.mockRequire);
something.act();
expect(requireSpy.mockRequire).toHaveBeenCalledWith('my_module');
expect(mockRootFunction).toHaveBeenCalled();
mod.__set__('require', origRequire);
});
});
It looks like I found an acceptable solution.
The spec helper:
var moduleSpies = {};
var originalJsLoader = require.extensions['.js'];
spyOnModule = function spyOnModule(module) {
var path = require.resolve(module);
var spy = createSpy("spy on module \"" + module + "\"");
moduleSpies[path] = spy;
delete require.cache[path];
return spy;
};
require.extensions['.js'] = function (obj, path) {
if (moduleSpies[path])
obj.exports = moduleSpies[path];
else
return originalJsLoader(obj, path);
}
afterEach(function() {
for (var path in moduleSpies) {
delete moduleSpies[path];
}
});
The spec:
describe("something.act()", function() {
it("calls the 'root' function of my module", function() {
var mod = spyOnModule('my_module');
something.act();
expect(mod).toHaveBeenCalled(); // mod is a spy
});
});
This is not perfect but does the job quite well. It does not even mess with the testee source code, which is kind of a criterion for me.
I needed to do this today and came across this post. My solution follows:
In a spec helper:
var originalRequire = require;
var requireOverrides = {};
stubModule = function(name) {
var double = originalRequire(name);
double['double'] = name;
requireOverrides[name] = double;
return double;
}
require = function(name) {
if (requireOverrides[name]) {
return requireOverrides[name];
} else {
return originalRequire(name);
}
}
afterEach(function() {
requireOverrides = {};
});
In a spec:
AWS = stubModule('aws-sdk');
spyOn(AWS.S3, 'Client');
// do something
expect(AWS.S3.Client).toHaveBeenCalled();
This was very helpful, but it doesn't support calling through via .andCallThrough().
I was able to adapt it though, so I thought I'd share:
function clone(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
var key;
var temp = new obj.constructor();
for (key in obj) {
if (obj.hasOwnProperty(key)) {
temp[key] = clone(obj[key]);
}
}
return temp;
};
spyOnModule = function spyOnModule(name) {
var path = require.resolve(name);
var spy = createSpy("spy on module \"" + name + "\"");
moduleSpies[path] = spy;
// Fake calling through
spy.andCallThrough = function() {
// Create a module object
var mod = clone(module);
mod.parent = module;
mod.id = path;
mod.filename = path;
// Load it backdoor
originalJsLoader(mod, path);
// And set it's export as a faked call
return this.andCallFake(mod.exports);
}
delete require.cache[path];
return spy;
};
You can use gently module (https://github.com/felixge/node-gently). Hijacking require is mentioned in examples, and dirty NPM module actively uses it, so I suppose it works.
There is another approach. You can put the module in the global scope by not using var when requiring it:
someModule = require('someModule');
describe('whatever', function() {
it('does something', function() {
spyOn(global, 'someModule');
someFunctionThatShouldCallTheModule();
expect(someModule).toHaveBeenCalled();
}
}
You could also wrap the module in another module:
//someModuleWrapper.js
require('someModule');
function callModule(arg) {
someModule(arg);
}
exports.callModule = callModule;
//In the spec file:
someModuleWrapper = require('someModuleWrapper');
describe('whatever', function() {
it('does something', function() {
spyOn(someModuleWrapper, 'callModule');
someFunctionThatShouldCallTheModule();
expect(someModuleWrapper.callModule).toHaveBeenCalled();
}
}
And then obviously make sure that wherever someFunctionThatShouldCallTheModule is, you're requiring the wrapper rather than the real module.

JavaScript Namespace

I want to create a global namespace for my application and in that namespace I want other namespaces:
E.g.
Dashboard.Ajax.Post()
Dashboard.RetrieveContent.RefreshSalespersonPerformanceContent();
I also want to place them in seperate files:
Ajax.js
RetrieveContent.js
However I have tried using this method, however it won't work because the same variable name is being used for the namespace in 2 seperate places. Can anyone offer an alternative?
Thanks.
You just need to make sure that you don't stomp on your namespace object if it's already been created. Something like this would work:
(function() {
// private vars can go in here
Dashboard = Dashboard || {};
Dashboard.Ajax = {
Post: function() {
...
}
};
})();
And the RetrieveContent file would be defined similarly.
Here is a very good article on various "Module Patterns" in JavaScript. There is a very nice little section on how you can augment modules, or namespaces and maintain a cross-file private state. That is to say, the code in separate files will be executed sequentially and properly augment the namespace after it is executed.
I have not explored this technique thoroughly so no promises... but here is the basic idea.
dashboard.js
(function(window){
var dashboard = (function () {
var my = {},
privateVariable = 1;
function privateMethod() {
// ...
}
my.moduleProperty = 1;
my.moduleMethod = function () {
// ...
};
return my;
}());
window.Dashboard = dashboard;
})(window);
dashboard.ajax.js
var dashboard = (function (my) {
var _private = my._private = my._private || {},
_seal = my._seal = my._seal || function () {
delete my._private;
delete my._seal;
delete my._unseal;
},
_unseal = my._unseal = my._unseal || function () {
my._private = _private;
my._seal = _seal;
my._unseal = _unseal;
};
// permanent access to _private, _seal, and _unseal
my.ajax = function(){
// ...
}
return my;
}(dashboard || {}));
dashboard.retrieveContent.js
var dashboard = (function (my) {
var _private = my._private = my._private || {},
_seal = my._seal = my._seal || function () {
delete my._private;
delete my._seal;
delete my._unseal;
},
_unseal = my._unseal = my._unseal || function () {
my._private = _private;
my._seal = _seal;
my._unseal = _unseal;
};
// permanent access to _private, _seal, and _unseal
my.retrieveContent = function(){
// ...
}
return my;
}(dashboard || {}));
The Yahoo Namespace function is exactly designed for this problem.
Added:
The source of the function is available. You can copy it into your own code if you want, change the root from YAHOO to something else, etc.
There are several libraries that already offer this sort of functionality if you want to use or examine a pre-baked (that is, a tested) solution.
YUI.attribute and YUI.base
dojo.mixin
underscore.extend
jQuery.extend
goog.provide and goog.object.extend
The simplest and most bug free one to get going with is probably jQuery.extend, with the deep argument set to true. (The reason I say it is bug free is not because I think that jQuery.extend suffers from less bugs than any of the other libraries -- but because it offers a clear option to deep copy attributes from the sender to the receiver -- which most of the other libraries explicitly do not provide. This will prevent many hard-to-diagnose bugs from cropping up in your program later because you used a shallow-copy extend and now have functions executing in contexts you weren't expecting them to be executing in. (If however you are cognizant of how you will be extending your base library while designing your methods, this should not be a problem.)
With the NS object created, you should just be able to add to it from where ever. Although you may want to try var NS = NS || {}; to ensure the NS object exists and isn't overwritten.
// NS is a global variable for a namespace for the app's code
var NS = NS || {};
NS.Obj = (function() {
// Private vars and methods always available to returned object via closure
var foo; // ...
// Methods in here are public
return {
method: function() {
}
};
}());
You could do something like this...
HTML page using namespaced library:
<html>
<head>
<title>javascript namespacing</title>
<script src="dashboard.js" type="text/javascript"></script>
<script src="ajax.js" type="text/javascript"></script>
<script src="retrieve_content.js" type="text/javascript"></script>
<script type="text/javascript">
alert(Dashboard.Ajax.Post());
alert(Dashboard.RetrieveContent.RefreshSalespersonPerformanceContent());
Dashboard.RetrieveContent.Settings.Timeout = 1500;
alert(Dashboard.RetrieveContent.Settings.Timeout);
</script>
</head>
<body>
whatever...
</body>
</html>
Dashboard.js:
(function(window, undefined){
var dashboard = {};
window.Dashboard = dashboard;
})(window);
Ajax.js:
(function(){
var ajax = {};
ajax.Post = function() { return "Posted!" };
window.Dashboard.Ajax = ajax
})();
Retrieve_Content.js:
(function(){
var retrieveContent = {};
retrieveContent.RefreshSalespersonPerformanceContent = function() {
return "content retrieved"
};
var _contentType;
var _timeout;
retrieveContent.Settings = {
"ContentType": function(contentType) { _contentType = contentType; },
"ContentType": function() { return _contentType; },
"Timeout": function(timeout) { _timeout = timeout; },
"Timeout": function() { return _timeout; }
};
window.Dashboard.RetrieveContent = retrieveContent;
})();
The Dashboard.js acts as the starting point for all namespaces under it. The rest are defined in their respective files. In the Retrieve_Content.js, I added some extra properties in there under Settings to give an idea of how to do that, if needed.
I believe the module pattern might be right up your alley. Here's a good article regarding different module patterns.
http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth
I highly recommend you use this technique:
https://github.com/mckoss/namespace
namespace.lookup('com.mydomain.mymodule').define(function (ns) {
var external = namespace.lookup('com.domain.external-module');
function myFunction() {
...
}
...
ns.extend({
'myFunction': myFunction,
...
});
});
I've been using this pattern for a couple of years; I wish more libraries would do the same thing; it's made it much easier for me to share code across my different projects as well.
i wrote this function to simplify creating namespaces. Mabey it will help you.
function ns(nsstr) {
var t = nsstr.split('.');
var obj = window[t[0]] = window[t[0]] || {};
for (var i = 1; i < t.length; i++) {
obj[t[i]] = obj[t[i]] || {};
obj = obj[t[i]];
}
}
ns('mynamespace.isawesome.andgreat.andstuff');
mynamespace.isawesome.andgreat.andstuff = 3;
console.log(mynamespace.isawesome.andgreat.andstuff);
bob.js can help in defining your namespaces (among others):
bob.ns.setNs('Dashboard.Ajax', {
Post: function () { /*...*/ }
});
bob.ns.setNs('Dashboard.RetrieveContent', {
RefreshSalespersonPerformanceContent: function () { /*...*/ }
});
Implementation:
namespace = function(packageName)
{
// Local variables.
var layers, layer, currentLayer, i;
// Split the given string into an array.
// Each element represents a namespace layer.
layers = packageName.split('.');
// If the top layer does not exist in the global namespace.
if (eval("typeof " + layers[0]) === 'undefined')
{
// Define the top layer in the global namesapce.
eval(layers[0] + " = {};");
}
// Assign the top layer to 'currentLayer'.
eval("currentLayer = " + layers[0] + ";");
for (i = 1; i < layers.length; ++i)
{
// A layer name.
layer = layers[i];
// If the layer does not exist under the current layer.
if (!(layer in currentLayer))
{
// Add the layer under the current layer.
currentLayer[layer] = {};
}
// Down to the next layer.
currentLayer = currentLayer[layer];
}
// Return the hash object that represents the last layer.
return currentLayer;
};
Result:
namespace('Dashboard.Ajax').Post = function() {
......
};
namespace('Dashboard.RetrieveContent').RefreshSalespersonPerformanceContent = function() {
......
};
Gist:
namespace.js

Categories

Resources