Skip to content

Commit 73d6118

Browse files
committed
Implement all doctrine-emitted types. Fixes #249
1 parent 571137a commit 73d6118

File tree

88 files changed

+1681
-670
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+1681
-670
lines changed

Diff for: lib/format_type.js

+134
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
var Syntax = require('doctrine').Syntax,
2+
globalsDocs = require('globals-docs'),
3+
u = require('unist-builder');
4+
5+
function t(text) {
6+
return u('text', text);
7+
}
8+
9+
function link(text) {
10+
var docs = globalsDocs.getDoc(text);
11+
if (docs) {
12+
return u('link', { href: docs }, [u('text', text)]);
13+
}
14+
return u('text', text);
15+
}
16+
17+
function commaList(getNamedLink, items, start, end, sep) {
18+
var res = [];
19+
if (start) {
20+
res.push(t(start));
21+
}
22+
for (var i = 0, iz = items.length; i < iz; ++i) {
23+
res = res.concat(formatType(items[i], getNamedLink));
24+
if (i + 1 !== iz) {
25+
res.push(t(sep || ', '));
26+
}
27+
}
28+
if (end) {
29+
res.push(t(end));
30+
}
31+
return res;
32+
}
33+
34+
function decorate(formatted, str, prefix) {
35+
if (prefix) {
36+
return [t(str)].concat(formatted);
37+
}
38+
return formatted.concat(t(str));
39+
}
40+
41+
/**
42+
* Helper used to format JSDoc-style type definitions into HTML or Markdown.
43+
*
44+
* @name formatType
45+
* @param {Object} node type object in doctrine style
46+
* @param {function(text): text} getNamedLink a function that tries
47+
* to find a URL to point a named link to
48+
* @returns {string} string
49+
* @example
50+
* var x = { type: 'NameExpression', name: 'String' };
51+
* // in template
52+
* // {{ type x }}
53+
* // generates String
54+
*/
55+
function formatType(node, getNamedLink) {
56+
var result = [];
57+
58+
if (!node) {
59+
return [];
60+
}
61+
62+
switch (node.type) {
63+
case Syntax.NullableLiteral:
64+
return [t('?')];
65+
case Syntax.AllLiteral:
66+
return [t('Any')];
67+
case Syntax.NullLiteral:
68+
return [t('null')];
69+
case Syntax.VoidLiteral:
70+
return [t('void')];
71+
case Syntax.UndefinedLiteral:
72+
return [link('undefined')];
73+
case Syntax.NameExpression:
74+
return [link(node.name)];
75+
case Syntax.ParameterType:
76+
return [t(node.name + ': ')].concat(formatType(node.expression, getNamedLink));
77+
78+
case Syntax.TypeApplication:
79+
return formatType(node.expression, getNamedLink)
80+
.concat(commaList(getNamedLink, node.applications, '.&lt;', '&gt;'));
81+
case Syntax.UnionType:
82+
return commaList(getNamedLink, node.elements, '(', ')', '|');
83+
case Syntax.ArrayType:
84+
return commaList(getNamedLink, node.elements, '&#91;', '&#93;');
85+
case Syntax.RecordType:
86+
return commaList(getNamedLink, node.fields, '{', '}');
87+
88+
case Syntax.FieldType:
89+
if (node.value) {
90+
return [t(node.key + ': ')].concat(formatType(node.value, getNamedLink));
91+
}
92+
return [t(node.key)];
93+
94+
case Syntax.FunctionType:
95+
result = [t('function (')];
96+
97+
if (node['this']) {
98+
if (node['new']) {
99+
result.push(t('new: '));
100+
} else {
101+
result.push(t('this: '));
102+
}
103+
104+
result = result.concat(formatType(node['this'], getNamedLink));
105+
106+
if (node.params.length !== 0) {
107+
result.push(t(', '));
108+
}
109+
}
110+
111+
result = result.concat(commaList(getNamedLink, node.params, '', ')'));
112+
113+
if (node.result) {
114+
result = result.concat([t(': ')].concat(formatType(node.result, getNamedLink)));
115+
}
116+
return result;
117+
118+
case Syntax.RestType:
119+
// note that here we diverge from doctrine itself, which
120+
// lets the expression be omitted.
121+
return decorate(formatType(node.expression, getNamedLink), '...', true);
122+
case Syntax.OptionalType:
123+
return decorate(formatType(node.expression, getNamedLink), '=');
124+
case Syntax.NonNullableType:
125+
return decorate(formatType(node.expression, getNamedLink), '!', node.prefix);
126+
case Syntax.NullableType:
127+
return decorate(formatType(node.expression, getNamedLink), '?', node.prefix);
128+
129+
default:
130+
throw new Error('Unknown type ' + node.type);
131+
}
132+
}
133+
134+
module.exports = formatType;

Diff for: lib/html_helpers.js

+54-75
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,44 @@
11
'use strict';
22

3-
var getGlobalExternalLink = require('globals-docs').getDoc,
3+
var getDoc = require('globals-docs').getDoc,
4+
formatType = require('./format_type'),
45
mdast = require('mdast'),
56
html = require('mdast-html'),
67
inlineLex = require('jsdoc-inline-lex');
78

8-
/**
9-
* Format a description and target as a Markdown link.
10-
*
11-
* @param {string} description the text seen as the link
12-
* @param {string} href where the link goes
13-
* @return {string} markdown formatted link
14-
*/
15-
function markdownLink(description, href) {
16-
return '[`' + description + '`](' + href + ')';
17-
}
18-
199
/**
2010
* Format link & tutorial tags with simple code inline tags.
2111
*
12+
* @param {Array<string>} paths potential linkable namepaths
2213
* @param {string} text input - typically a description
2314
* @returns {string} markdown-friendly output
2415
* @private
2516
* @example
2617
* formatInlineTags('{@link Foo}'); // "[Foo](#foo)"
2718
*/
28-
function formatInlineTags(text) {
19+
function formatInlineTags(paths, text) {
2920
var output = '';
3021
var tokens = inlineLex(text);
3122

3223
for (var i = 0; i < tokens.length; i++) {
3324
if (tokens[i].type === 'text') {
3425
output += tokens[i].capture[0];
3526
} else if (tokens[i].type === 'link') {
36-
var parts = tokens[i].capture[1].split(/\s|\|/);
37-
if (parts.length === 1) {
38-
output += markdownLink(tokens[i].capture[1], tokens[i].capture[1]);
27+
var described = tokens[i].capture[1].match(/([^\s|\|]*)(\s|\|)(.*)/);
28+
if (described) {
29+
// 1 is the match, 3 is description
30+
output += autolink(paths, described[1], described[3]);
3931
} else {
40-
output += markdownLink(parts.slice(1).join(' '), parts[0]);
32+
output += autolink(paths, tokens[i].capture[1]);
4133
}
4234
} else if (tokens[i].type === 'prefixLink') {
43-
output += markdownLink(tokens[i].capture[1], tokens[i].capture[2]);
35+
output += autolink(paths, tokens[i].capture[1], tokens[i].capture[2]);
4436
}
4537
}
4638

4739
return output;
4840
}
4941

50-
/**
51-
* Link text to this page or to a central resource.
52-
* @param {Array<string>} paths list of valid namespace paths that are linkable
53-
* @param {string} text inner text of the link
54-
* @returns {string} potentially linked HTML
55-
*/
56-
function autolink(paths, text) {
57-
if (paths.indexOf(text) !== -1) {
58-
return '<a href="#' + text + '">' + text + '</a>';
59-
} else if (getGlobalExternalLink(text)) {
60-
return '<a href="' + getGlobalExternalLink(text) + '">' + text + '</a>';
61-
}
62-
return text;
63-
}
64-
65-
/**
66-
* Helper used to format JSDoc-style type definitions into HTML.
67-
*
68-
* @name formatType
69-
* @param {Object} type type object in doctrine style
70-
* @param {Array<string>} paths valid namespace paths that can be linked
71-
* @returns {string} string
72-
* @example
73-
* var x = { type: 'NameExpression', name: 'String' };
74-
* // in template
75-
* // {{ type x }}
76-
* // generates String
77-
*/
78-
function formatType(type, paths) {
79-
if (!type) {
80-
return '';
81-
}
82-
function recurse(element) {
83-
return formatType(element, paths);
84-
}
85-
switch (type.type) {
86-
case 'NameExpression':
87-
return '<code>' + autolink(paths, type.name) + '</code>';
88-
case 'UnionType':
89-
return type.elements.map(recurse).join(' or ');
90-
case 'AllLiteral':
91-
return 'Any';
92-
case 'RestType':
93-
return '...' + formatType(type.expression, paths);
94-
case 'OptionalType':
95-
case 'NullableType':
96-
return '<code>[' + formatType(type.expression, paths) + ']</code>';
97-
case 'TypeApplication':
98-
return formatType(type.expression, paths) + '&lt;' +
99-
type.applications.map(recurse).join(', ') + '&gt;';
100-
case 'UndefinedLiteral':
101-
return 'undefined';
102-
}
103-
}
104-
10542
/**
10643
* Format a parameter name. This is used in formatParameters
10744
* and just needs to be careful about differentiating optional
@@ -131,6 +68,35 @@ function formatParameters() {
13168
}).join(', ') + ')';
13269
}
13370

71+
/**
72+
* Link text to this page or to a central resource.
73+
* @param {Array<string>} paths list of valid namespace paths that are linkable
74+
* @param {string} text inner text of the link
75+
* @returns {string?} potentially a url
76+
*/
77+
function getNamedLink(paths, text) {
78+
if (paths.indexOf(text) !== -1) {
79+
return '#' + text;
80+
} else if (getDoc(text)) {
81+
return getDoc(text);
82+
}
83+
}
84+
85+
/**
86+
* Link text to this page or to a central resource.
87+
* @param {Array<string>} paths list of valid namespace paths that are linkable
88+
* @param {string} text inner text of the link
89+
* @param {string} description link text override
90+
* @returns {string} potentially linked HTML
91+
*/
92+
function autolink(paths, text, description) {
93+
var url = getNamedLink(paths, text);
94+
if (url) {
95+
return '<a href="' + url + '">' + (description || text) + '</a>';
96+
}
97+
return text;
98+
}
99+
134100
/**
135101
* Given a Handlebars instance, register helpers
136102
*
@@ -139,6 +105,7 @@ function formatParameters() {
139105
* @returns {undefined} invokes side effects on Handlebars
140106
*/
141107
function htmlHelpers(Handlebars, paths) {
108+
142109
Handlebars.registerHelper('permalink', function () {
143110
return this.path.join('.');
144111
});
@@ -147,6 +114,10 @@ function htmlHelpers(Handlebars, paths) {
147114

148115
Handlebars.registerHelper('format_params', formatParameters);
149116

117+
var htmlOptions = {
118+
entities: false
119+
};
120+
150121
/**
151122
* This helper is exposed in templates as `md` and is useful for showing
152123
* Markdown-formatted text as proper HTML.
@@ -161,11 +132,19 @@ function htmlHelpers(Handlebars, paths) {
161132
* // generates <h2>foo</h2>
162133
*/
163134
Handlebars.registerHelper('md', function formatMarkdown(string) {
164-
return new Handlebars.SafeString(mdast().use(html).process(formatInlineTags(string)));
135+
return new Handlebars.SafeString(mdast().use(html, htmlOptions)
136+
.process(formatInlineTags(paths, string)));
165137
});
166138

167139
Handlebars.registerHelper('format_type', function (type) {
168-
return formatType(type, paths);
140+
if (!type) {
141+
return '';
142+
}
143+
return new Handlebars.SafeString(mdast().use(html, htmlOptions)
144+
.stringify({
145+
type: 'root',
146+
children: formatType(type, paths)
147+
}));
169148
});
170149
}
171150

Diff for: lib/markdown_format_type.js

-29
This file was deleted.

Diff for: lib/output/markdown_ast.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
var mdast = require('mdast'),
22
u = require('unist-builder'),
3-
formatType = require('../markdown_format_type'),
3+
formatType = require('../format_type'),
44
formatInlineTags = require('../format_inline_tags'),
55
hljs = require('highlight.js');
66

@@ -35,7 +35,7 @@ function commentsToAST(comments, opts, callback) {
3535
u('paragraph', [
3636
u('inlineCode', param.name),
3737
u('text', ' '),
38-
!!param.type && u('strong', [u('text', formatType(param.type))]),
38+
!!param.type && u('strong', formatType(param.type)),
3939
u('text', ' ')
4040
].concat(mdast.parse(formatInlineTags(param.description)).children)
4141
.concat([
@@ -71,7 +71,7 @@ function commentsToAST(comments, opts, callback) {
7171
u('paragraph', [
7272
u('inlineCode', property.name),
7373
u('text', ' '),
74-
u('strong', [u('text', formatType(property.type))]),
74+
u('strong', formatType(property.type)),
7575
u('text', ' ')
7676
]
7777
.concat(mdast.parse(formatInlineTags(property.description)).children)
@@ -93,7 +93,7 @@ function commentsToAST(comments, opts, callback) {
9393
return !!comment.returns && comment.returns.map(function (returns) {
9494
return u('paragraph', [
9595
u('text', 'Returns '),
96-
u('strong', [u('text', formatType(returns.type))]),
96+
u('strong', formatType(returns.type)),
9797
u('text', ' ')
9898
].concat(mdast.parse(formatInlineTags(returns.description)).children));
9999
});

0 commit comments

Comments
 (0)