The parser can parse:
foo.bar
, String[]
Array<string>
, function(arg1, arg2): ret
Boolean/"top"/"bottom"
(x: number) => string
, typeof x
, import("./some-module")
Array<Array<string>>
, function(function(Function))
The live demo is available.
const {parse} = require('jsdoctypeparser'); const ast = parse('Array<MyClass>');
The ast
becomes:
{ "type": "GENERIC", "subject": { "type": "NAME", "name": "Array" }, "objects": [ { "type": "NAME", "name": "MyClass" } ], "meta": { "syntax": "ANGLE_BRACKET" } }
See the AST specifications.
We can stringify the AST nodes by using publish
.
const {publish} = require('jsdoctypeparser'); const ast = { type: 'GENERIC', subject: { type: 'NAME', name: 'Array' }, objects: [ { type: 'NAME', name: 'MyClass' } ] }; const string = publish(ast);
The string
becomes:
"Array<MyClass>"
We can change the stringification strategy by using the 2nd parameter of publish(node, publisher)
. The publisher
MUST have handlers for all node types (see lib/NodeType.js
).
And we can override default behavior by using createDefaultPublisher
.
const {publish, createDefaultPublisher} = require('jsdoctypeparser'); const ast = { type: 'NAME', name: 'MyClass', }; const customPublisher = createDefaultPublisher(); customPublisher.NAME = (node, pub) => `<a href="./types/${node.name}.html">${node.name}</a>`; const string = publish(ast, customPublisher);
The string
becomes:
<a href="./types/MyClass.html">MyClass</a>
We can traverse the AST by using traverse
. This function takes 3 parameters (a node and an onEnter handler, an onLeave handler). The handlers take a visiting node.
const {parse, traverse} = require('jsdoctypeparser'); const ast = parse('Array<{ key1: function(), key2: A.B.C }>'); function onEnter(node, parentName, parentNode) { console.log('enter', node.type, parentName, parentNode.type); } function onLeave(node, parentName, parentNode) { console.log('leave', node.type, parentName, parentNode.type); } traverse(ast, onEnter, onLeave);
The output will be:
enter GENERIC null null enter NAME subject GENERIC leave NAME subject GENERIC enter RECORD objects GENERIC enter RECORD_ENTRY entries RECORD enter FUNCTION value RECORD_ENTRY leave FUNCTION value RECORD_ENTRY leave RECORD_ENTRY entries RECORD enter RECORD_ENTRY entries RECORD enter MEMBER value RECORD_ENTRY enter MEMBER owner MEMBER enter NAME owner MEMBER leave NAME owner MEMBER leave MEMBER owner MEMBER leave MEMBER value RECORD_ENTRY leave RECORD_ENTRY entries RECORD leave RECORD objects GENERIC leave GENERIC null null
NAME
Example:
/** * @type {name} */
Structure:
{ "type": "NAME", "name": string }
MEMBER
Example:
/** * @type {owner.name} * @type {superOwner.owner.name} */
Structure:
{ "type": "MEMBER", "name": string, "quoteStyle": "none", "owner": node, "hasEventPrefix": boolean }
INNER_MEMBER
Example:
/** * @type {owner~name} */
Structure:
{ "type": "INNER_MEMBER", "name": string, "quoteStyle": "none", "owner": node, "hasEventPrefix": boolean }
INSTANCE_MEMBER
Example:
/** * @type {owner#name} */
Structure:
{ "type": "INSTANCE_MEMBER", "name": string, "quoteStyle": "none", "owner": node, "hasEventPrefix": boolean }
UNION
Example:
/** * @type {left|right} * @type {(left|right)} * @type {left/right} */
Structure:
{ "type": "UNION", "left": node, "right": node, "meta": { "syntax": ("PIPE" or "SLASH") } }
RECORD
Example:
/** * @type {{}} * @type {{ key: value }} * @type {{ key: value, anyKey }} */
Structure:
{ "type": "RECORD", "entries": [ recordEntryNode, recordEntryNode, ... ] }
RECORD_ENTRY
Structure:
{ "type": "RECORD_ENTRY", "key": string, "value": node (or null) }
GENERIC
Example:
/** * @type {Subject<Object, Object>} * @type {Object[]} */
Structure:
{ "type": "GENERIC", "subject": node, "objects": [ node, node, ... ], "meta": { "syntax": ("ANGLE_BRACKET" or "ANGLE_BRACKET_WITH_DOT" or "SQUARE_BRACKET") } }
FUNCTION
Example:
/** * @type {function()} * @type {function(param, param): return} * @type {function(this: Context)} * @type {function(new: Class)} */
Structure:
{ "type": "FUNCTION", "params": [ node, node, ... ], "returns": node (or null), "new": node (or null), "this": node (or null) }
OPTIONAL
Example:
/** * @type {Optional=} */
Structure:
{ "type": "OPTIONAL", "value": node, "meta": { "syntax": ("PREFIX_EQUALS_SIGN" or "SUFFIX_EQUALS_SIGN") } }
NULLABLE
Example:
/** * @type {?Nullable} */
Structure:
{ "type": "NULLABLE", "value": node, "meta": { "syntax": ("PREFIX_QUESTION_MARK" or "SUFFIX_QUESTION_MARK") } }
NOT_NULLABLE
Example:
/** * @type {!NotNullable} */
Structure:
{ "type": "NOT_NULLABLE", "value": node, "meta": { "syntax": ("PREFIX_BANG" or "SUFFIX_BANG") } }
VARIADIC
Example:
/** * @type {...Variadic} * @type {Variadic...} * @type {...} */
Structure:
{ "type": "VARIADIC", "value": node (or null), "meta": { "syntax": ("PREFIX_DOTS" or "SUFFIX_DOTS" or "ONLY_DOTS") } }
MODULE
Example:
/** * @type {module:path/to/file.Module} */
Structure:
{ "type": "MODULE", "value": node }
FILE_PATH
Example:
/** * @type {module:path/to/file.Module} * ^^^^^^^^^^^^ */
Structure:
{ "type": "FILE_PATH", "path": string }
EXTERNAL
Example:
/** * @type {external:External} */
Structure:
{ "type": "EXTERNAL", "value": node }
STRING_VALUE
Example:
/** * @type {"abc"} * @type {"can\"escape"} */
Structure:
{ "type": "STRING_VALUE", "quoteStyle": "double", "string": string }
NUMBER_VALUE
Example:
/** * @type {123} * @type {0b11} * @type {0o77} * @type {0xff} */
Structure:
{ "type": "NUMBER_VALUE", "number": string }
ANY
Example:
/** * @type {*} */
Structure:
{ "type": "ANY" }
UNKNOWN
Example:
/** * @type {?} */
Structure:
{ "type": "UNKNOWN" }
PARENTHESIS
Example:
/** * @type {(Foo)} */
Structure:
{ "type": "PARENTHESIS", "value": node }
We can use a parenthesis to change operator orders.
/** * @type {(module:path/to/file.js).foo} */
To parse a type into a JSON structure, you may pass a string argument containing the structure to parse (with the JSON results equivalent to the parsing example above):
jsdoctypeparser 'Array<MyClass>'
Note: There is no need to prefix the path to the jsdoctypeparser
binary, e.g., with ./node_modules/.bin/
when you are running within one of the package.json
scripts
or if you have installed the package globally.