Do primitive type names need to be uppercase or lowercase? - jsdoc

/**
* #param {String} foo
* #param {Number} bar
*/
or
/**
* #param {string} foo
* #param {number} bar
*/
JSDoc #type documentation is not being explicit about it.
I always uppercase String and Number because it is my understanding that I need to use the constructor name. In JavaScript, String and Number exist as constructors.
I have noticed inconsistency: I am defining other primitive types (e.g. null, undefined) as lowercase.
Do primitive type names need to be uppercase or lowercase?

It doesn't matter:
JSDoc doesn't care. It's up to the user's preference. I tend to use lowercase for primitive types (and function, for some reason) and uppercase for Array and Object.
I tend to use lowercase because the typeof operator returns lowercase.

Related

VSCode IntelliSense does not autocomplete JavaScript DOM events and methods

I am using Visual Studio Code version 1.17.1.
In *.js file when I type document.querySelector("#elementId").style. I have no IntelliSense hints for styles (like margin, display, etc.).
Even no onclick event hint after document.querySelector("#elementId").
I don't use any npm packages. It is just simple html\css\js project.
How to turn on correct IntelliSense hints? Thanks.
Because result of the querySelector is either:
Element - the most general base class or null
If you already know id you can use document.getElementById() - which returns instance of more specific class - HTMLElement - autocomplete will work as expected.
document.getElementById('elementId').
If you don't know id, but want autocomplete you can use JSDoc type annotations:
/** #type {HTMLElement} */
var el = document.querySelector(".myclass");
el.
// or without extra variable:
/** #type {HTMLElement} */
(document.querySelector(".myclass")).
I haven't really tested it but you can try something like that:
/**
* #type {function(string): HTMLElement}
*/
var querySelector = document.querySelector.bind(document);
querySelector('.myclass').
Another choice would be alter typescript types:
Create file dom.d.ts
Append to it:
interface NodeSelector {
querySelector<K extends keyof ElementTagNameMap>(selectors: K): ElementTagNameMap[K] | null;
querySelector<E extends HTMLElement = HTMLElement>(selectors: string): E | null;
querySelectorAll<K extends keyof ElementListTagNameMap>(selectors: K): ElementListTagNameMap[K];
querySelectorAll<E extends HTMLElement = HTMLElement>(selectors: string): NodeListOf<E>;
}
Now querySelector returns HTMLElement.
The other answer points to the correct answer – type casting with jsdoc – but I've found that this only works consistently when you do it exactly as typescript wants when dealing with union types: you need to wrap the casted expression in parentheses and place the type cast doc on the same line. The snippet from a permalink to the wiki:
// We can "cast" types to other types using a JSDoc type assertion
// by adding an `#type` tag around any parenthesized expression.
/**
* #type {number | string}
*/
var numberOrString = Math.random() < 0.5 ? "hello" : 100;
var typeAssertedNumber = /** #type {number} */ (numberOrString)

JSDoc typedef in a separate file

Can I define all custom types in a separate file (e.g. types.jsdoc), so that they can be reused throughout the application? What's the right way to do it?
/**
* 2d coordinates.
* #typedef {Object} Coordinates
* #property {Number} x - Coordinate x.
* #property {Number} y - Coordinate y.
*/
You can define types in a module (eg. typedefs.js). The module contains your JSDoc typdefs and can simply export an unused property.
// typedefs.js
/**
* #typdef foo
* #property {string} bar
*/
// etc.
exports.unused = {};
To use it, import the module where you need to reference these typdefs:
const typedefs = require("./typedefs");
/** #type {typedefs.foo} */
const fb = { bar: "hello" };
You may wish to annotate typedefs.js as a #module or #namespace. Because I'm using "tsd-jsdoc" to generate a types.d.ts file, and due to the way TypeScript now interprets modules vs. namespaces, I've annotated my typedefs.js file as a #namespace and documented each typedef as a member of that namespace:
/**
* #namespace typedefs
*/
/**
* #typedef foo
* #property {string} bar
* #memberof typdefs
*/
Hope that helps.
This is a TypeScript-flavored JSDoc specific answer, but I'm having success using a triple-slash directive to "import" all the types from another file. This has the advantage of not actually adding an unused import which can upset linters and bundlers.
I'm putting my shared types in one file called typedefs.js like this:
// typedefs.js
/**
* #typedef {Object} Foo
* #property {string} bar
*/
/**
* #typedef {Object} Baz
* #property {number} buzz
*/
and then using /// <reference path="typedefs.js" /> in the other files to access the shared types like this:
// randomThing.js
/// <reference path="typedefs.js" />
/**
* Turn a Foo into a Baz
*
* #param {Foo} a
* #return {Baz}
export function (a) {
return { buzz: a.bar.length };
}
The tricky thing though is that now typedefs.js is just being referenced in a comment, bundlers like rollup miss it completely. So I'm combining it with my old consts.js that exports a few constants and is imported in at least one place. That way the typedefs are still included in the rollup output.
I hope someone else finds this helpful.
p.s. rollup will completely exclude a pure JSDoc typedefs.js file _even if you have import './typedefs.js' because of tree-shaking! Gotta run rollup with --no-treeshake to keep those comments in the rollup output.
In vscode, the import('./path/to/types.js').def tag works perfectly fine.
For e.g.
types.js
/**
* #typedef {Object} connection
* #property {String} id
* #property {Number} pingRetries
* #property {(data:Object) => void} sendJSON
*/
exports.unused = {};
And someFile.js
/**
* #param {import('./types').connection} param
*/
const someFunc = (param) => {}
Also, note that the exports.unused = {} is necessary in the types.js file, otherwise the auto-import of import('./types') would not work and you may have to type it by yourself.
I just tried with VSCode and it works only if the separate file is opened in the editor. If not, external typedefs are typed as any
I usually do something similar in my projects, the difference being I use the extension .js to name the file. Webstorm works perfectly and is able to check types and auto-complete just fine. It won't recognize the .jsdoc extension (I just checked), so stick to .js even if the file doesn't contain any code statement.
I've had success with simply creating my types in a typedefs.js file and referencing using the ts/vscode import(path/to/file).Foo tag. JSDoc does not support this syntax out of the box, so I suggest also using jsdoc-tsimport-plugin in order to parse your docs.
Eg: typedef.js:
/**
* #typedef {Object} Foo
* #property {string} id
*/
/**
* #typedef {Object} Bar
* #property {string[]} things
*/
// having to export an empty object here is annoying,
// but required for vscode to pass on your types.
export {};
coolFunction.js
/**
* This function is super dope
* #param {import('../typedef').Foo[]} foo - a foo
* #return {import('../typedef').Bar[]} bar - an array of bars
*/
export function (foo) {
// do cool things
return bar;
}
I'm also using tsd-jsdoc to create a types.d.ts file, and this implementation is successfully creating the types. I had trouble with declaring modules and namespaces with the types file— just creating standalone typedefs for said models worked best for me.

What is the correct object assessor for sys categories

I want to access the title of the first (and only) category form my object.
See screen attached.
Which object assessor do i use?
Because ObjectStorages have no numeric index, I've created an own viewhelper (in DCE extension) to make the array of ObjectStorages numeric. It also returns you the given index.
Example: {spareparts.0.categories -> dce:arrayGetIndex(index:1)}
This returns the second category. Default is index:0, which returns the first item.
This approach is better than using a f:for loop with iterator.isFirst. If there are many categories in the query result, this could become a performance issue.
The code of this viewhelper is pretty simple:
<?php
namespace ArminVieweg\Dce\ViewHelpers;
/* | This extension is made for TYPO3 CMS and is licensed
* | under GNU General Public License.
* |
* | (c) 2012-2017 Armin Ruediger Vieweg <armin#v.ieweg.de>
*/
/**
* Returns the given index of an array.
*
* #package ArminVieweg\Dce
*/
class ArrayGetIndexViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper
{
/**
* Returns the value of the given index in the given array. To make sure the indexes are numeric the array will be
* converted. Named array keys will be overwritten by ascending index numbers (starting with 0).
*
* #param array $subject The array to get the value of
* #param int|string $index Index of array. May be int or string. Default is zero (0).
* #return mixed The value of the given array index
*/
public function render(array $subject = null, $index = 0)
{
if ($subject === null) {
$subject = $this->renderChildren();
}
$subject = array_values($subject);
return $subject[$index];
}
}
Source: https://bitbucket.org/ArminVieweg/dce/src/fc30918f1bdbdf13dbe4f0a3d9abd9c59a7385b2/Classes/ViewHelpers/ArrayGetIndexViewHelper.php
Hope It helps.

How to declare unlimited/variadic parameters in DocBlock?

Lets say I have a function (obviously a trivial example):
public function dot(){
return implode('.', func_get_args());
}
Now I know I could modify this to be
public function dot(array $items){
return implode('.', $array);
}
but with some functions that is not an option. So, how would you document the first version of the function with a docBlock so an IDE can interpret that it can receive unlimited parameters?
I have seen some methods that use:
/**
* Joins one or more strings together with a . (dot)
* #param string $string1
* #param string $string2
* #param string $_ [optional]
* #return string
*/
public function dot($string1, $string2, $_ = null) {
return implode('.', func_get_args());
}
Which in an IDE looks like
But that feels like a hack to me, is there no way to do it just with docBlock?
[UPDATED 2015-01-08]
Old way to do this in PHPDoc was:
http://manual.phpdoc.org/HTMLSmartyConverter/HandS/phpDocumentor/tutorial_tags.param.pkg.html
/**
* #param int $param,...
**/
However, this is no longer supported. As of PHP 5.6 Variadic Method Parameters are a part of the PHP language, and the PHPDoc's have been updated to reflect this as of PHPDoc 2.4 if I recall correctly. This is also in the PhpStorm IDE as of EAP 139.659 (should be in 8.0.2 and up). Not sure about implementation of other IDEs.
https://youtrack.jetbrains.com/issue/WI-20157
In any case, proper syntax for DocBlocks going forward for variadic parameters is:
/**
* #param int ...$param
**/
As Variadics are implemented in PHP 5.6 PHPDocumentor should support the following syntax as of version 2.4.
/**
* #param Type ...$value
* Note: PHP 5.6+ syntax equal to func_get_args()
*/
public function abc(Type ...$value) {}
This should be the correct way to describe such a signature. This will likely be included in PSR-5. Once that is accepted IDE's should follow to support this "official" recommendation.
However, in the mean time some IDE's have an improved understanding of what they consider correct. Hit hard on the IDE vendor to support the offical PHP syntax that is supported as of 5.6 or use whatever works in the meantime.
In php the concept of valist or list of "optional arguments" does not exist.
the $_ variable will just contain, here the third string you give.
The only way to allow an array OR a string is to test the first argument with is_array()
public function dot($arg1){
if(is_array($arg1)){
return implode('.',$arg1);
}
else if $arg1 instanceof \Traversable){
return implode('.',iterator_to_array($arg1));
}
else{
return implode('.',func_get_args());
}
}
Now that you handled the behaviour you want, you have to document it. In php, as overloading is not allowed, a convention is to use "mixed" as a type if you want to provide multiple types.
/**
*#param mixed $arg1 an array, iterator that will be joined OR first string of the list
*#return string a string with all strings of the list joined with a point
*#example dot("1","2","3"); returns 1.2.3 dot(array(1,2,3)); returns 1.2.3
*/
Moreover, according to phpdocumentor documentation you can declare sort of valist with
/**
*#param string ... list of strings
*/

doxygen function parameter documentation (//!< vs #param)

If I use "after the member" documentation for function parameters, for example, use //!< after each parameter, instead of #param in the header, the "Parameters" section is always placed after "Return" in the generated output file.
Is is possible to define the order so that "Parameters" will be placed before "Return"?
/**
*****************************************************************************************
* #brief Test API
*
* #usage This API can be called at any time
*
* #return 0 if successful; or 1 if failed
****************************************************************************************/
int TestAPI(
int argument1, //!< first argument
int argument2 //!< second argument
);
I've just tried out your code with Doxygen 1.7.5.1, and confirmed that with your code, the Parameter list in the output comes after the description of Return.
This is a shame, as the //!< style is much nicer than having to re-state the names of all the parameters with #param:
/**
*****************************************************************************************
* #brief Test API
*
* #usage This API can be called at any time
*
* #param argument1 first argument
* #param argument2 second argument
*
* #return 0 if successful; or 1 if failed
****************************************************************************************/
int TestAPI2(
int argument1,
int argument2
);
I had a look in the Doxygen Bugzilla bug database, to see if it was a relatively recent bug (as then you could try reverting to an older installation).
I believe you've found Doxygen Bug 316311: 'parameter documentation after return documentation by using inline comments', which was reported in September 2005, and hasn't been fixed.
So, sadly, I'm afraid the answer to your question Is is possible to define the order so that "Parameters" will be placed before "Return"? is almost certainly No.
Edit
I've just added a note to Doxygen Bug 316311, asking for it to be changed to Status=CONFIRMED.