I keep getting the warning mentioned above but can't figure out why. I've added deps.js and deps.js contains a reference to the type.
Here is the offending code:
goog.provide("MyCompany.MyApp.dom");
MyCompany.MyApp.dom.getArticleAmountInput_=function(){
return document.getElementById("articleAmount");
};
/**
* Gets the article amount input value
* #type {function(this:MyCompany.MyApp.dom):number} */
MyCompany.MyApp.dom.getArticleAmount=function(){
var tmp=this.getArticleAmountInput_();
return (tmp)?tmp.value():undefined;
};
In deps.js:
goog.addDependency('../../MyCompany/MyApp/dom.js', [ 'MyCompany.MyApp.dom'], []);
Code loads in html so it does find the class at runtime. Here is how I compile the code:
java -jar ../../compiler.jar \
--compilation_level=ADVANCED_OPTIMIZATIONS \
--formatting=PRETTY_PRINT \
--warning_level=VERBOSE \
--summary_detail_level=3 \
--js=MyCompany/MyApp/dom.js \
--js=closure/goog/deps.js \
--js_output_file=out.js
And it keeps giving me the warning:
WARNING - Bad type annotation. Unknown type MyCompany.MyApp.dom
[update]
Tried to leave out the goog.provide completely and leave out the js=closure/goog/deps.js when compiling and changed everything to lower case but keep getting the same warning on this code:
//goog.provide("mycompany.myapp.dom");
var mycompany={};
mycompany.myapp={};
mycompany.myapp.dom={};
mycompany.myapp.dom.getArticleAmountInput_=function(){
return document.getElementById("articleAmount");
};
/**
* Gets the article amount input value
* #type {function(this:mycompany.myapp.dom):number} */
mycompany.myapp.dom.getArticleAmount=function(){
var tmp=this.getArticleAmountInput_();
return (tmp)?tmp.value():undefined;
};
[update]
The thing is that when I add a typedef I get warnings that myapp.dom is never defined but when I let the code determine what the type is I get Bad type annotation.
Tried to add a typedef like so:
/**
* #typedef {{getArticleAmount:function(this:myapp.dom):?number}}
*/
myapp.dom;
But don't realy see why as goog.provide should create the myapp.dom and the compiler should know that.
[update]
I have created the following myapp.workflow from constructors. Now the compiler should recognize the type and Eclipse can code assist. Not sure if this is the way to do it but I'll try to re factor a small project.
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).
Anonymous types (namespaces or singletons) don't have specific types in Closure-compiler and cannot be used as a type name in an annotation. Only constructors and interfaces can be used as new type names. (typedefs can be used but are really just shorthand annotations)
In many cases the compiler will correctly infer the types and you will not need to annotate it. In your specific case, it looks like the problem is your use of the this keyword. Using the this keyword in a static object / namespace is dangerous and not supported. The compiler will raise a warning. While you can suppress the warning with a #this annotation, that is not the correct action here as you are not specifically specifying the this reference by using .call or .apply.
The solution is to use the full object name:
/**
* Gets the article amount input value
*/
mycompany.myapp.dom.getArticleAmount=function(){
var tmp=mycompany.myapp.dom.getArticleAmountInput_();
return (tmp)?tmp.value():undefined;
};
For the full technical details, reference the This this is your this post.
Related
I am trying to compile code using closure compiler and generate public only documentation using JsDoc.
Why is the use of #public and #export tags at the same time prohibited? There is also an unit test checking it.
/**
* #public
* #export
*/
function hello(name) {
alert('Hello, ' + name);
}
hello('New user');
When trying to compile that, closure compiler throws a warning:
JSC_PARSE_ERROR: Parse error. extra visibility tag at line 4 character
3 * #export
Here is an example using online closure compiler.
As mentioned here about #public:
Indicates that a member or property is public. A property marked
#public is accessible to all code in any file. This is the implicit
default and rarely used. This is not used to indicate that name should
be preserved in obfuscating builds see #export.
So how can I indicate that I want a particular symbol to be both public and exported?
The error is telling you that #public is implied by #export.
Exporting something implies it will be used by external code, and that implies that the item must be public.
In my experience, you'll likely only need to know one thing about #public and that is from a portion in the question:
[...]This is the implicit default and rarely used[...]
I bet this is a stupid question but I somehow can't find the reason for this in any document I have found since this morning.
I am experienced in using JavaDoc but somehow even though the syntax of #link is the same, JSDoc3 simply does not generate hrefs to the related elements. I have tried out every possible way for the namespaces to link (also obviously wrong ones), but non of them changes the result a bit. I expected to receive a link by writing {#link #myFunction} or at least {#link MyClass#myFunction}, but neither of this created a hyperlink. Here is the code I have tested this with:
/**
* See {#link myOtherFunction} and [MyClass's foo property]{#link MyClass#foo}.
* Or look at {#link https://github.com GitHub}
*/
function myFunction(){};
/**
* See {#link #myFunction} or maybe {#link #myFunction()}
*/
function myOtherFunction() {};
I am generating it with ./node_modules/.bin/jsdoc ./* --configure ./conf.json and my default config file is:
{
"tags": {
"allowUnknownTags": true
},
"source": {
"includePattern": ".+\\.js(doc|x)?$",
"excludePattern": "(^|\\/|\\\\)_"
},
"plugins": [],
"templates": {
"cleverLinks": true,
"monospaceLinks": false,
"default": {
"outputSourceFiles": true
}
}
}
(it makes no difference if I write "cleverLinks": false,)
This is how my output looks like:
So as one can see the URL is generated properly but the namespaces are not.
I am just badly confused since I can nowhere find a description that something must be done in order to generate hrefs to my namespaces. Additionally jsdoc says:
The {#link} inline tag creates a link to the namepath or URL that you specify. When you use the {#link} tag, you can also provide link text, using one of several different formats. If you don't provide any link text, JSDoc uses the namepath or URL as the link text.
which does not sound like there needs to be done anything in order to generate links to the namepaths.
And it also defines the syntax to be:
{#link namepathOrURL}
[link text]{#link namepathOrURL}
{#link namepathOrURL|link text}
{#link namepathOrURL link text (after the first space)}
My namepaths are okay as well since webstorm is able to resolve them directly.
What am I missing so badly?
Best regards,
Vegaaaa
I have found out my issue was related to the usage of JSDoc with CommonJS (NodeJS). After several hours of googling and trial and error I have managed to end up with how it working differently in NodeJS. I might play around with #inner and #instance but this resolves the question why JSDoc did not want to generate links for my NodeJS Code.
It is due to the fact that CommonJS's scope works differently to client side JS, which has one reason in the definition of NodeJS modules. Thus one need to tell JSDoc how to resolve a variable by adding the #module tag for a module and referencing to members of a module by resolving its relationship like {#link module:MODULE_NAME~instanceName}.
Here is an example with the corresponding generated html. Hope this helps someone running in the same issues like me.
Best regards,
Vegaaaa
/**
* #module lib
*/
/**
* #constructor
*/
var SomeClass = function () {
};
/**
* Some doc...
*/
var moduleFunction = function () {
/**
* #type {number}
*/
var innerVar = 0;
/**
* #type {number}
*/
this.instanceVar = 0;
/**
* #memberOf module:lib~moduleFunction
*/
function staticVar() {
console.log(0)
}
}
/**
* Link to this module (identified by #module lib in the beginning): {#link module:lib} <br/>
* Link to my constructor: {#link module:lib~SomeClass} <br/>
* Link to a module function: {#link module:lib~moduleFunction} <br/>
* Link to an instance variable of a module function: {#link module:lib~moduleFunction#instanceVar} <br/>
* Link to a inner variable within a module function: {#link module:lib~moduleFunction~innerVar} <br/>
* Link to a static variable within a module function: {#link module:lib~moduleFunction.staticVar} <br/>
*/
function documentedFunction(){}
I want to document a function written in another module, which uses http.ClientRequest typed parameter. I want something like this, but it does not work:
/**
* #param {ClientRequest} req
*/
function setToken(req) {
}
I have tried also #param {http.ClientRequest}, but it did not work.
Update:
Basically I solved that problem by importing the required module by import http from "http";. However, I don't want to import it because this module does not use http module but provides helper functions.
After improve answer from IGx89 I got a shorter variant without typedef. I prefer this variant when I reference to another module one time:
/**
* #param {import('http').ClientRequest} req
*/
function setToken(req) {
}
But if you need reference to some type from another module with long path variant with typedef looks shorter.
Add the following to the top of your file:
/** #typedef {import('http').ClientRequest} ClientRequest */
I had this same problem myself (though regarding a module in my own app) and also had a very hard time finding the solution. I eventually figured out the above syntax by reading through this issue in the TypeScript GitHub repo: https://github.com/Microsoft/TypeScript/issues/14377
It does not work because it is a custom type JSDoc don't know. You have to setup your own definition with a #typedef.
/**
* A number, or a string containing a number.
* #typedef {(number|string)} NumberLike
*/
/**
* Set the magic number.
* #param {NumberLike} x - The magic number.
*/
function setMagicNumber(x) {
}
See the full examples on JSDoc typedef tag definition examples
I made an example which worked for me with JSDoc 3.5.3
/** #typedef {ClientRequest} TestReq */
/**
* #param {TestReq} req
*/
function setToken(req) {
}
JSDoc output image
I have a function that takes data from server:
function getData(data){
console.log(data.someVar);
}
WebStorm says that someVar is an unresolved variable.
How can I get rid of such warnings?
I see several options:
Suppress warnings in IDE settings;
Add a JSON source file with fields (details);
Use array-like syntax: data['some_unres_var'];
Also, WebStorm is offering me to create namespace for the "data" (add an annotation like /** #namespace data.some_unres_var*/), create such field, or rename it.
Use JSDoc:
/**
* #param {{some_unres_var:string}} data
*/
function getData(data){
console.log(data.some_unres_var);
}
JSDoc the object. Then its members.
/**
* #param data Information about the object.
* #param data.member Information about the object's members.
*/
function getData(data){
console.log(data.member);
}
#property for local variables (non parameters).
Tested in PyCharm. #Nicholi confirms it works in WebStorm.
The {{ member:type }} syntax Andreas suggested may conflict with Django templates.
Thanks to Jonny Buchanan's answer citing the #param wiki.
To document arrays of objects, use [] brackets as JSDoc suggests:
/**
* #param data
* #param data.array_member[].foo
*/
All other answers are incorrect for the general case. What if you don't get data as a parameter? You don't have JSDoc then:
function niceApiCall(parameters) {
const result = await ... // HTTP call to the API here
for (const e of result.entries) {
.. // decorate each entry in the result
}
return result;
}
WebStorm will warn that "result.entries" is an unresolved variable (field).
The general solution is to add an #namespace declaration:
function niceApiCall(parameters) {
/** #namespace result.entries **/
const result = await ... // HTTP call to the API here
for (const e of result.entries) {
.. // decorate each entry in the result
}
return result;
}
Destructuring use, Luke.
function getData(data){
const {member} = data;
console.log(member);
}
using a dummy js file with anonymous function expression returning the json literal, as written at http://devnet.jetbrains.com/message/5366907, may be a solution. I can also suggest creating a fake variable that will hold this json value, and use this var as a value of #param annotation to let WebStorm know what the actual type is. Like:
var jsontext = {"some_unres_var":"val"};
/** #param {jsontext} data */
function getData(data){
console.log(data.some_unres_var);
}
See also http://devnet.jetbrains.com/message/5504337#5504337
To remove the warnings on The WebStorm IDE you can simply uncheck the inspection options for:
Unresolved Javascript function
Unresolved Javascript variable
ps. this will remove the warnings on the IDE, that I don't think is the best idea, because we will lost one of the best utilities in a IDE like Webstorm, which can worsen the quality of our code.
Even so, if you want to follow in the menu: File > Settings > Editor > Inspections we can disable the Javascript warnings
Like the following picture:
I am trying to properly annotate all my Javascript code and am still a beginner in this field.
I get objects from a server call that are directly in json. Those objects are passed to functions and I call members directly. It obviously is very error prone while obfuscating so I am trying to annotate everything properly.
My understanding is that (i) I should create a class for this object even though it is never created directly with new and (ii) I should be careful with member names since they are fixed by the server response and should not be changed (or should be aliased beforehand).
I have two questions: are my asumptions correct ? how to do the annotation based on that.
Here is a sample code to illustrate
$.get("url.php", function(data) {
process(data);}, "json"); // <= returns {"a":"abc","b":1}
function process(data) {
$("#someElement").html(data.a + data.b);
}
Here is the class I was planning on creating for closure compilation purposes
/**
* The object that is sent back from the server
* #constructor
*/
function ServerResponse() {
/** #type {string} a */
this["a"] = "";
/** #type {number} b */
this["b"] = 0;
}
Here is the annotation for my process function
/**
* Process data from the server
* #param {ServerResponse} data: the Object sent back from the server
*/
Is my annotation correct? Is it robust to obfuscation?
Thanks a lot for your help
If you quote property names, you need to quote them consistently at every usage. If you haven't see this, you should read:
https://developers.google.com/closure/compiler/docs/api-tutorial3
So that your first snippet would be:
function process(data) {
$("#someElement").html(data['a'] + data['b']);
}
If you are trying to avoid quoting or if you would like the compiler to type check the usage of the properties (quoted properties references are not checked), you should define an extern file to include with the compilation of your source:
/**
* #fileoverview
* #externs
*/
/** #interface */
function ServerResponse() {}
/** #type {string} */
ServerResponse.prototype.a;
/** #type {number} */
ServerResponse.prototype.b;