|
||
---|---|---|
.. | ||
bin | ||
lib | ||
peg_lib | ||
peg_src | ||
schemas | ||
tests | ||
.eslintignore | ||
.eslintrc | ||
.jscsrc | ||
.travis.yml | ||
LICENSE-MIT.txt | ||
README.md | ||
index.js | ||
package.json |
README.md
jsdoctypeparser
The parser can parse:
- JSDoc type expressions
foo.bar
,String[]
- Closure Compiler type expressions
Array<string>
,function(arg1, arg2): ret
- JSDuck type definitions
Boolean/"top"/"bottom"
- some Typescript types
(x: number) => string
,typeof x
,import("./some-module")
- Complex type expressions
Array<Array<string>>
,function(function(Function))
Live demo
The live demo is available.
Usage
Parsing
var parse = require('jsdoctypeparser').parse;
var 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.
Publishing
We can stringify the AST nodes by using publish
.
var publish = require('jsdoctypeparser').publish;
var ast = {
type: 'GENERIC',
subject: {
type: 'NAME',
name: 'Array'
},
objects: [
{
type: 'NAME',
name: 'MyClass'
}
]
};
var string = publish(ast);
The string
becomes:
"Array<MyClass>"
Custom publishing
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>
Traversing
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 }>');
funciton onEnter(node) {
console.log('enter', node.type);
}
funciton onLeave(node) {
console.log('leave', node.type);
}
traverse(ast, onEnter, onLeave);
The output will be:
enter GENERIC
enter RECORD
enter RECORD_ENTRY
enter FUNCTION
leave FUNCTION
leave RECORD_ENTRY
enter RECORD_ENTRY
enter MEMBER
enter MEMBER
enter NAME
leave NAME
leave MEMBER
leave MEMBER
leave RECORD_ENTRY
leave RECORD
leave GENERIC
AST Specifications
NAME
Example:
/**
* @type {name}
*/
Structure:
{
"type": "NAME",
"name": string
}
MEMBER
Example:
/**
* @type {owner.name}
* @type {superOwner.owner.name}
*/
Structure:
{
"type": "MEMBER",
"name": string,
"owner": node,
"hasEventPrefix": boolean
}
INNER_MEMBER
Example:
/**
* @type {owner~name}
*/
Structure:
{
"type": "INNER_MEMBER",
"name": string,
"owner": node,
"hasEventPrefix": boolean
}
INSTANCE_MEMBER
Example:
/**
* @type {owner#name}
*/
Structure:
{
"type": "INSTANCE_MEMBER",
"name": string,
"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",
"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
}
Others
We can use a parenthesis to change operator orders.
/**
* @type {(module:path/to/file.js).foo}
*/