umberto 2.2.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +2 -2
- package/LICENSE.md +1 -1
- package/hexo-shim.js +1 -1
- package/package.json +2 -1
- package/scripts/filter/after-post-render/basepath-replacer.js +1 -1
- package/scripts/filter/after-post-render/fix-code-samples.js +1 -1
- package/scripts/filter/after-post-render/gather-guides.js +1 -1
- package/scripts/filter/after-post-render/img-linker.js +1 -1
- package/scripts/filter/after-post-render/import-guide.js +1 -1
- package/scripts/filter/after-post-render/insert-error-codes.js +1 -1
- package/scripts/filter/after-post-render/linker.js +1 -1
- package/scripts/filter/after-post-render/parseicontag.js +1 -1
- package/scripts/filter/after-post-render/process-variables.js +1 -1
- package/scripts/filter/after-post-render/snippets.js +1 -1
- package/scripts/filter/after-post-render/time-end.js +1 -1
- package/scripts/filter/after-post-render/time-start.js +1 -1
- package/scripts/filter/after-post-render/validate-after-render.js +1 -1
- package/scripts/filter/before-post-render/add-project-info-to-page.js +1 -1
- package/scripts/filter/before-post-render/add-repo-url.js +1 -1
- package/scripts/filter/before-post-render/change-output-path.js +1 -1
- package/scripts/filter/before-post-render/escape-special-characters.js +1 -1
- package/scripts/filter/before-post-render/execute-and-insert-function-results.js +1 -1
- package/scripts/filter/before-post-render/infobox.js +1 -1
- package/scripts/filter/before-post-render/insertchangelog.js +1 -1
- package/scripts/filter/before-post-render/replace-macros.js +1 -1
- package/scripts/filter/before-post-render/set-layout.js +1 -1
- package/scripts/filter/before-post-render/validate-page-data.js +1 -1
- package/scripts/helper/find-main-category-page.js +1 -1
- package/scripts/helper/get-pages-for-nav-tree.js +1 -1
- package/scripts/helper/mark-empty-categories.js +1 -1
- package/scripts/helper/normalize-badges.js +1 -1
- package/scripts/helper/u-split-to-title-and-content.js +1 -1
- package/scripts/helper/u-toc.js +1 -1
- package/scripts/utils/execute-and-insert-function-results.js +1 -1
- package/scripts/utils/findmaincategorypage.js +1 -1
- package/scripts/utils/getreportissuewidgeturl.js +1 -1
- package/scripts/utils/insertchangelog.js +1 -1
- package/scripts/utils/normalizebadges.js +1 -1
- package/scripts/utils/parseicontag.js +1 -1
- package/scripts/utils/parselinks.js +61 -41
- package/scripts/utils/shoulddisplaynewindicator.js +1 -1
- package/scripts/utils/transforminfobox.js +1 -1
- package/scripts-dev/postinstall.js +1 -1
- package/src/api-builder/api-builder.js +28 -8
- package/src/api-builder/classes/description-parser.js +79 -63
- package/src/api-builder/classes/doc-data-factory.js +58 -5
- package/src/api-builder/classes/file-name-manager.js +1 -1
- package/src/api-builder/classes/html-file.js +1 -1
- package/src/api-builder/classes/navigation-tree.js +1 -1
- package/src/api-builder/classes/tree-node.js +1 -1
- package/src/api-builder/utils/findtargetdoclet.js +84 -0
- package/src/api-builder/utils/utils.js +41 -0
- package/src/data-converter/converters/jsdoc2umberto.js +8 -1
- package/src/data-converter/converters/jsduck2umberto.js +1 -1
- package/src/data-converter/converters/typedoc/abstractparser.js +364 -0
- package/src/data-converter/converters/typedoc/accessorparser.js +64 -0
- package/src/data-converter/converters/typedoc/classparser.js +49 -0
- package/src/data-converter/converters/typedoc/constantparser.js +45 -0
- package/src/data-converter/converters/typedoc/constructorparser.js +34 -0
- package/src/data-converter/converters/typedoc/errorparser.js +44 -0
- package/src/data-converter/converters/typedoc/eventparser.js +57 -0
- package/src/data-converter/converters/typedoc/functionparser.js +61 -0
- package/src/data-converter/converters/typedoc/interfaceparser.js +46 -0
- package/src/data-converter/converters/typedoc/methodparser.js +63 -0
- package/src/data-converter/converters/typedoc/moduleparser.js +31 -0
- package/src/data-converter/converters/typedoc/propertyparser.js +74 -0
- package/src/data-converter/converters/typedoc/typedoc.ts +297 -0
- package/src/data-converter/converters/typedoc/typedocconverter.js +742 -0
- package/src/data-converter/converters/typedoc/typeparser.js +71 -0
- package/src/data-converter/converters/typedoc2umberto.js +52 -0
- package/src/data-converter/data-collection.js +1 -1
- package/src/data-converter/data-provider.js +4 -2
- package/src/data-converter/doclet-collection.js +14 -2
- package/src/data-converter/middlewares/relation-fixer.js +1 -1
- package/src/helpers/capitalize.js +1 -1
- package/src/helpers/copy-file.js +1 -1
- package/src/helpers/create-filtering-data-attribs.js +1 -1
- package/src/helpers/doc-formats.js +3 -2
- package/src/helpers/escape-longname.js +1 -1
- package/src/helpers/extract-longname.js +1 -1
- package/src/helpers/get-api-infobox-tooltip.js +1 -1
- package/src/helpers/get-docsearch-config.js +1 -1
- package/src/helpers/get-file-patterns-to-process.js +1 -1
- package/src/helpers/get-short-module-path.js +1 -1
- package/src/helpers/github-url.js +1 -1
- package/src/helpers/glob-to-regexp.js +1 -1
- package/src/helpers/html-safe.js +1 -1
- package/src/helpers/is-non-empty-array.js +1 -1
- package/src/helpers/snippets.js +1 -1
- package/src/helpers/split-longname.js +101 -8
- package/src/hexo/filter/extend-config.js +1 -1
- package/src/hexo/filter/project-locals.js +1 -1
- package/src/hexo/get-repo-urls.js +1 -1
- package/src/hexo/helper/get-page-group.js +1 -1
- package/src/hexo/project-globals.js +1 -1
- package/src/hexo-manager.js +1 -1
- package/src/index.js +1 -1
- package/src/sdk-builder/get-sdk-sources.js +1 -1
- package/src/sdk-builder/sdk-builder.js +1 -1
- package/src/tasks/build-api-docs.js +4 -4
- package/src/tasks/build-documentation.js +3 -3
- package/src/tasks/build-sdk.js +1 -1
- package/src/tasks/build-snippets.js +1 -1
- package/src/tasks/cache-files.js +1 -1
- package/src/tasks/compile-sass.js +1 -1
- package/src/tasks/copy-assets.js +1 -1
- package/src/tasks/copy-files.js +1 -1
- package/src/tasks/copy-project-docs.js +1 -1
- package/src/tasks/copy-project-icons.js +1 -1
- package/src/tasks/create-redirect-page.js +1 -1
- package/src/tasks/create-sitemap.js +1 -1
- package/src/tasks/create-sym-links.js +1 -1
- package/src/tasks/execute-hooks.js +1 -1
- package/src/tasks/get-extra-files.js +1 -1
- package/src/tasks/get-hexo-config.js +1 -1
- package/src/tasks/get-main-config.js +1 -1
- package/src/tasks/get-project-config.js +3 -3
- package/src/tasks/macro-replacer.js +1 -1
- package/src/tasks/overwrite-api-guides.js +1 -1
- package/src/tasks/read-doc-sources.js +1 -1
- package/src/tasks/run-webpack.js +1 -1
- package/src/tasks/validate-html-w3c.js +1 -1
- package/src/tasks/validate-links.js +1 -1
- package/src/tasks/watcher.js +1 -1
- package/src/tasks/write-html-files.js +1 -1
- package/src/template/template-collection.js +1 -1
- package/themes/umberto/layout/_api-docs/_mixin/_api-see-source.pug +2 -1
- package/themes/umberto/layout/_api-docs/_mixin/_class-item.pug +0 -1
- package/themes/umberto/layout/_api-docs/_mixin/_dev-names.pug +9 -3
- package/themes/umberto/layout/_api-docs/_mixin/_fires-item.pug +2 -2
- package/themes/umberto/layout/_api-docs/_mixin/_hierarchy-item.pug +2 -2
- package/themes/umberto/layout/_api-docs/_mixin/_link-or-text.pug +40 -41
- package/themes/umberto/layout/_api-docs/_mixin/_method.pug +8 -2
- package/themes/umberto/layout/_api-docs/_mixin/_property.pug +1 -1
- package/themes/umberto/layout/_api-docs/_mixin/_related.pug +1 -1
- package/themes/umberto/layout/_api-docs/_mixin/_sidebox-list-item.pug +1 -1
- package/themes/umberto/layout/_api-docs/_mixin/_type.pug +175 -9
- package/themes/umberto/layout/_api-docs/_mixin/type-parameter.pug +18 -0
- package/themes/umberto/layout/_api-docs/_partial/filter.pug +16 -4
- package/themes/umberto/layout/_api-docs/_partial/type-parameters.pug +26 -0
- package/themes/umberto/layout/_api-docs/api-base.pug +2 -0
- package/themes/umberto/src/css/_api-content.scss +1 -1
- package/themes/umberto/src/css/_api-info-box.scss +1 -1
- package/themes/umberto/src/css/_api-props-filter.scss +1 -1
- package/themes/umberto/src/css/_api-see-source.scss +1 -1
- package/themes/umberto/src/css/_api-subheader.scss +1 -1
- package/themes/umberto/src/css/_api-tree.scss +1 -1
- package/themes/umberto/src/css/_badge.scss +1 -1
- package/themes/umberto/src/css/_collapsinglist.scss +1 -1
- package/themes/umberto/src/css/_content.scss +3 -2
- package/themes/umberto/src/css/_docsearch.scss +1 -1
- package/themes/umberto/src/css/_dropdown.scss +1 -1
- package/themes/umberto/src/css/_editor-icon.scss +1 -1
- package/themes/umberto/src/css/_feedback-widget.scss +1 -1
- package/themes/umberto/src/css/_footer.scss +1 -1
- package/themes/umberto/src/css/_formatted.scss +1 -1
- package/themes/umberto/src/css/_guide-content.scss +1 -1
- package/themes/umberto/src/css/_guide-sdk-tree.scss +1 -1
- package/themes/umberto/src/css/_loading-spinner.scss +1 -1
- package/themes/umberto/src/css/_main.scss +1 -1
- package/themes/umberto/src/css/_navigation.scss +1 -1
- package/themes/umberto/src/css/_notice.scss +1 -1
- package/themes/umberto/src/css/_print.scss +1 -1
- package/themes/umberto/src/css/_prism.scss +1 -1
- package/themes/umberto/src/css/_rwd-breadcrumbs.scss +1 -1
- package/themes/umberto/src/css/_rwd-menu.scss +1 -1
- package/themes/umberto/src/css/_secondary-navigation.scss +1 -1
- package/themes/umberto/src/css/_theme-dark.scss +1 -1
- package/themes/umberto/src/css/_toggler.scss +1 -1
- package/themes/umberto/src/css/_top.scss +1 -1
- package/themes/umberto/src/css/_tree.scss +7 -5
- package/themes/umberto/src/css/_warning-banner.scss +1 -1
- package/themes/umberto/src/css/components/_lightbox.scss +1 -1
- package/themes/umberto/src/css/helpers/_color.scss +1 -1
- package/themes/umberto/src/css/helpers/_font.scss +1 -1
- package/themes/umberto/src/css/helpers/_globals.scss +1 -1
- package/themes/umberto/src/css/helpers/_reset.scss +1 -1
- package/themes/umberto/src/css/helpers/_spacing.scss +1 -1
- package/themes/umberto/src/css/pages/_sdk.scss +1 -1
- package/themes/umberto/src/css/styles.scss +1 -1
- package/themes/umberto/src/js/_anchors.js +1 -1
- package/themes/umberto/src/js/_apisearch.js +1 -1
- package/themes/umberto/src/js/_apitree.js +1 -1
- package/themes/umberto/src/js/_collapsables.js +1 -1
- package/themes/umberto/src/js/_copymobileapinavigation.js +1 -1
- package/themes/umberto/src/js/_devnames.js +1 -1
- package/themes/umberto/src/js/_dropdowns.js +1 -1
- package/themes/umberto/src/js/_filtering.js +2 -1
- package/themes/umberto/src/js/_imageModal.js +1 -1
- package/themes/umberto/src/js/_pagenavigation.js +1 -1
- package/themes/umberto/src/js/_prism.js +1 -1
- package/themes/umberto/src/js/_rwdmenu.js +1 -1
- package/themes/umberto/src/js/_samplecode.js +1 -1
- package/themes/umberto/src/js/_sidenavigation.js +1 -1
- package/themes/umberto/src/js/_toc.js +1 -1
- package/themes/umberto/src/js/_tooltips.js +1 -1
- package/themes/umberto/src/js/_warningbanner.js +1 -1
- package/themes/umberto/src/js/app.js +1 -1
|
@@ -0,0 +1,742 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2017-2023, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const MarkdownIt = require( 'markdown-it' );
|
|
9
|
+
const markdown = new MarkdownIt( {
|
|
10
|
+
html: true
|
|
11
|
+
} );
|
|
12
|
+
|
|
13
|
+
const ISSUE_URL = 'https://github.com/cksource/umberto/issues/new?assignees=&labels=type:feature,squad:devops';
|
|
14
|
+
|
|
15
|
+
class TypedocConverter {
|
|
16
|
+
/**
|
|
17
|
+
* @param {Array.<AbstractParser>} parsers
|
|
18
|
+
*/
|
|
19
|
+
constructor( parsers ) {
|
|
20
|
+
/**
|
|
21
|
+
* @protected
|
|
22
|
+
* @member {Array.<Object>}
|
|
23
|
+
*/
|
|
24
|
+
this._doclets = [];
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* A map translating an identifier from Typedoc to a JsDoc doclet.
|
|
28
|
+
* It may contain an identifier from Typedoc that points to another identifier (a reference linked to another reference).
|
|
29
|
+
*
|
|
30
|
+
* @protected
|
|
31
|
+
* @member {Map.<Number, String|Number>}
|
|
32
|
+
*/
|
|
33
|
+
this._moduleMap = new Map();
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @protected
|
|
37
|
+
* @member {Array.<AbstractParser>}
|
|
38
|
+
*/
|
|
39
|
+
this._parsers = parsers.map( Class => new Class() );
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @protected
|
|
43
|
+
* @member {TypeConverter}
|
|
44
|
+
*/
|
|
45
|
+
this._typeConverter = new TypeConverter( this._moduleMap );
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @param {Array.<TypedocCommentItem>} content
|
|
50
|
+
* @returns {String}
|
|
51
|
+
*/
|
|
52
|
+
static convertComment( content ) {
|
|
53
|
+
const value = content.reduce( ( value, { kind, text, tag } ) => {
|
|
54
|
+
if ( kind === 'inline-tag' ) {
|
|
55
|
+
text = `{${ tag } ${ text }}`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return value + text;
|
|
59
|
+
}, '' );
|
|
60
|
+
|
|
61
|
+
return markdown.render( value ).trim();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @param {Object} projectReflection
|
|
66
|
+
* @param {Array.<TypedocReflection>} projectReflection.children
|
|
67
|
+
* @returns {Array.<Object>}
|
|
68
|
+
*/
|
|
69
|
+
convertToJsDoc( projectReflection ) {
|
|
70
|
+
// Convert the entire project to JsDoc doclets.
|
|
71
|
+
for ( const child of projectReflection.children ) {
|
|
72
|
+
this._convertChild( child );
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Then, when all doclets are specified, let's align types.
|
|
76
|
+
for ( const doclet of this._doclets ) {
|
|
77
|
+
// Post-processing is possible only if a doclet contains its original signature.
|
|
78
|
+
if ( !doclet._signature ) {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// TODO: Could we get a deep list of all inheritance/derived?
|
|
83
|
+
// Map parent references of classes and interfaces...
|
|
84
|
+
if ( 'augmentsNested' in doclet ) {
|
|
85
|
+
const extendedTypes = doclet._signature.extendedTypes || [];
|
|
86
|
+
|
|
87
|
+
doclet.augmentsNested = extendedTypes.flatMap( getHierarchyCallback( this._typeConverter ) );
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ...but also, the derived instances...
|
|
91
|
+
if ( 'descendants' in doclet ) {
|
|
92
|
+
const extendedBy = doclet._signature.extendedBy || [];
|
|
93
|
+
|
|
94
|
+
doclet.descendants = extendedBy.flatMap( getHierarchyCallback( this._typeConverter ) );
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ...and implemented interfaces.
|
|
98
|
+
if ( 'implementsNested' in doclet ) {
|
|
99
|
+
const implementedTypes = doclet._signature.implementedTypes || [];
|
|
100
|
+
|
|
101
|
+
doclet.implementsNested = implementedTypes.flatMap( getHierarchyCallback( this._typeConverter ) );
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Unify the `_signature` tuple, so all doclets use the same algorithm.
|
|
105
|
+
if ( !Array.isArray( doclet._signature ) ) {
|
|
106
|
+
doclet._signature = [ doclet._signature, doclet._signature ];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const [ getSignature, setSignature ] = doclet._signature;
|
|
110
|
+
const returnTypes = this._convertReturnTypes( doclet, getSignature );
|
|
111
|
+
|
|
112
|
+
if ( returnTypes ) {
|
|
113
|
+
if ( 'returns' in doclet ) {
|
|
114
|
+
doclet.returns = returnTypes;
|
|
115
|
+
} else if ( 'type' in doclet ) {
|
|
116
|
+
doclet.type = returnTypes[ 0 ].type;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if ( 'params' in doclet ) {
|
|
121
|
+
doclet.params = this._convertParameters( doclet, setSignature );
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if ( 'properties' in doclet ) {
|
|
125
|
+
doclet.properties = this._convertProperties( doclet, setSignature );
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if ( 'typeParameters' in doclet ) {
|
|
129
|
+
// For all doclets, it does not matter whether we process a get or a set signature.
|
|
130
|
+
// Hence, let's use the first one.
|
|
131
|
+
doclet.typeParameters = this._typeConverter.convertTypeParameters(
|
|
132
|
+
// Methods/functions || classes/interfaces/typedefs.
|
|
133
|
+
getSignature.typeParameter || getSignature.typeParameters
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// In the end, remove the original signature as it isn't needed anymore.
|
|
138
|
+
delete doclet._signature;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return this._doclets;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* @protected
|
|
146
|
+
* @param {TypedocReflection} reflection
|
|
147
|
+
* @param {String|null} [parentName=null]
|
|
148
|
+
*/
|
|
149
|
+
_convertChild( reflection, parentName = null ) {
|
|
150
|
+
const parser = this._parsers.find( parser => parser.canParse( reflection ) );
|
|
151
|
+
|
|
152
|
+
let doclets;
|
|
153
|
+
|
|
154
|
+
if ( parser ) {
|
|
155
|
+
doclets = parser.parse( reflection, parentName );
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if ( doclets ) {
|
|
159
|
+
doclets = Array.isArray( doclets ) ? doclets : [ doclets ];
|
|
160
|
+
|
|
161
|
+
for ( const item of doclets ) {
|
|
162
|
+
this._doclets.push( item );
|
|
163
|
+
this._moduleMap.set( reflection.id, item.longname );
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if ( reflection.kindString === 'Reference' ) {
|
|
168
|
+
if ( reflection.id !== reflection.target ) {
|
|
169
|
+
this._moduleMap.set( reflection.id, reflection.target );
|
|
170
|
+
} else {
|
|
171
|
+
console.warn( `Reference reflection "${ reflection.name }" points to itself, so it has been skipped.` );
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if ( reflection.children ) {
|
|
176
|
+
if ( doclets ) {
|
|
177
|
+
parentName = doclets[ 0 ].longname;
|
|
178
|
+
} else {
|
|
179
|
+
parentName = '';
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
reflection.children.forEach( subItem => {
|
|
183
|
+
this._convertChild( subItem, parentName );
|
|
184
|
+
} );
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* @protected
|
|
190
|
+
* @param {Object} doclet
|
|
191
|
+
* @param {TypedocCallSignature} signature
|
|
192
|
+
* @returns {Array|null}
|
|
193
|
+
*/
|
|
194
|
+
_convertParameters( doclet, signature ) {
|
|
195
|
+
if ( !signature.parameters ) {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return signature.parameters
|
|
200
|
+
.map( item => {
|
|
201
|
+
const response = this._convertTypeToJsDoc( item );
|
|
202
|
+
|
|
203
|
+
response.name = item.name;
|
|
204
|
+
|
|
205
|
+
if ( item.comment && item.comment.summary ) {
|
|
206
|
+
response.description = TypedocConverter.convertComment( item.comment.summary );
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if ( item.flags.isOptional ) {
|
|
210
|
+
response.optional = true;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if ( item.defaultValue ) {
|
|
214
|
+
response.defaultvalue = item.defaultValue;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return response;
|
|
218
|
+
} );
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* @protected
|
|
223
|
+
* @param {Object} doclet
|
|
224
|
+
* @param {TypedocCallSignature} signature
|
|
225
|
+
* @returns {Array|null}
|
|
226
|
+
*/
|
|
227
|
+
_convertProperties( doclet, signature ) {
|
|
228
|
+
const types = signature.type.type === 'union' ? signature.type.types : [ signature.type ];
|
|
229
|
+
const type = types.find( type => type.declaration && type.declaration.children );
|
|
230
|
+
|
|
231
|
+
if ( !type ) {
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return type.declaration.children.map( child => {
|
|
236
|
+
const response = this._convertTypeToJsDoc( child );
|
|
237
|
+
|
|
238
|
+
response.name = child.name;
|
|
239
|
+
|
|
240
|
+
if ( signature.comment && signature.comment.blockTags ) {
|
|
241
|
+
const atProperty = signature.comment.blockTags.find( blockTag => {
|
|
242
|
+
return blockTag.tag === '@property' && blockTag.name === child.name;
|
|
243
|
+
} );
|
|
244
|
+
|
|
245
|
+
if ( atProperty ) {
|
|
246
|
+
response.description = TypedocConverter.convertComment( atProperty.content );
|
|
247
|
+
}
|
|
248
|
+
} else if ( child.comment && child.comment.summary ) {
|
|
249
|
+
response.description = TypedocConverter.convertComment( child.comment.summary );
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if ( child.flags.isOptional ) {
|
|
253
|
+
response.optional = true;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if ( child.defaultValue ) {
|
|
257
|
+
response.defaultvalue = child.defaultValue;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return response;
|
|
261
|
+
} );
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* @protected
|
|
266
|
+
* @param {Object} doclet
|
|
267
|
+
* @param {TypedocReflectionType} signature
|
|
268
|
+
* @returns {Array|null}
|
|
269
|
+
*/
|
|
270
|
+
_convertReturnTypes( doclet, signature ) {
|
|
271
|
+
if ( !signature.type ) {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const response = this._convertTypeToJsDoc( signature );
|
|
276
|
+
|
|
277
|
+
const comment = signature.comment || {};
|
|
278
|
+
|
|
279
|
+
if ( !comment.blockTags ) {
|
|
280
|
+
comment.blockTags = [];
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const atReturns = comment.blockTags.find( blockTag => blockTag.tag === '@returns' );
|
|
284
|
+
|
|
285
|
+
if ( atReturns ) {
|
|
286
|
+
response.description = TypedocConverter.convertComment( atReturns.content );
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return [ response ];
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* @protected
|
|
294
|
+
* @param {TypedocReflectionType} parameterReflection
|
|
295
|
+
* @returns {Object}
|
|
296
|
+
*/
|
|
297
|
+
_convertTypeToJsDoc( parameterReflection ) {
|
|
298
|
+
let namesOrNames = this._typeConverter.convert( parameterReflection.type );
|
|
299
|
+
|
|
300
|
+
// Union.
|
|
301
|
+
if ( namesOrNames instanceof Set ) {
|
|
302
|
+
return {
|
|
303
|
+
type: {
|
|
304
|
+
names: [ ...namesOrNames ]
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
// Missing type. Use a name without linking it anywhere.
|
|
309
|
+
else if ( !namesOrNames ) {
|
|
310
|
+
namesOrNames = parameterReflection.type.name;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return {
|
|
314
|
+
type: {
|
|
315
|
+
// Convert items into an array to avoid having mixed structures in a view.
|
|
316
|
+
names: [ namesOrNames ]
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* A helper class for converting complex Typedoc reflections to less complicated JSDoc objects.
|
|
324
|
+
*
|
|
325
|
+
* @private
|
|
326
|
+
*/
|
|
327
|
+
class TypeConverter {
|
|
328
|
+
/**
|
|
329
|
+
* @param {Map} moduleMap
|
|
330
|
+
*/
|
|
331
|
+
constructor( moduleMap ) {
|
|
332
|
+
/**
|
|
333
|
+
* A map translating an identifier from Typedoc to a JsDoc doclet.
|
|
334
|
+
*
|
|
335
|
+
* @protected
|
|
336
|
+
* @member {Map.<Number, String>}
|
|
337
|
+
*/
|
|
338
|
+
this._moduleMap = moduleMap;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* @param {TypedocReflectionType} type
|
|
343
|
+
* @returns {Object|Array.<String>|String|null}
|
|
344
|
+
*/
|
|
345
|
+
convert( type ) {
|
|
346
|
+
// Sometimes the `type` property of the reflection does not contain the actual type of the reflection, but it could hold another
|
|
347
|
+
// kind of information, like the `array` or `optional` values. In that case, the actual type is stored in the `elementType`
|
|
348
|
+
// property. To handle this condition comprehensively, it is enough to always try to take the actual reflection from the
|
|
349
|
+
// `elementType` property (if it exists).
|
|
350
|
+
const typeReflection = type.elementType || type;
|
|
351
|
+
const convertedType = this._convertSingleType( typeReflection );
|
|
352
|
+
|
|
353
|
+
if ( type.type === 'array' ) {
|
|
354
|
+
if ( !convertedType ) {
|
|
355
|
+
return 'Array';
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if ( convertedType instanceof Set ) {
|
|
359
|
+
return [ ...convertedType ];
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return [ convertedType ];
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return convertedType;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Converts type parameters or class, interface, method or function to a format that can be rendered on API pages.
|
|
370
|
+
*
|
|
371
|
+
* The returned object contains a `value` property which must be an array.
|
|
372
|
+
* Thanks to that, it can be pass through the `type()` mixin.
|
|
373
|
+
*
|
|
374
|
+
* See: `themes/umberto/layout/_api-docs/_mixin/_type.pug.
|
|
375
|
+
*
|
|
376
|
+
* @param {Array.<TypedocReflectionTypeParameter>|null} parameters
|
|
377
|
+
* @returns {Array.<Object>|null}
|
|
378
|
+
*/
|
|
379
|
+
convertTypeParameters( parameters ) {
|
|
380
|
+
if ( !Array.isArray( parameters ) ) {
|
|
381
|
+
return null;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
return parameters.map( parameter => {
|
|
385
|
+
let description;
|
|
386
|
+
|
|
387
|
+
if ( parameter.comment && parameter.comment.summary ) {
|
|
388
|
+
description = TypedocConverter.convertComment( parameter.comment.summary );
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// A type without a definition. Just a name.
|
|
392
|
+
if ( !parameter.type ) {
|
|
393
|
+
if ( parameter.default ) {
|
|
394
|
+
const value = this.convert( parameter.default );
|
|
395
|
+
|
|
396
|
+
return {
|
|
397
|
+
name: parameter.name,
|
|
398
|
+
value: [ value ],
|
|
399
|
+
description
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return {
|
|
404
|
+
name: parameter.name,
|
|
405
|
+
description
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// A type parameter describing an argument of a function or a returned type or a reference.
|
|
410
|
+
if ( typeof parameter.type === 'string' ) {
|
|
411
|
+
return {
|
|
412
|
+
name: this.convert( parameter ),
|
|
413
|
+
description
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// A simple type....
|
|
418
|
+
if ( parameter.type.type === 'intrinsic' ) {
|
|
419
|
+
let value = parameter.type.name;
|
|
420
|
+
|
|
421
|
+
// ...with a default value.
|
|
422
|
+
if ( parameter.default ) {
|
|
423
|
+
value += ` = ${ this.convertIntrinsicType( parameter.default ) }`;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return {
|
|
427
|
+
name: parameter.name,
|
|
428
|
+
isExtending: true,
|
|
429
|
+
value: [ value ],
|
|
430
|
+
description
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
const type = this.convert( parameter.type );
|
|
435
|
+
|
|
436
|
+
// To avoid complex type parameters (they are available in typings provided by TypeScript),
|
|
437
|
+
// let's ignore unions.
|
|
438
|
+
if ( type instanceof Set ) {
|
|
439
|
+
return {
|
|
440
|
+
name: parameter.name,
|
|
441
|
+
description
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
return {
|
|
446
|
+
name: parameter.name,
|
|
447
|
+
isExtending: true,
|
|
448
|
+
value: [ type ],
|
|
449
|
+
description
|
|
450
|
+
};
|
|
451
|
+
} );
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* @param {TypedocTypeDetails} reference
|
|
456
|
+
* @returns {String}
|
|
457
|
+
*/
|
|
458
|
+
convertReference( reference ) {
|
|
459
|
+
let moduleName;
|
|
460
|
+
let referenceId = reference.id;
|
|
461
|
+
|
|
462
|
+
if ( !referenceId ) {
|
|
463
|
+
return reference.name;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// The reference identifier in a module map may point to another reference identifier.
|
|
467
|
+
// The loop is needed to get the target (final) module name.
|
|
468
|
+
do {
|
|
469
|
+
moduleName = this._moduleMap.get( referenceId );
|
|
470
|
+
referenceId = typeof moduleName === 'number' ? moduleName : null;
|
|
471
|
+
} while ( referenceId );
|
|
472
|
+
|
|
473
|
+
if ( moduleName ) {
|
|
474
|
+
return moduleName;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
return reference.name;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* @param {TypedocTypeDetails} parameter
|
|
482
|
+
* @returns {Object}
|
|
483
|
+
*/
|
|
484
|
+
convertIndexedAccess( parameter ) {
|
|
485
|
+
const convertIndex = reflection => {
|
|
486
|
+
if ( reflection.type === 'reference' ) {
|
|
487
|
+
return this.convertReference( reflection );
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
return this.convertIntrinsicType( reflection );
|
|
491
|
+
};
|
|
492
|
+
|
|
493
|
+
return {
|
|
494
|
+
type: 'generic',
|
|
495
|
+
name: this._convertSingleType( parameter.objectType ),
|
|
496
|
+
typeParameter: convertIndex( parameter.indexType )
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* @param {TypedocTypeDetails} typeReflection
|
|
502
|
+
* @returns {String|null|*}
|
|
503
|
+
*/
|
|
504
|
+
convertIntrinsicType( typeReflection ) {
|
|
505
|
+
if ( typeReflection.type === 'literal' ) {
|
|
506
|
+
if ( typeof typeReflection.value === 'string' ) {
|
|
507
|
+
return `'${ typeReflection.value }'`;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
return String( typeReflection.value );
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
return typeReflection.name;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* @param {Array.<TypedocReflectionType>} types
|
|
518
|
+
* @returns {Set}
|
|
519
|
+
*/
|
|
520
|
+
convertUnion( types ) {
|
|
521
|
+
const values = types.map( singleType => this.convert( singleType ) )
|
|
522
|
+
.filter( Boolean );
|
|
523
|
+
|
|
524
|
+
// Keep unique values only.
|
|
525
|
+
return new Set( values );
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Converts a single type reflection produced by Typedoc to a simpler JSDoc-structure that Umberto handles out-of-the-box.
|
|
530
|
+
*
|
|
531
|
+
* It returns:
|
|
532
|
+
* * the `null` value when converting the `void` type,
|
|
533
|
+
* * a `module:...` string if a type is a reference to other module,
|
|
534
|
+
* * a string if given type is a template,
|
|
535
|
+
* * an instance of the `Set` class if given type is an union,
|
|
536
|
+
* * an object when converting predicates or inline types.
|
|
537
|
+
*
|
|
538
|
+
* When detecting an unsupported type, it prints a warning message on a console suggesting
|
|
539
|
+
* to report an issue and providing support for the missing structure.
|
|
540
|
+
*
|
|
541
|
+
* @protected
|
|
542
|
+
* @param {TypedocTypeDetails} typeReflection
|
|
543
|
+
* @returns {Object|String|Set|null}
|
|
544
|
+
*/
|
|
545
|
+
_convertSingleType( typeReflection ) {
|
|
546
|
+
// See the `TypedocTypeDetails` type in the `typedoc.ts` file for checking the supported types.
|
|
547
|
+
//
|
|
548
|
+
// Results of this function is processed by Pug.
|
|
549
|
+
// See: `themes/umberto/layout/_api-docs/_mixin/_type.pug`.
|
|
550
|
+
//
|
|
551
|
+
// When introducing support for more TypeScript constructions,
|
|
552
|
+
// consider introducing a new structure that contains an opening symbol,
|
|
553
|
+
// a separator, and a closing symbol to avoid `instanceof` checks in the view.
|
|
554
|
+
//
|
|
555
|
+
// Examples:
|
|
556
|
+
//
|
|
557
|
+
// * Array: `Array<Type1 | Type2>`
|
|
558
|
+
// * Union: `Type1 | Type2 | Type3`
|
|
559
|
+
// * Intersection: `... & ...`
|
|
560
|
+
// * Tuple: `[ name1: Type1, name2: Type2 ]`
|
|
561
|
+
//
|
|
562
|
+
// TODO: When working on #1052, consider rewriting the function to always return an object
|
|
563
|
+
// containing type arguments. Then, `TypedocConverter#_convertTypeToJsDoc()` should not process
|
|
564
|
+
// them manually.
|
|
565
|
+
if ( typeReflection.type === 'reference' ) {
|
|
566
|
+
const reference = this.convertReference( typeReflection );
|
|
567
|
+
|
|
568
|
+
if ( !typeReflection.typeArguments ) {
|
|
569
|
+
return reference;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// An object representing a type containing type arguments.
|
|
573
|
+
return {
|
|
574
|
+
type: 'generic',
|
|
575
|
+
name: reference,
|
|
576
|
+
typeParameters: this.convertTypeParameters( typeReflection.typeArguments )
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
if ( typeReflection.type === 'indexedAccess' ) {
|
|
581
|
+
return this.convertIndexedAccess( typeReflection );
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
if ( typeReflection.type === 'literal' || typeReflection.type === 'intrinsic' ) {
|
|
585
|
+
return this.convertIntrinsicType( typeReflection );
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// Inline type: an object or a function.
|
|
589
|
+
if ( typeReflection.type === 'reflection' ) {
|
|
590
|
+
if ( Array.isArray( typeReflection.declaration.signatures ) ) {
|
|
591
|
+
const [ signature ] = typeReflection.declaration.signatures;
|
|
592
|
+
const isClass = signature.kindString === 'Constructor signature';
|
|
593
|
+
|
|
594
|
+
const params = ( signature.parameters || [] )
|
|
595
|
+
.map( singleType => this.convert( singleType.type ) )
|
|
596
|
+
.filter( Boolean );
|
|
597
|
+
|
|
598
|
+
const returns = signature.type ? this.convert( signature.type ) : null;
|
|
599
|
+
|
|
600
|
+
return {
|
|
601
|
+
type: 'function',
|
|
602
|
+
params,
|
|
603
|
+
returns,
|
|
604
|
+
isClass
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// The fields specified below describe an object.
|
|
609
|
+
//
|
|
610
|
+
// * `typeReflection.declaration.indexSignature` - a generic object,
|
|
611
|
+
// * `Array.isArray( typeReflection.declaration.children )` - an objet with the exact fields.
|
|
612
|
+
return 'object';
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// A structure represented by an array.
|
|
616
|
+
if ( typeReflection.type === 'tuple' ) {
|
|
617
|
+
// It is an array with mixed types.
|
|
618
|
+
// The position of these types matter.
|
|
619
|
+
return 'tuple';
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
if ( typeReflection.type === 'named-tuple-member' ) {
|
|
623
|
+
return this.convert( typeReflection.element );
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// A structure that mixes two and more different types.
|
|
627
|
+
if ( typeReflection.type === 'intersection' ) {
|
|
628
|
+
return 'object';
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
if ( typeReflection.type === 'query' ) {
|
|
632
|
+
return typeReflection.queryType.name;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// A modified object type.
|
|
636
|
+
// See: https://www.typescriptlang.org/docs/handbook/2/mapped-types.html.
|
|
637
|
+
if ( typeReflection.type === 'mapped' ) {
|
|
638
|
+
return [
|
|
639
|
+
'{',
|
|
640
|
+
'[',
|
|
641
|
+
typeReflection.parameter,
|
|
642
|
+
'in',
|
|
643
|
+
typeReflection.parameterType.name,
|
|
644
|
+
']?:', // TODO: Perhaps we should check `typeReflection.optionalModifier`.
|
|
645
|
+
typeReflection.templateType.name,
|
|
646
|
+
'}'
|
|
647
|
+
].join( ' ' );
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
// A conditional type.
|
|
651
|
+
// Perhaps it could be rendered as an union.
|
|
652
|
+
// See: https://www.typescriptlang.org/docs/handbook/2/conditional-types.html.
|
|
653
|
+
if ( typeReflection.type === 'conditional' ) {
|
|
654
|
+
return 'object';
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// See: https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html.
|
|
658
|
+
if ( typeReflection.type === 'template-literal' ) {
|
|
659
|
+
const output = typeReflection.tail.reduce( ( output, [ type, suffix ] ) => {
|
|
660
|
+
return output + '${ ' + this._convertSingleType( type ) + ' }' + suffix;
|
|
661
|
+
}, typeReflection.head );
|
|
662
|
+
|
|
663
|
+
return '`' + output + '`';
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
if ( typeReflection.type === 'typeOperator' ) {
|
|
667
|
+
return {
|
|
668
|
+
type: 'operator',
|
|
669
|
+
operator: typeReflection.operator,
|
|
670
|
+
values: this.convert( typeReflection.target )
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// See: https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-func.html#unions.
|
|
675
|
+
if ( typeReflection.type === 'union' ) {
|
|
676
|
+
return this.convertUnion( typeReflection.types );
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
// See: https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates.
|
|
680
|
+
/* istanbul ignore else */
|
|
681
|
+
if ( typeReflection.type === 'predicate' ) {
|
|
682
|
+
let typesOrType = this.convert( typeReflection.targetType );
|
|
683
|
+
|
|
684
|
+
if ( typesOrType instanceof Set ) {
|
|
685
|
+
typesOrType = [ ...typesOrType ];
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
if ( !Array.isArray( typesOrType ) ) {
|
|
689
|
+
// `typesOrType` can be an object representing a generic value.
|
|
690
|
+
// TODO: Missing CC here.
|
|
691
|
+
const value = typeof typesOrType === 'object' ? typesOrType.name : typesOrType;
|
|
692
|
+
|
|
693
|
+
if ( value.toLowerCase() === 'object' ) {
|
|
694
|
+
return 'boolean';
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
// Convert a single item into an array to avoid having mixed structures in a view.
|
|
698
|
+
typesOrType = [ typesOrType ];
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
return {
|
|
702
|
+
type: 'predicate',
|
|
703
|
+
name: typeReflection.name,
|
|
704
|
+
instances: typesOrType
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
// At this stage, the type cannot be converted. Perhaps, we missed something while developing
|
|
709
|
+
// the conversion. Let's ask users to create a new issue containing the non-supported structure.
|
|
710
|
+
//
|
|
711
|
+
// Note: The function is created only to hack Istanbul when generating the CC.
|
|
712
|
+
// There is no need for asserting it.
|
|
713
|
+
/* istanbul ignore next */
|
|
714
|
+
const displayMissingTypeAlert = () => {
|
|
715
|
+
console.warn( 'Found a type definition not supported by Umberto yet.' );
|
|
716
|
+
console.warn( 'Please, create a new issue: ' + ISSUE_URL );
|
|
717
|
+
console.log( '' );
|
|
718
|
+
console.warn( 'Ensure to include the following type definition in the issue to help us understand the structure.' );
|
|
719
|
+
console.log( '' );
|
|
720
|
+
console.log( '```json\n' + JSON.stringify( typeReflection, null, 2 ) + '\n```' );
|
|
721
|
+
};
|
|
722
|
+
|
|
723
|
+
/* istanbul ignore next */
|
|
724
|
+
displayMissingTypeAlert();
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
module.exports = TypedocConverter;
|
|
729
|
+
|
|
730
|
+
/**
|
|
731
|
+
* @param {TypeConverter} converter
|
|
732
|
+
* @returns {Function}
|
|
733
|
+
*/
|
|
734
|
+
function getHierarchyCallback( converter ) {
|
|
735
|
+
return reference => {
|
|
736
|
+
if ( reference.type === 'intersection' ) {
|
|
737
|
+
return reference.types.map( ref => converter.convertReference( ref ) );
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
return converter.convertReference( reference );
|
|
741
|
+
};
|
|
742
|
+
}
|