jsdoctypeparser

9.0.0 • Public • Published

jsdoctypeparser

Build Status NPM version

The parser can parse:

Live demo

The live demo is available.

Usage (Programmatic)

Parsing

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.

Publishing

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>"

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 }>');
 
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

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,
  "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)} 
 */

Structure:

{
  "type": "UNION",
  "left": node,
  "right": node
}

INTERSECTION

Example:

/**
 * @type {left&right}
 * @type {(left&right)}
 */

Structure:

{
  "type": "INTERSECTION",
  "left": node,
  "right": node
}

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
}

Others

We can use a parenthesis to change operator orders.

/**
 * @type {(module:path/to/file.js).foo}
 */

Usage (CLI)

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.

License

This script is licensed under the MIT.

Package Sidebar

Install

npm i jsdoctypeparser

Weekly Downloads

349,086

Version

9.0.0

License

MIT

Unpacked Size

810 kB

Total Files

42

Last publish

Collaborators

  • orgachem