umberto 6.1.2 → 7.0.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.
Files changed (26) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/package.json +1 -1
  3. package/src/api-builder/utils/findtargetdoclet.js +2 -2
  4. package/src/data-converter/converters/typedoc/abstractparser.js +54 -50
  5. package/src/data-converter/converters/typedoc/accessorparser.js +7 -5
  6. package/src/data-converter/converters/typedoc/classparser.js +5 -3
  7. package/src/data-converter/converters/typedoc/computedpropertyparser.js +4 -3
  8. package/src/data-converter/converters/typedoc/constantparser.js +5 -3
  9. package/src/data-converter/converters/typedoc/constructorparser.js +4 -3
  10. package/src/data-converter/converters/typedoc/errorparser.js +4 -10
  11. package/src/data-converter/converters/typedoc/eventparser.js +4 -10
  12. package/src/data-converter/converters/typedoc/functionparser.js +5 -3
  13. package/src/data-converter/converters/typedoc/interfaceparser.js +5 -3
  14. package/src/data-converter/converters/typedoc/methodparser.js +6 -4
  15. package/src/data-converter/converters/typedoc/moduleparser.js +9 -3
  16. package/src/data-converter/converters/typedoc/propertyparser.js +7 -28
  17. package/src/data-converter/converters/typedoc/referenceparser.js +41 -0
  18. package/src/data-converter/converters/typedoc/reflectionkind.js +34 -0
  19. package/src/data-converter/converters/typedoc/typedoc.ts +215 -214
  20. package/src/data-converter/converters/typedoc/typedocconverter.js +130 -99
  21. package/src/data-converter/converters/typedoc/typeparser.js +10 -6
  22. package/src/data-converter/converters/typedoc2umberto.js +9 -3
  23. package/themes/umberto/layout/gloria/_api-docs/_mixin/_type.pug +9 -0
  24. package/themes/umberto/layout/umberto/_api-docs/_mixin/_type.pug +9 -0
  25. package/themes/umberto/src/gloria/js/_codeswitcherbuttons.js +2 -2
  26. package/themes/umberto/src/umberto/js/_codeswitcherbuttons.js +2 -2
@@ -6,11 +6,13 @@
6
6
  'use strict';
7
7
 
8
8
  const MarkdownIt = require( 'markdown-it' );
9
+ const ReflectionKind = require( './reflectionkind' );
9
10
  const markdown = new MarkdownIt( {
10
11
  html: true
11
12
  } );
12
13
 
13
14
  const ISSUE_URL = 'https://github.com/cksource/umberto/issues/new?assignees=&labels=type:feature,squad:platform';
15
+ const MODULE_INDEX_PATTERN = /^module:(?!icons\b)[\w-]+\/index/;
14
16
 
15
17
  class TypedocConverter {
16
18
  /**
@@ -28,7 +30,7 @@ class TypedocConverter {
28
30
  * It may contain an identifier from Typedoc that points to another identifier (a reference linked to another reference).
29
31
  *
30
32
  * @protected
31
- * @member {Map.<Number, String|Number>}
33
+ * @member {Map.<Number, String>}
32
34
  */
33
35
  this._moduleMap = new Map();
34
36
 
@@ -64,16 +66,14 @@ class TypedocConverter {
64
66
  /**
65
67
  * Prepares the name for the computed property.
66
68
  *
67
- * @param {TypedocReflection<'Index signature'>} item
69
+ * @param {BaseReflection} item
68
70
  * @returns {String}
69
71
  */
70
72
  static getComputedName( item ) {
71
- if ( item.kindString !== 'Index signature' ) {
73
+ if ( item.kind !== ReflectionKind.IndexSignature ) {
72
74
  return item.name;
73
75
  }
74
76
 
75
- // TypeDoc is able to handle only one (the first found one) index signature.
76
- // See: https://github.com/TypeStrong/typedoc/blob/af63d9e4e1/src/lib/converter/factories/index-signature.ts#L20
77
77
  const [ firstParam ] = item.parameters;
78
78
  const paramName = firstParam.name;
79
79
  const paramType = firstParam.type.name;
@@ -82,8 +82,7 @@ class TypedocConverter {
82
82
  }
83
83
 
84
84
  /**
85
- * @param {Object} projectReflection
86
- * @param {Array.<TypedocReflection>} projectReflection.children
85
+ * @param {ProjectReflection} projectReflection
87
86
  * @returns {Array.<Object>}
88
87
  */
89
88
  convertToJsDoc( projectReflection ) {
@@ -153,44 +152,47 @@ class TypedocConverter {
153
152
  if ( 'typeParameters' in doclet ) {
154
153
  // For all doclets, it does not matter whether we process a get or a set signature.
155
154
  // Hence, let's use the first one.
156
- doclet.typeParameters = this._typeConverter.convertTypeParameters(
157
- // Methods/functions || classes/interfaces/typedefs.
158
- getSignature.typeParameter || getSignature.typeParameters
159
- );
155
+ doclet.typeParameters = this._typeConverter.convertTypeParameters( getSignature.typeParameters );
156
+ }
157
+
158
+ // To resolve references from a package entry point (`@module package/index`).
159
+ // We want to link a reference to its target module.
160
+ //
161
+ // Currently, we do not render them in the API docs. However, there are plans to improve
162
+ // rendering of CKEditor 5 packages (`ckeditor5` and `ckeditor5-premium-features`).
163
+ // So, let's keep it for the future.
164
+ if ( '_isReference' in doclet ) {
165
+ let targetDoclet;
166
+ let referenceId = getSignature.target;
167
+
168
+ // The reference identifier may point to another reference identifier.
169
+ // The loop is needed to get the target (final) module name.
170
+ do {
171
+ targetDoclet = this._doclets.find( item => item.id === referenceId );
172
+ referenceId = targetDoclet.target;
173
+ } while ( referenceId );
174
+
175
+ doclet.targetDoclet = targetDoclet;
160
176
  }
161
177
 
162
- // In the end, remove the original signature as it isn't needed anymore.
178
+ // In the end, remove the helper properties.
179
+ delete doclet._isReference;
163
180
  delete doclet._signature;
164
181
  }
165
182
 
166
- return this._doclets;
183
+ // Index pages are not rendered yet. Hence, we drop all these doclets. Except for icons.
184
+ return this._doclets
185
+ .filter( doclet => {
186
+ return !doclet.longname.match( MODULE_INDEX_PATTERN ) && !doclet.memberof?.match( MODULE_INDEX_PATTERN );
187
+ } );
167
188
  }
168
189
 
169
190
  /**
170
191
  * @protected
171
- * @param {TypedocReflection} reflection
192
+ * @param {BaseReflection} reflection
172
193
  * @param {String|null} [parentName=null]
173
194
  */
174
195
  _convertChild( reflection, parentName = null ) {
175
- // For unknown reasons, TypeScript or TypeDoc treats all CKEditor 5 icons (except for the first one)
176
- // as a reference to the first exported member by a module.
177
- // We map them manually to display a proper list of the available doclets.
178
- // See: https://github.com/cksource/ckeditor5-internal/issues/3993.
179
- if ( parentName === 'module:icons/index' && reflection.kindString === 'Reference' ) {
180
- reflection = {
181
- ...reflection,
182
- kind: 32,
183
- kindString: 'Variable',
184
- flags: {
185
- isConst: true
186
- },
187
- type: {
188
- type: 'intrinsic',
189
- name: 'string'
190
- }
191
- };
192
- }
193
-
194
196
  const parser = this._parsers.find( parser => parser.canParse( reflection ) );
195
197
 
196
198
  let doclets;
@@ -204,40 +206,42 @@ class TypedocConverter {
204
206
 
205
207
  for ( const item of doclets ) {
206
208
  this._doclets.push( item );
209
+
207
210
  this._moduleMap.set( reflection.id, item.longname );
208
211
  }
209
212
  }
210
213
 
211
- if ( reflection.kindString === 'Reference' ) {
212
- if ( reflection.id !== reflection.target ) {
213
- this._moduleMap.set( reflection.id, reflection.target );
214
- } else {
215
- console.warn( `Reference reflection "${ reflection.name }" points to itself, so it has been skipped.` );
216
- }
214
+ if ( !doclets ) {
215
+ return;
217
216
  }
218
217
 
219
- // A computed property is stored in the `indexSignature` key, but we want to convert it in the same way as we do for a "normal"
220
- // property. Hence, let's just treat the `indexSignature` as it would be a doclet's child, so the dedicated parser for the
221
- // `indexSignature` can prepare a doclet for the computed property.
222
- if ( reflection.children || reflection.indexSignature ) {
223
- parentName = doclets ? doclets[ 0 ].longname : '';
218
+ const [ doclet ] = doclets;
219
+ parentName = doclet.longname;
224
220
 
225
- if ( reflection.children ) {
226
- reflection.children.forEach( subItem => {
227
- this._convertChild( subItem, parentName );
228
- } );
229
- }
221
+ // A computed property is stored in the `indexSignatures` key, but we want to convert it in the same way as we do for a "normal"
222
+ // property. Hence, let's just treat the `indexSignatures` as it would be a doclet's child, so the dedicated parser for the
223
+ // `indexSignatures` can prepare a doclet for the computed property.
224
+ ( reflection.children || [] ).forEach( subItem => {
225
+ this._convertChild( subItem, parentName );
226
+ } );
230
227
 
231
- if ( reflection.indexSignature ) {
232
- this._convertChild( reflection.indexSignature, parentName );
233
- }
234
- }
228
+ ( reflection.indexSignatures || [] ).forEach( ( subItem, index ) => {
229
+ this._convertChild( mapIndexSignatureObject( subItem, index ), parentName );
230
+ } );
231
+
232
+ // CKEditor 5 events are stored in the `ckeditor5Events` key.
233
+ ( reflection.ckeditor5Events || [] ).forEach( subItem => {
234
+ this._convertChild( {
235
+ ...subItem,
236
+ isCKEditor5Event: true
237
+ }, parentName );
238
+ } );
235
239
  }
236
240
 
237
241
  /**
238
242
  * @protected
239
243
  * @param {Object} doclet
240
- * @param {TypedocCallSignature} signature
244
+ * @param {CallSignatureReflection} signature
241
245
  * @returns {Array|null}
242
246
  */
243
247
  _convertParameters( doclet, signature ) {
@@ -282,43 +286,47 @@ class TypedocConverter {
282
286
 
283
287
  /**
284
288
  * @protected
285
- * @param {TypedocCallSignature} signature
289
+ * @param {CallSignatureReflection} signature
286
290
  * @returns {Array|null}
287
291
  */
288
292
  _convertProperties( signature ) {
289
- const types = signature.type.type === 'union' ? signature.type.types : [ signature.type ];
293
+ let types;
294
+
295
+ // Support for a literal object (`const foo: { /* object literal */ } = ...`).
296
+ if ( 'children' in signature || 'indexSignatures' in signature ) {
297
+ types = [
298
+ {
299
+ declaration: {
300
+ children: [
301
+ ...( signature.children || [] ),
302
+ ...( signature.indexSignatures || [] ).map( mapIndexSignatureObject )
303
+ ]
304
+ }
305
+ }
306
+ ];
307
+ } else {
308
+ types = signature.type.type === 'union' ? signature.type.types : [ signature.type ];
309
+ }
290
310
 
291
311
  const properties = types
292
312
  .filter( type => type.declaration )
293
313
  .flatMap( type => {
294
- const result = [];
295
-
296
- if ( type.declaration.children ) {
297
- result.push( ...type.declaration.children );
298
- }
299
-
300
- if ( type.declaration.indexSignature ) {
301
- result.push( type.declaration.indexSignature );
302
- }
303
-
304
- return result;
314
+ return [
315
+ ...( type.declaration.children || [] ),
316
+ ...( type.declaration.indexSignatures || [] ).map( mapIndexSignatureObject )
317
+ ];
305
318
  } );
306
319
 
307
320
  return properties.map( child => {
308
321
  // Nested properties cannot be duplicated so we can take the first signature when processing functions.
309
- const childSignature = child.kindString === 'Method' ? child.signatures[ 0 ] : child;
322
+ const childSignature = child.kind === ReflectionKind.Method ? child.signatures[ 0 ] : child;
310
323
  const response = this._convertTypeToJsDoc( childSignature );
311
324
 
312
325
  // For all properties, explicitly create the `id` key (as `extraId` key).
313
326
  // The `id` is then used to create the `longname` key. Unfortunately, nested properties are processed manually,
314
327
  // so part of the parser's job must be done here.
315
328
  response.extraId = `member-${ childSignature.name }`;
316
-
317
- if ( child.kindString === 'Index signature' ) {
318
- response.name = TypedocConverter.getComputedName( childSignature );
319
- } else {
320
- response.name = childSignature.name;
321
- }
329
+ response.name = TypedocConverter.getComputedName( childSignature );
322
330
 
323
331
  if ( signature.comment && signature.comment.blockTags ) {
324
332
  const atProperty = signature.comment.blockTags.find( blockTag => {
@@ -347,16 +355,30 @@ class TypedocConverter {
347
355
  /**
348
356
  * @protected
349
357
  * @param {Object} doclet
350
- * @param {TypedocReflectionType} signature
358
+ * @param {CallSignatureReflection} signature
351
359
  * @returns {Array|null}
352
360
  */
353
361
  _convertReturnTypes( doclet, signature ) {
354
362
  if ( !signature.type ) {
363
+ // Temporary solution for the `object` type. Let's create a fake structure that converter understands.
364
+ if ( signature.kind === ReflectionKind.TypeAlias ) {
365
+ return [
366
+ this._convertTypeToJsDoc( {
367
+ type: {
368
+ type: 'reflection',
369
+ declaration: {
370
+ // Passing non-empty `signatures` would convert it as a callable type.
371
+ signatures: null
372
+ }
373
+ }
374
+ } )
375
+ ];
376
+ }
377
+
355
378
  return null;
356
379
  }
357
380
 
358
381
  const response = this._convertTypeToJsDoc( signature );
359
-
360
382
  const comment = signature.comment || {};
361
383
 
362
384
  if ( !comment.blockTags ) {
@@ -374,7 +396,7 @@ class TypedocConverter {
374
396
 
375
397
  /**
376
398
  * @protected
377
- * @param {TypedocReflectionType} parameterReflection
399
+ * @param {ParameterReflection} parameterReflection
378
400
  * @returns {Object}
379
401
  */
380
402
  _convertTypeToJsDoc( parameterReflection ) {
@@ -422,7 +444,7 @@ class TypeConverter {
422
444
  }
423
445
 
424
446
  /**
425
- * @param {TypedocReflectionType} type
447
+ * @param {AvailableTypes} type
426
448
  * @returns {Object|Array.<String>|String|null}
427
449
  */
428
450
  convert( type ) {
@@ -441,7 +463,7 @@ class TypeConverter {
441
463
  }
442
464
 
443
465
  /**
444
- * @param {TypedocTypeDetails|null} type
466
+ * @param {AvailableTypes|null} type
445
467
  * @returns {string|Array}
446
468
  */
447
469
  convertArray( type ) {
@@ -464,7 +486,7 @@ class TypeConverter {
464
486
  *
465
487
  * See: `themes/umberto/<theme name>/layout/_api-docs/_mixin/_type.pug`.
466
488
  *
467
- * @param {Array.<TypedocReflectionTypeParameter>|null} parameters
489
+ * @param {Array.<TypeParameterReflection>|null} parameters
468
490
  * @returns {Array.<Object>|null}
469
491
  */
470
492
  convertTypeParameters( parameters ) {
@@ -547,23 +569,15 @@ class TypeConverter {
547
569
  }
548
570
 
549
571
  /**
550
- * @param {TypedocTypeDetails} reference
572
+ * @param {ReferenceType} reference
551
573
  * @returns {String}
552
574
  */
553
575
  convertReference( reference ) {
554
- let moduleName;
555
- let referenceId = reference.id;
556
-
557
- if ( !referenceId ) {
576
+ if ( !reference.target ) {
558
577
  return reference.name;
559
578
  }
560
579
 
561
- // The reference identifier in a module map may point to another reference identifier.
562
- // The loop is needed to get the target (final) module name.
563
- do {
564
- moduleName = this._moduleMap.get( referenceId );
565
- referenceId = typeof moduleName === 'number' ? moduleName : null;
566
- } while ( referenceId );
580
+ const moduleName = this._moduleMap.get( reference.target );
567
581
 
568
582
  if ( moduleName ) {
569
583
  return moduleName;
@@ -573,7 +587,7 @@ class TypeConverter {
573
587
  }
574
588
 
575
589
  /**
576
- * @param {TypedocTypeDetails} parameter
590
+ * @param {AvailableTypes} parameter
577
591
  * @returns {Object}
578
592
  */
579
593
  convertIndexedAccess( parameter ) {
@@ -593,7 +607,7 @@ class TypeConverter {
593
607
  }
594
608
 
595
609
  /**
596
- * @param {TypedocTypeDetails} typeReflection
610
+ * @param {LiteralOrIntrinsic} typeReflection
597
611
  * @returns {String|null|*}
598
612
  */
599
613
  convertIntrinsicType( typeReflection ) {
@@ -609,7 +623,7 @@ class TypeConverter {
609
623
  }
610
624
 
611
625
  /**
612
- * @param {Array.<TypedocReflectionType>} types
626
+ * @param {Array.<UnionType>} types
613
627
  * @returns {Set}
614
628
  */
615
629
  convertUnion( types ) {
@@ -634,11 +648,11 @@ class TypeConverter {
634
648
  * to report an issue and providing support for the missing structure.
635
649
  *
636
650
  * @protected
637
- * @param {TypedocTypeDetails} typeReflection
651
+ * @param {AvailableTypes} typeReflection
638
652
  * @returns {Object|String|Set|null}
639
653
  */
640
654
  _convertSingleType( typeReflection ) {
641
- // See the `TypedocTypeDetails` type in the `typedoc.ts` file for checking the supported types.
655
+ // See the `AvailableTypes` type in the `typedoc.ts` file for checking the supported types.
642
656
  //
643
657
  // Results of this function is processed by Pug.
644
658
  // See: `themes/umberto/<theme name>/layout/_api-docs/_mixin/_type.pug`.
@@ -691,7 +705,7 @@ class TypeConverter {
691
705
  if ( typeReflection.type === 'reflection' ) {
692
706
  if ( Array.isArray( typeReflection.declaration.signatures ) ) {
693
707
  const [ signature ] = typeReflection.declaration.signatures;
694
- const isClass = signature.kindString === 'Constructor signature';
708
+ const isClass = signature.kind === ReflectionKind.ConstructorSignature;
695
709
 
696
710
  const params = ( signature.parameters || [] )
697
711
  .map( singleType => ( {
@@ -724,7 +738,7 @@ class TypeConverter {
724
738
  return 'tuple';
725
739
  }
726
740
 
727
- if ( typeReflection.type === 'named-tuple-member' ) {
741
+ if ( typeReflection.type === 'namedTupleMember' ) {
728
742
  return this.convert( typeReflection.element );
729
743
  }
730
744
 
@@ -772,7 +786,7 @@ class TypeConverter {
772
786
  }
773
787
 
774
788
  // See: https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html.
775
- if ( typeReflection.type === 'template-literal' ) {
789
+ if ( typeReflection.type === 'templateLiteral' ) {
776
790
  const output = typeReflection.tail.reduce( ( output, [ type, suffix ] ) => {
777
791
  return output + '${ ' + this._convertSingleType( type ) + ' }' + suffix;
778
792
  }, typeReflection.head );
@@ -822,6 +836,16 @@ class TypeConverter {
822
836
  };
823
837
  }
824
838
 
839
+ // Since typedoc@0.28, CKEditor 5 types in unions are represented as `unknown`.
840
+ // We aim to display a pure string instead of the `unknown` value.
841
+ // See: http://127.0.0.1:8080/ckeditor5/45.0.0/api/module_engine_conversion_conversion-Conversion.html#function-attributeToAttribute
842
+ if ( typeReflection.type === 'unknown' ) {
843
+ return {
844
+ type: 'raw',
845
+ value: this.convertIntrinsicType( typeReflection )
846
+ };
847
+ }
848
+
825
849
  // At this stage, the type cannot be converted. Perhaps, we missed something while developing
826
850
  // the conversion. Let's ask users to create a new issue containing the non-supported structure.
827
851
  //
@@ -857,3 +881,10 @@ function getHierarchyCallback( converter ) {
857
881
  return converter.convertReference( reference );
858
882
  };
859
883
  }
884
+
885
+ function mapIndexSignatureObject( subItem, index ) {
886
+ return {
887
+ ...subItem,
888
+ name: `${ subItem.name }[${ index }]`
889
+ };
890
+ }
@@ -6,23 +6,25 @@
6
6
  'use strict';
7
7
 
8
8
  const AbstractParser = require( './abstractparser' );
9
+ const ReflectionKind = require( './reflectionkind' );
9
10
 
10
11
  module.exports = class TypeParser extends AbstractParser {
11
12
  /**
12
- * @param {TypedocReflectionMeta} item
13
+ * @param {BaseReflection} item
13
14
  * @returns {Boolean}
14
15
  */
15
16
  canParse( item ) {
16
- return item.kindString === 'Type alias';
17
+ return item.kind === ReflectionKind.TypeAlias;
17
18
  }
18
19
 
19
20
  /**
20
- * @param {TypedocReflection<'Type alias'>} item
21
+ * @param {LiteralObjectReflection} item
21
22
  * @param {String} parentName
22
23
  * @returns {Object}
23
24
  */
24
25
  parse( item, parentName ) {
25
26
  const result = {
27
+ id: item.id,
26
28
  name: item.name,
27
29
  memberof: parentName,
28
30
  longname: this.getLongName( item, parentName ),
@@ -40,9 +42,11 @@ module.exports = class TypeParser extends AbstractParser {
40
42
  typeParameters: null
41
43
  };
42
44
 
43
- // There are two distinct type definitions that are rendered in own way by Umberto: function type and object type.
44
- // For function type, its params and return type is displayed. For object, all its properties are shown.
45
- const isFunctionType = item.type.declaration && item.type.declaration.signatures;
45
+ // There are various distinct type definitions that are rendered in own way by Umberto:
46
+ // 1. a function type - show params and return type.
47
+ // 2. an object type - show all its properties.
48
+ // 3. a type alias - show the type name.
49
+ const isFunctionType = item.type?.declaration?.signatures;
46
50
 
47
51
  if ( isFunctionType ) {
48
52
  // Needed for post-processing once all project reflections are converted.
@@ -19,6 +19,7 @@ const MethodParser = require( './typedoc/methodparser' );
19
19
  const ConstructorParser = require( './typedoc/constructorparser' );
20
20
  const ErrorParser = require( './typedoc/errorparser' );
21
21
  const EventParser = require( './typedoc/eventparser' );
22
+ const ReferenceParser = require( './typedoc/referenceparser' );
22
23
 
23
24
  module.exports = data => {
24
25
  const projectReflection = JSON.parse( data );
@@ -33,7 +34,7 @@ module.exports = data => {
33
34
  // Top level. All things belong to a module.
34
35
  ModuleParser,
35
36
 
36
- // Module's children.
37
+ // Children of a module.
37
38
  ClassParser,
38
39
  InterfaceParser,
39
40
  FunctionParser,
@@ -41,13 +42,18 @@ module.exports = data => {
41
42
  TypeParser,
42
43
  ErrorParser,
43
44
 
44
- // Class's and interface's children.
45
+ // Children of an interface or a class.
45
46
  ConstructorParser,
46
47
  MethodParser,
47
48
  AccessorParser,
48
49
  PropertyParser,
49
50
  ComputedPropertyParser,
50
- EventParser
51
+
52
+ // Events of an interface or a class.
53
+ EventParser,
54
+
55
+ // Helper for processing a package entry point.
56
+ ReferenceParser
51
57
  ] );
52
58
 
53
59
  return typedoc.convertToJsDoc( projectReflection );
@@ -56,6 +56,15 @@ mixin renderComplexStructure( complexType )
56
56
  | !{ ' ' }
57
57
  +renderType( complexType.values )
58
58
 
59
+ //- Raw operator.
60
+ //-
61
+ //- Since `typedoc@0.28`, some of known types are translated as `unknown`. To display anything, we treat
62
+ //- them as a pure string. We wrap it in brackets to avoid confusions when it is a part of the union type.
63
+ if ( complexType.type === 'raw' && complexType.value )
64
+ | !{ '&lpar; ' }
65
+ | #{ complexType.value }
66
+ | !{ ' &rpar;' }
67
+
59
68
  //- An object with type arguments.
60
69
  if ( complexType.type === 'generic' && complexType.name && ( complexType.typeParameters || complexType.typeParameter ) )
61
70
  +renderGenericType( complexType )
@@ -56,6 +56,15 @@ mixin renderComplexStructure( complexType )
56
56
  | !{ ' ' }
57
57
  +renderType( complexType.values )
58
58
 
59
+ //- Raw operator.
60
+ //-
61
+ //- Since `typedoc@0.28`, some of known types are translated as `unknown`. To display anything, we treat
62
+ //- them as a pure string. We wrap it in brackets to avoid confusions when it is a part of the union type.
63
+ if ( complexType.type === 'raw' && complexType.value )
64
+ | !{ '&lpar; ' }
65
+ | #{ complexType.value }
66
+ | !{ ' &rpar;' }
67
+
59
68
  //- An object with type arguments.
60
69
  if ( complexType.type === 'generic' && complexType.name && ( complexType.typeParameters || complexType.typeParameter ) )
61
70
  +renderGenericType( complexType )
@@ -100,11 +100,11 @@ export function createCodeSwitcherButtons() {
100
100
 
101
101
  const selfHostedButton = createButton( 'Self-hosted (npm)', activeType === type.selfHosted );
102
102
 
103
- selfHostedButton.setAttribute( 'title', 'Self-hosted shows imports for installations using npm or ZIP setups.' );
103
+ selfHostedButton.setAttribute( 'title', 'Show import snippets for npm and ZIP setups.' );
104
104
 
105
105
  const cloudButton = createButton( 'Cloud (CDN)', activeType === type.cloud );
106
106
 
107
- cloudButton.setAttribute( 'title', 'Cloud shows imports for installations using CDN setups.' );
107
+ cloudButton.setAttribute( 'title', 'Show import snippets for a CDN setup.' );
108
108
 
109
109
  const switcherToolbar = switcher.querySelector( `.${ codeSwitcherToolbarClass }` );
110
110
 
@@ -100,11 +100,11 @@ export function createCodeSwitcherButtons() {
100
100
 
101
101
  const selfHostedButton = createButton( 'Self-hosted (npm)', activeType === type.selfHosted );
102
102
 
103
- selfHostedButton.setAttribute( 'title', 'Self-hosted shows imports for installations using npm or ZIP setups.' );
103
+ selfHostedButton.setAttribute( 'title', 'Show import snippets for npm and ZIP setups.' );
104
104
 
105
105
  const cloudButton = createButton( 'Cloud (CDN)', activeType === type.cloud );
106
106
 
107
- cloudButton.setAttribute( 'title', 'Cloud shows imports for installations using CDN setups.' );
107
+ cloudButton.setAttribute( 'title', 'Show import snippets for a CDN setup.' );
108
108
 
109
109
  const switcherToolbar = switcher.querySelector( `.${ codeSwitcherToolbarClass }` );
110
110