Buggy code completion in eclipse JavaScript Development Tools - javascript

I open a project with file => new => static web project. Name it MyProject and web content folder name is WebContent.
Right click the WebContent directory and add a js directory. Right click the js directory and choose new => other => JavaScript source file and call it DomStuff.js with the following content:
var MyApp={};
MyApp.DomStuff={};
MyApp.DomStuff.someFunction=function(){
return true;
}
MyApp.do<== here it auto completes to DomStuff
Right click the js directory again and choose new => other => JavaScript source file and call it WorkFlow.js
When I type MyApp. then press control + space I get a box saying No Default Proposals. It's like auto complete only works when all the code is in one file.
Right click JavaScript Resources under the Source tab MyProject/WebContent is listed as included all and excluded none.
This is in Eclipse Version: 4.2.1 with Eclipse Web Developer Tools 3.4.1 and JavaScript Development Tools 1.4.1.
For as long as I remember I never got the auto complete to work on code outside the file I am currently working on. Is this normal or am I missing some setting here?

Standard JSDT can seem non deterministic when it come to completions across files. That is because even if the project is configured correctly then the most expensive type of it's source code analysis only occurs on files that are open. Do you get the same result if both files are open?
By the way, there is a fork of JSDT that is a candidate for merging to official JSDT called JSDT+NJSDoc that handles such cross file analysis extremely efficiently (and adds other features): https://bitbucket.org/nexj/webtools.jsdt.core

[update]
Basically Eclipse with JSDT can't do the job. Tried to define all my namespaces with constructor functions but it's all too much trouble.
Trying netbeans now and it'll assist most of the closure library and all of my code. Some things like goog.array won't complete because goog.array is never defined. When adding goog.array=new Object() to the array.js it'll complete goog.array and goog.array.ArrayLike. These modded js file go in your js/libs directory of your project.
If you want the troublesome way to get it to work in Eclipse then keep reading.
It seems that Eclipse has problems with objects declared as object literals. Declaring my complex types with a constructor function seems to do the trick. An instance of the root object has to be created on Window (capital W).
// this would be the way I would define
// a complex property that doesn't need
// more than one instance and is not complex
// enough to put in a separate file
myapp.workflow.objectLiteral={
thisDoesNotCodeAssist:function(){},
neitherDoesThis:22
};
/** if you define the complex property as
* a constructor it will auto complete
* in other files and closure compiler will
* recognize it's type
*/
/** #constructor organizes flow
* used for Eclipse code assist */
var WorkFlow=function(){};
ProwpWithSubs=function(){};
PropWithSubs.prototype.subProp=22;
PropWithSubs.prototype.subFunction=function(){
this.subsub=44;
};
WorkFlow.prototype.propwithsubs=new PropWithSubs();
if(ALLWAYSFALSE){
/**needed for Eclipse code assist
* #constructor
*/
var MyApp=function(){};
MyApp.prototype.workflow=new WorkFlow();
MyApp.prototype.dom=new DOM();
Window.prototype.myapp=new MyApp();
}else{
myapp.workflow=new WorkFlow();
}
[update]
Here are 3 files I use to split up the definition and the implementation a little so it's easier with google closure.
Setting up the main types in types.js
// source: js/mmyapp/types.js
goog.provide("myapp.types");
/** #constructor */
var gooblediegoog=function(){};
/** #constructor */
gooblediegoog.prototype.WorkFlow=function(){};
/** #constructor */
gooblediegoog.prototype.Dom=function(){};
myapp.types=new gooblediegoog();
A file that isn't used at all in my code but tells Eclipse how to auto complete:
// source: js/myapp/forCodeAssist.js
/** #const {boolean} */
var ALLWAYSFALSE=false;
if(ALLWAYSFALSE){
/**needed for Eclipse autocomplete
* #constructor
*/
var MyApp=function(){};
MyApp.prototype.types=new gooblediegoog();
Window.prototype.myapp=new MyApp();
MyApp.prototype.workflow=new myapp.types.WorkFlow();
MyApp.prototype.dom=new myapp.types.Dom();
}
An implementation of workflow:
// source: js/myapp/workflow.js
goog.provide("myapp.workflow");
goog.require("myapp.types");
goog.require("myapp.dom");
/** #returns number|undefined */
myapp.types.WorkFlow.prototype.createOrder=function(){
return myapp.dom.getArticleAmout();
};
myapp.workflow=new myapp.types.WorkFlow();
window['console'].log(myapp.workflow.createOrder());
This can be converted to a myapp.workflow.createOrder=... syntax by replacing myapp.types.WorkFlow.prototype with myapp.workflow, removing myapp.workflow=new myapp.types.WorkFlow() and removing the goog.require("myapp.types"). Maybe this can be automated in the build/compile process if needed.
I am not sure if creating a single object with the help from a constructor function is much more expensive than just having goog.require create myapp.workflow and adding properties to it as I used to do (and as it's done in closure library).

Related

Using JSDoc with SuiteScript

I am using WebStorm to write SuiteScript code and the netsuite N/record module (I defined the module as record). I have a function I wrote that will return a record (below is a simplified form of it)
/**
*
* #returns {record.Record} record.Record
*/
function getRecord() {
return rrecord.load({type: 'customrecordtc_login', id: recordId})
}
I am trying to use the JS doc so that it knows that this return is a Record object, i.e. if I called something like
r = getRecord()
I was hoping intelisence would know that I can use something such as
r.getText({...})
etc. But currently I can't get the JSDoc to do that.
Is that something possible and if so how?
The JSDoc that I put doesn't seem to direct it to Record object.
Is there an additional addon (I added in the suitecloud SDK plugin from NetSuite)?
Below is a screen shot of how my IDE looks in a given place and I wondered if there was a way to JSDoc to do something kind of similar with my own utils scripts (or their returns). (to add or change something so the IDE knows to treat a return from a utility function as a specific thing and let it auto complete. For example if I called x=utils.getSomeRecord(). and the IDE would be able to give tips for x. ** display .getField etc. like above screen shot)

PhpStorm JS inspection - JS variable coming from backend

I wanted to take some time to "clean" a personal app, to remove most of the warnings, etc.
As stated in the title I use the PhpStorm IDE and I have some warnings "Unresolved variable slug" when I use series.slug. The variable series comes from either a JSON from a PHP Class or after an Ajax call.
Is there a way to indicate an object's properties or to link a js variable to a PHP class (like in Twig)?
P.S. In my "Settings > Languages > JS > Code Quality Tools", I have nothing enabled, I just have the "basic" PhpStorm inspection.
If you use some object with keys only known in runtime (generated, received through the ajax call, etc.) in your code, there is no way for the IDE to resolve them using static code analysis.
But you can let the IDE know what your runtime data looks like. Possible solution using JSDoc annotations:
/**
* #typedef {Object} series
* #property {string} slug
* ... other series props here....
*/
...
/**
* function that uses series data
* #param {series} data
*/
function foo (data){...}
See also https://youtrack.jetbrains.com/issue/WEB-17419#comment=27-1058451, https://intellij-support.jetbrains.com/hc/en-us/community/posts/206349469-disable-unresolved-variable-on-json-object-received-by-ajax-call for other possible workarounds

Is there a way to force NetBeans JavaScript Autocomplete?

I am developing some JavaScript to be used in a CMS I'm working on.
I have encapsulated my code like this:
(function(){
var libraryName = {};
...code...
window.libraryName = libraryName;
}())
Now when I add a subnamespace and try using it outside my declaration, the NetBeans (8.0.2) autocomplete function doesn't work. Like this:
(function(){
var libraryName = {};
libraryName.subSet = {
showSomething: function(){}
};
window.libraryName = libraryName;
}())
libraryName.subSet.showSomething(); // This works
libraryName.subSet. // No current autocomplete even when pressing CTRL+space
I would like to know if there is some way to tell NetBeans how to autocomplete instead of it guessing.
Thanks
You can use Ctrl+K, the "hippie" code completion. It directly completes some matching result and if the completed item is not what you wanted, you can keep pressing Ctrl+K to get another autocompleted item (will replace the previously inserted one). Another thing, you can press Ctrl+Space 2 times to get "full" code completion (meaning pretty much everything from other objects/variables)
Update: There is another way using JSDoc, but it works only in Dev build of NetBeans and will be part of the next 8.1 release (you can download Dev builds from here):
/**
* #typedef libraryName
* #property {Function} showSomething description
* #property {someProp} foo description
*/
/**
* #typedef someProp
* #property {Date} day description
* #property {Number} num description
*/
/**
* #typedef libraryName.someProp2
* #property {Date} day description
* #property {Number} num description
*/
This way you'd have to create this "documentation" for your library and have it somewhere in JS file in your project (perhaps non-minified JS file of your library). With this #typedef feature, you can learn code completion pretty much anything even if it is not even in your code). Of course there are some issues yet to be fixed (it is a Dev build)...
I tried another approach which worked for me.
I copied my JavaScript file and removed the encapsulation. So I now have two files, the "real" one with the encapsulation and another "working" one that doesn't have the encapsulation. Now when I try using the autocomplete it works.
The downside for this is that you create noise since there is a file that isn't meant for the web app and you have to update it every time you update the original file. But it makes coding easier with the magic of autocomplete. When you load html you just don't reference the "working" file.
So, this would be my main.js file (in /js/main.js for instance)
(function(){
var libraryName = {};
libraryName.subSet = {
showSomething: function(){}
};
window.libraryName = libraryName;
}())
And a main.tmp.js file would be like this (in /tmp/main.tmp.js for instance)
var libraryName = {};
libraryName.subSet = {
showSomething: function(){}
};
Now, when I do libraryName.subSet. it shows me the correct autocomplete with showSomething.

Treat the use of #author as code style violation

Goal:
Issue a warning in case an #author tag is used anywhere inside the .js files in the project.
Question:
Is it something that jshint or other static code check tools can help with? If not, what options do I have?
Description:
I completely agree with Paul's answer at Javadoc #author tag good practices thread and treat #author tag as an unnecessary noise.
And, in the Python world, I've seen people checking for the tag usage. For example, Openstack Style Guidelines explicitly state not use #author tag. They have developed a set of custom flake8 checks which include:
[H105] Don’t use author tags.
Now, I'm trying to solve the same problem in JavaScript.
Example (this should not pass a code quality check):
/**
* #author John Smith <john#smith.com>
*/
'use strict';
No, jshint can't do that. Just do a grep across the sources looking for #author. If you want you could put that in a git pre-commit hook. Or, you could hack JSDoc to error out when creating docs if it encounters #author.
Sorry, I meant to try this out before posting an answer, but the bounty's almost up. ;^)
This answer claims that there's a way to write your own JSHint module.
It looks like it was done in a branch, https://github.com/jshint/jshint-next/wiki/Design
Its readme says, This project is obsolete. It was merged into the main repository, so that's a good sign.
Let's pretend it works as advertised and has been merged back in.
Great instructions here, though note that those are on the "jshint-next" site.
Example code from that page:
// This module errs on any identifier that doesn't starts with 'kitty'.
function myModule(linter) {
linter.on("Identifier", function (ident) {
if (ident.name && ident.name.slice(0, 5) !== "kitty")
linter.report.addError("C001", "More cats please.");
});
}
Here's from the initial section on how to set up a linter:
var Linter = require("jshint").Linter;
var code = "<your beautiful JavaScript code here>";
// Create a new instance of Linter.
var linter = new Linter(code);
// Now you can teach JSHint about your predefined variables.
// Note that default JavaScript identifiers are already there.
linter.addGlobals({
jQuery: false,
MyPlugin: true
});
// If you have any JSHint extensions, you can attach them
// to the current instance.
linter.addModule(myModule);
// Finally, parse your code.
linter.parse();
I realize that's pretty generic (you'd still need to research linter.on options beyond Identifier; there's a String too, eg), but it looks pretty promising. Again, you can see how to integrate using the instructions above. And it looks like this is the format that's used in style.js.
I have not tried this out yet. Just haven't had time at home; apologies.
Is there a specific reason torazaburo's "Just grep it" answer doesn't work? Do you need this to be part of a code quality workflow? If so, this "write your own module" would seem to be the way to go.
There are also pretty obvious ways to hack up JSLint, if you're up for it, but I'm not sure Crockford would appreciate that. ;^)
Solved it with ESLint package - a pluggable linting utility for JavaScript.
Created a custom rule (note how simple it is) and saved it to rules/no-author.js:
/**
* #fileoverview A rule to disallow #author tag in code
*/
module.exports = function (context) {
"use strict";
function checkComment(node) {
var commentToCheck = node.value.toLowerCase().trim();
if (commentToCheck.indexOf("#author") !== -1) {
context.report(node, "A comment unexpectedly contains #author.");
}
}
return {
"BlockComment": checkComment,
"LineComment": checkComment
};
};
Now, imagine I have a test.js file that violates the use of #author tag:
/**
* #author John Smith <john#smith.com>
*/
And see how the rule is applied:
$ eslint test.js --rulesdir=rules/ --rule='no-author: 2'
test.js
1:0 error A comment unexpectedly contains #author no-author
✖ 1 problem
FYI, no-author: 2 here means to turn the rule on as an error (exit code is 1 when triggered).

How do I use uncompressed files in Dojo 1.7?

I've created a Dojo module which depends on dojox/data/JsonRestStore like this:
define("my/MyRestStore",
["dojo/_base/declare", "dojox/data/JsonRestStore"],
function(declare, JsonRestStore) {
var x = new JsonRestStore({
target: '/items',
identifier: 'id'
});
...
which is fine. But now I want to have the the uncompressed version of the JsonRestStore code loaded so that I can debug it. I can't find any documentation on how to do this, but since there is a file called 'JsonRestStore.js.uncompressed.js' I changed my code to:
define("my/MyRestStore",
["dojo/_base/declare", "dojox/data/JsonRestStore.js.uncompressed"],
function(declare, JsonRestStore) {
...
thinking that might work.
I can see the JsonRestStore.js.uncompressed.js file being loaded in FireBug, but I get an error when trying to do new JsonRestStore:
JsonRestStore is not a constructor
Should this work?
Is there a way of configuring Dojo to use uncompressed versions of all modules? That's what I really want, but will settle for doing it on a per dependency basis if that's the only way.
Update
I've found a way to achieve what I want to do: rename the JsonRestStore.js.uncompressed.js file to JsonRestStore.js.
However, this seems a bit like a hacky workaround so I'd still be keen to know if there is a better way (e.g. via configuration).
You have two options
1) Create a custom build. The custom build will output a single uncompressed file that you can use for debugging. Think the dojo.js.uncompressed.js but it includes all the extra modules that you use.
OR
2) For a development environment, use the dojo source code. This means downloading the Dojo Toolkit SDK and referencing dojo.js from that in the development environment.
For the projects I work on, I do both. I set up the Dojo configuration so that it can be dynamic and I can change which configuration that I want using a query string parameter.
When I am debugging a problem, I will use the first option just to let me step through code and see what is going on. I use the second option when I am writing some significant js and don't want the overhead of the custom build to see my changes.
I describe this a bit more at
http://swingingcode.blogspot.com/2012/03/dojo-configurations.html
I think the reason for this is due to the fact that the loader declares its class-loads (modules), by the file conventions used. The 1.7 loader is not too robust just yet, ive had similar problems until realizing how to separate the '.' and '/' chars.
Its only a qualified guess; but i believe it has to do with the interpretation of '.' character in the class-name which signifies as a sub-namespace and not module name.
The 'define(/ * BLANK * / [ / * DEPENDENCIES * / ], ...)' - where no first string parameter is given - gets loaded by the filename (basename). The returned declare also has a saying though. So, for your example with jsonrest, its split/parsed as such:
toplevel = dojox
mid = data
modulename = JsonRestStore.js.uncompressed
(Fail.. Module renders as dojox.data.JsonRestStore.js.uncompressed, not dojox.data.JsonRestStore as should).
So, three options;
Load uncomressed classes through <script src="{{dataUrl}}/dojox/data/JsonRestStore.js.uncompressed.js"></script> and work them on dojo.ready
I think modifying the define([], function(){}) in uncompressed.js to define("JsonRestStore", [], function() {}) would do the trick (uncomfirmed)
Use the dojo/text loader, see below
Text filler needed :)
define("my/MyRestStore",
["dojo/_base/declare", "dojo/text!dojox/data/JsonRestStore.js.uncompressed.js"],
function(declare, JsonRestStore) {
...
JsonRestStore = eval(JsonRestStore);
// not 100% sure 'define' returns reference to actual class,
// if above renders invalid, try access through global reference, such as
// dojox.dat...

Categories