umberto 10.5.1 → 10.6.1
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/CHANGELOG.md +21 -14
- package/package.json +2 -2
- package/src/data-converter/converters/typedoc/typedocconverter.js +180 -24
- package/themes/umberto/layout/gloria/_api-docs/_mixin/_type.pug +67 -1
- package/themes/umberto/layout/gloria/_modules/header/index.pug +4 -4
- package/themes/umberto/layout/gloria/_trackers/google-tag-manager-noscript.pug +4 -0
- package/themes/umberto/layout/gloria/_trackers/index.pug +1 -0
- package/themes/umberto/layout/gloria/api.pug +1 -0
- package/themes/umberto/layout/gloria/base.pug +1 -0
- package/themes/umberto/layout/gloria/index.pug +1 -0
- package/themes/umberto/layout/umberto/_partial/google-tag-manager.pug +13 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,41 +1,48 @@
|
|
|
1
1
|
Changelog
|
|
2
2
|
=========
|
|
3
3
|
|
|
4
|
-
## [10.
|
|
4
|
+
## [10.6.1](https://github.com/cksource/umberto/compare/v10.6.0...v10.6.1) (June 18, 2026)
|
|
5
5
|
|
|
6
|
-
###
|
|
6
|
+
### Other changes
|
|
7
7
|
|
|
8
|
-
*
|
|
8
|
+
* Updated homepage link.
|
|
9
|
+
* Restored the web-based Google Tag Manager snippets in both Gloria and legacy Umberto themes.
|
|
9
10
|
|
|
10
11
|
|
|
11
|
-
## [10.
|
|
12
|
+
## [10.6.0](https://github.com/cksource/umberto/compare/v10.5.1...v10.6.0) (June 8, 2026)
|
|
12
13
|
|
|
13
14
|
### Features
|
|
14
15
|
|
|
15
|
-
*
|
|
16
|
+
* Improved rendering of complex TypeScript types in API docs.
|
|
16
17
|
|
|
18
|
+
Intersection (`A & B`), tuple (`[ key: T, value: U ]`), and conditional (`T extends U ? X : Y`) types now render with their full structure preserved and each reference linkable, instead of collapsing to a generic `object` or `tuple` placeholder. Optional tuple elements display the trailing `?` from the source. The `infer X` keyword inside conditionals renders as such and no longer triggers "unsupported type" warnings during the docs build.
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
Properties tables on intersection type aliases now list the fields from the inline-literal half — including nested cases like `abc: A & { b: T }`, which now exposes `abc.b` as a sub-row, and cases where the inline literal is wrapped in `Partial<...>`, `Readonly<...>`, or `Required<...>`, where the wrapper's modifier is applied to each field. Per-field inline TSDoc comments (`/** ... */`) above each field render their descriptions in the Properties table, where they were previously dropped.
|
|
19
21
|
|
|
20
|
-
###
|
|
22
|
+
### Other changes
|
|
21
23
|
|
|
22
|
-
*
|
|
24
|
+
* Updated the GTM integration to use the new server-side setup in both Gloria and legacy Umberto themes.
|
|
23
25
|
|
|
24
26
|
|
|
25
|
-
## [10.
|
|
27
|
+
## [10.5.1](https://github.com/cksource/umberto/compare/v10.5.0...v10.5.1) (May 14, 2026)
|
|
26
28
|
|
|
27
|
-
###
|
|
29
|
+
### Bug fixes
|
|
28
30
|
|
|
29
|
-
*
|
|
31
|
+
* Changed the call for feedback title from `<h3>` to `<div>` to prevent it from appearing in the table of contents.
|
|
30
32
|
|
|
31
33
|
|
|
32
|
-
## [10.
|
|
34
|
+
## [10.5.0](https://github.com/cksource/umberto/compare/v10.4.1...v10.5.0) (April 14, 2026)
|
|
33
35
|
|
|
34
36
|
### Features
|
|
35
37
|
|
|
36
|
-
* Added
|
|
38
|
+
* Added the Call for feedback component for documentation pages.
|
|
39
|
+
|
|
37
40
|
|
|
38
|
-
|
|
41
|
+
## [10.4.1](https://github.com/cksource/umberto/compare/v10.4.0...v10.4.1) (April 13, 2026)
|
|
42
|
+
|
|
43
|
+
### Bug fixes
|
|
44
|
+
|
|
45
|
+
* Fixed URL in the dropdown for LTS item to have absolute URL to pass documentation validation.
|
|
39
46
|
|
|
40
47
|
---
|
|
41
48
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "umberto",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.6.1",
|
|
4
4
|
"description": "CKSource Documentation builder",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@babel/core": "^7.18.10",
|
|
19
|
-
"@babel/preset-env": "^7.
|
|
19
|
+
"@babel/preset-env": "^7.29.5",
|
|
20
20
|
"@minify-html/node": "^0.17.1",
|
|
21
21
|
"@vscode/markdown-it-katex": "^1.1.2",
|
|
22
22
|
"babel-loader": "^10.0.0",
|
|
@@ -265,7 +265,11 @@ export class TypedocConverter {
|
|
|
265
265
|
response.defaultvalue = item.defaultValue;
|
|
266
266
|
}
|
|
267
267
|
|
|
268
|
-
|
|
268
|
+
// Parameter tables expand inline object literals one level only and skip intersection
|
|
269
|
+
// fan-out: TypeDoc materializes mapped types like `{ [K in keyof this]?: unknown }` into
|
|
270
|
+
// a reflection containing every property of the host class, which would otherwise produce
|
|
271
|
+
// dozens of fake `param.*` sub-rows.
|
|
272
|
+
const nestedProperties = this._convertProperties( item, { maxDepth: 0, deepIntersections: false } );
|
|
269
273
|
|
|
270
274
|
if ( !nestedProperties ) {
|
|
271
275
|
return response;
|
|
@@ -285,9 +289,20 @@ export class TypedocConverter {
|
|
|
285
289
|
/**
|
|
286
290
|
* @protected
|
|
287
291
|
* @param {CallSignatureReflection} signature
|
|
292
|
+
* @param {Object} [options]
|
|
293
|
+
* @param {Number} [options.maxDepth=Infinity] How many additional levels of nested inline object
|
|
294
|
+
* literals to expand under each child. `0` means "do not recurse; emit only the immediate
|
|
295
|
+
* children of `signature.type`". Default `Infinity` is unbounded (terminates naturally at
|
|
296
|
+
* intrinsics) — used for type-alias property tables so nested intersections/inline literals
|
|
297
|
+
* are flattened to dotted names.
|
|
298
|
+
* @param {Boolean} [options.deepIntersections=true] Whether to fan out intersection members the
|
|
299
|
+
* way unions are fanned out. Type-alias property tables want this; function-parameter tables
|
|
300
|
+
* set it to `false` because TypeDoc materializes mapped types like `{ [K in keyof this]?: unknown }`
|
|
301
|
+
* into reflections containing every property of the host class — fanning into them would
|
|
302
|
+
* produce dozens of misleading sub-rows on parameters such as `values: object & ...`.
|
|
288
303
|
* @returns {Array|null}
|
|
289
304
|
*/
|
|
290
|
-
_convertProperties( signature ) {
|
|
305
|
+
_convertProperties( signature, { maxDepth = Infinity, deepIntersections = true } = {} ) {
|
|
291
306
|
let types;
|
|
292
307
|
|
|
293
308
|
// Support for a literal object (`const foo: { /* object literal */ } = ...`).
|
|
@@ -302,7 +317,10 @@ export class TypedocConverter {
|
|
|
302
317
|
}
|
|
303
318
|
}
|
|
304
319
|
];
|
|
320
|
+
} else if ( deepIntersections ) {
|
|
321
|
+
types = flattenCompositeTypes( signature.type );
|
|
305
322
|
} else {
|
|
323
|
+
// Fan out unions only; intersections stay opaque so each member is treated as a whole.
|
|
306
324
|
types = signature.type.type === 'union' ? signature.type.types : [ signature.type ];
|
|
307
325
|
}
|
|
308
326
|
|
|
@@ -315,7 +333,7 @@ export class TypedocConverter {
|
|
|
315
333
|
];
|
|
316
334
|
} );
|
|
317
335
|
|
|
318
|
-
return properties.
|
|
336
|
+
return properties.flatMap( child => {
|
|
319
337
|
// Nested properties cannot be duplicated so we can take the first signature when processing functions.
|
|
320
338
|
const childSignature = child.kind === ReflectionKind.Method ? child.signatures[ 0 ] : child;
|
|
321
339
|
const response = this._convertTypeToJsDoc( childSignature );
|
|
@@ -326,14 +344,17 @@ export class TypedocConverter {
|
|
|
326
344
|
response.extraId = `member-${ childSignature.name }`;
|
|
327
345
|
response.name = TypedocConverter.getComputedName( childSignature );
|
|
328
346
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
347
|
+
// Prefer a matching `@property` block tag on the parent type alias; otherwise fall back to
|
|
348
|
+
// the child reflection's own comment summary (inline `/** ... */` on each field).
|
|
349
|
+
//
|
|
350
|
+
// `blockTags` is an empty array (not absent) when TypeDoc parses a comment with only a summary,
|
|
351
|
+
// so a plain truthy check would always pass and the fallback would be unreachable.
|
|
352
|
+
const atProperty = signature.comment?.blockTags?.find( blockTag => {
|
|
353
|
+
return blockTag.tag === '@property' && blockTag.name === childSignature.name;
|
|
354
|
+
} );
|
|
333
355
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
}
|
|
356
|
+
if ( atProperty ) {
|
|
357
|
+
response.description = TypedocConverter.convertComment( atProperty.content );
|
|
337
358
|
} else if ( childSignature.comment && childSignature.comment.summary ) {
|
|
338
359
|
response.description = TypedocConverter.convertComment( childSignature.comment.summary );
|
|
339
360
|
}
|
|
@@ -342,11 +363,34 @@ export class TypedocConverter {
|
|
|
342
363
|
response.optional = true;
|
|
343
364
|
}
|
|
344
365
|
|
|
366
|
+
if ( childSignature.flags.isReadonly ) {
|
|
367
|
+
response.readonly = true;
|
|
368
|
+
}
|
|
369
|
+
|
|
345
370
|
if ( childSignature.defaultValue ) {
|
|
346
371
|
response.defaultvalue = childSignature.defaultValue;
|
|
347
372
|
}
|
|
348
373
|
|
|
349
|
-
|
|
374
|
+
// If the property's type is itself an inline object literal (directly, or as part of an
|
|
375
|
+
// intersection/union), expose its fields as nested rows — mirrors how `_convertParameters`
|
|
376
|
+
// flattens nested object literals in function parameters. The intersection-walking flag is
|
|
377
|
+
// propagated so callers that disable it (parameters) stay consistent through recursion.
|
|
378
|
+
const nestedProperties = maxDepth > 0 ?
|
|
379
|
+
this._convertProperties( childSignature, { maxDepth: maxDepth - 1, deepIntersections } ) :
|
|
380
|
+
null;
|
|
381
|
+
|
|
382
|
+
if ( !nestedProperties || !nestedProperties.length ) {
|
|
383
|
+
return response;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return [
|
|
387
|
+
response,
|
|
388
|
+
...nestedProperties.map( nestedProperty => {
|
|
389
|
+
nestedProperty.name = `${ childSignature.name }.${ nestedProperty.name }`;
|
|
390
|
+
|
|
391
|
+
return nestedProperty;
|
|
392
|
+
} )
|
|
393
|
+
];
|
|
350
394
|
} );
|
|
351
395
|
}
|
|
352
396
|
|
|
@@ -553,7 +597,12 @@ class TypeConverter {
|
|
|
553
597
|
};
|
|
554
598
|
}
|
|
555
599
|
|
|
556
|
-
|
|
600
|
+
// The `type += ` = default `` concatenation below assumes `type` is a string.
|
|
601
|
+
// When the constraint is a structured value (intersection, conditional, tuple, generic,
|
|
602
|
+
// function, predicate, operator, raw) or an array (`Array<X>` sugar), `+=` coerces it
|
|
603
|
+
// via `toString()` — producing `[object Object] = ...` or stripping the `Array<>` wrapper.
|
|
604
|
+
// Skip the default in those cases; the constraint is still rendered.
|
|
605
|
+
if ( parameter.default && typeof type === 'string' ) {
|
|
557
606
|
type += ` = ${ this.convertIntrinsicType( parameter.default ) }`;
|
|
558
607
|
}
|
|
559
608
|
|
|
@@ -729,20 +778,50 @@ class TypeConverter {
|
|
|
729
778
|
return 'object';
|
|
730
779
|
}
|
|
731
780
|
|
|
732
|
-
// A structure represented by an array.
|
|
781
|
+
// A structure represented by an array. The position and label of each element matter.
|
|
782
|
+
// E.g.: `[ number, string ]`, `[ key: number, value: string ]`, or `[ first: string, second?: number ]`.
|
|
783
|
+
// Optional elements appear in two forms in TypeDoc:
|
|
784
|
+
// * `[ key?: T ]` — `namedTupleMember` with `isOptional`.
|
|
785
|
+
// * `( T )?` — an `optional` wrapper around the element type.
|
|
733
786
|
if ( typeReflection.type === 'tuple' ) {
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
787
|
+
return {
|
|
788
|
+
type: 'tuple',
|
|
789
|
+
elements: ( typeReflection.elements || [] ).map( element => {
|
|
790
|
+
if ( element.type === 'namedTupleMember' ) {
|
|
791
|
+
const result = { name: element.name, value: this.convert( element.element ) };
|
|
792
|
+
|
|
793
|
+
if ( element.isOptional ) {
|
|
794
|
+
result.optional = true;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
return result;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
if ( element.type === 'optional' ) {
|
|
801
|
+
return { value: this.convert( element.elementType ), optional: true };
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
return { value: this.convert( element ) };
|
|
805
|
+
} )
|
|
806
|
+
};
|
|
737
807
|
}
|
|
738
808
|
|
|
809
|
+
// A namedTupleMember reached outside a tuple context (defensive — TS does not allow this at top level).
|
|
739
810
|
if ( typeReflection.type === 'namedTupleMember' ) {
|
|
740
811
|
return this.convert( typeReflection.element );
|
|
741
812
|
}
|
|
742
813
|
|
|
743
814
|
// A structure that mixes two and more different types.
|
|
815
|
+
// Each member is converted independently so its name/reference is preserved in the rendered signature.
|
|
816
|
+
// Inline object literal members additionally contribute their fields to the doclet's property table
|
|
817
|
+
// (see `flattenCompositeTypes()` consumed by `_convertProperties()`).
|
|
744
818
|
if ( typeReflection.type === 'intersection' ) {
|
|
745
|
-
return
|
|
819
|
+
return {
|
|
820
|
+
type: 'intersection',
|
|
821
|
+
values: typeReflection.types
|
|
822
|
+
.map( singleType => this.convert( singleType ) )
|
|
823
|
+
.filter( Boolean )
|
|
824
|
+
};
|
|
746
825
|
}
|
|
747
826
|
|
|
748
827
|
if ( typeReflection.type === 'query' ) {
|
|
@@ -776,11 +855,16 @@ class TypeConverter {
|
|
|
776
855
|
return type.join( ' ' );
|
|
777
856
|
}
|
|
778
857
|
|
|
779
|
-
// A conditional type
|
|
780
|
-
// Perhaps it could be rendered as an union.
|
|
858
|
+
// A conditional type: `CheckType extends ExtendsType ? TrueType : FalseType`.
|
|
781
859
|
// See: https://www.typescriptlang.org/docs/handbook/2/conditional-types.html.
|
|
782
860
|
if ( typeReflection.type === 'conditional' ) {
|
|
783
|
-
return
|
|
861
|
+
return {
|
|
862
|
+
type: 'conditional',
|
|
863
|
+
checkType: this.convert( typeReflection.checkType ),
|
|
864
|
+
extendsType: this.convert( typeReflection.extendsType ),
|
|
865
|
+
trueType: this.convert( typeReflection.trueType ),
|
|
866
|
+
falseType: this.convert( typeReflection.falseType )
|
|
867
|
+
};
|
|
784
868
|
}
|
|
785
869
|
|
|
786
870
|
// See: https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html.
|
|
@@ -815,15 +899,24 @@ class TypeConverter {
|
|
|
815
899
|
}
|
|
816
900
|
|
|
817
901
|
if ( !Array.isArray( typesOrType ) ) {
|
|
818
|
-
// `
|
|
819
|
-
//
|
|
902
|
+
// Predicates fundamentally resolve to `boolean` for narrowing — when the target type cannot
|
|
903
|
+
// be expressed compactly inline (an intersection, a conditional, a tuple, or an inline
|
|
904
|
+
// object literal), show just `boolean`. References, generics, etc. keep their normal rendering.
|
|
905
|
+
const compoundTypes = [ 'intersection', 'conditional', 'tuple' ];
|
|
906
|
+
|
|
907
|
+
if ( typeof typesOrType === 'object' && compoundTypes.includes( typesOrType.type ) ) {
|
|
908
|
+
return 'boolean';
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
// For all remaining objects, fall back to `.name` (e.g., `{ type: 'generic', name: 'Array' }`).
|
|
912
|
+
// Guard the case where `.name` is absent so an unanticipated shape does not throw.
|
|
820
913
|
const value = typeof typesOrType === 'object' ? typesOrType.name : typesOrType;
|
|
821
914
|
|
|
822
|
-
if ( value.toLowerCase() === 'object' ) {
|
|
915
|
+
if ( value && value.toLowerCase() === 'object' ) {
|
|
823
916
|
return 'boolean';
|
|
824
917
|
}
|
|
825
918
|
|
|
826
|
-
// Convert a single item into an array to
|
|
919
|
+
// Convert a single item into an array to keep a uniform shape for the renderer.
|
|
827
920
|
typesOrType = [ typesOrType ];
|
|
828
921
|
}
|
|
829
922
|
|
|
@@ -844,6 +937,12 @@ class TypeConverter {
|
|
|
844
937
|
};
|
|
845
938
|
}
|
|
846
939
|
|
|
940
|
+
// An `infer X` type-variable binding inside a conditional's `extendsType`.
|
|
941
|
+
// See: https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#inferring-within-conditional-types.
|
|
942
|
+
if ( typeReflection.type === 'inferred' ) {
|
|
943
|
+
return `infer ${ typeReflection.name }`;
|
|
944
|
+
}
|
|
945
|
+
|
|
847
946
|
// At this stage, the type cannot be converted. Perhaps, we missed something while developing
|
|
848
947
|
// the conversion. Let's ask users to create a new issue containing the non-supported structure.
|
|
849
948
|
//
|
|
@@ -884,3 +983,60 @@ function mapIndexSignatureObject( subItem, index ) {
|
|
|
884
983
|
name: `${ subItem.name }[${ index }]`
|
|
885
984
|
};
|
|
886
985
|
}
|
|
986
|
+
|
|
987
|
+
/**
|
|
988
|
+
* Modifier flags applied by the built-in utility type wrappers we descend into.
|
|
989
|
+
* Used by `flattenCompositeTypes()` so that an inline literal hidden inside e.g.
|
|
990
|
+
* `Partial<{...}>` still surfaces in the property table with the right per-field flags.
|
|
991
|
+
*/
|
|
992
|
+
const FLAG_PROPAGATING_WRAPPERS = new Map( [
|
|
993
|
+
[ 'Partial', { isOptional: true } ],
|
|
994
|
+
[ 'Required', { isOptional: false } ],
|
|
995
|
+
[ 'Readonly', { isReadonly: true } ]
|
|
996
|
+
] );
|
|
997
|
+
|
|
998
|
+
/**
|
|
999
|
+
* Flattens a typedoc type into a list of candidate types whose `declaration.children`
|
|
1000
|
+
* contribute to the parent's property table. Unions and intersections are recursively
|
|
1001
|
+
* flattened so members that are inline object literals are reached. References to the
|
|
1002
|
+
* `Partial`, `Required`, and `Readonly` utility wrappers are descended into so an
|
|
1003
|
+
* intersection like `Base & Partial<{ a: T }>` still exposes `a` (with the matching
|
|
1004
|
+
* per-field modifier). Other reference and non-declaration members are left in place
|
|
1005
|
+
* and skipped by the caller's `type.declaration` filter.
|
|
1006
|
+
*
|
|
1007
|
+
* @param {AvailableTypes} type
|
|
1008
|
+
* @returns {Array.<AvailableTypes>}
|
|
1009
|
+
*/
|
|
1010
|
+
function flattenCompositeTypes( type ) {
|
|
1011
|
+
if ( type.type === 'union' || type.type === 'intersection' ) {
|
|
1012
|
+
return type.types.flatMap( flattenCompositeTypes );
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
if (
|
|
1016
|
+
type.type === 'reference' &&
|
|
1017
|
+
FLAG_PROPAGATING_WRAPPERS.has( type.name ) &&
|
|
1018
|
+
type.typeArguments &&
|
|
1019
|
+
type.typeArguments.length === 1
|
|
1020
|
+
) {
|
|
1021
|
+
const flagOverrides = FLAG_PROPAGATING_WRAPPERS.get( type.name );
|
|
1022
|
+
|
|
1023
|
+
return flattenCompositeTypes( type.typeArguments[ 0 ] ).map( inner => {
|
|
1024
|
+
if ( !inner.declaration ) {
|
|
1025
|
+
return inner;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
return {
|
|
1029
|
+
...inner,
|
|
1030
|
+
declaration: {
|
|
1031
|
+
...inner.declaration,
|
|
1032
|
+
children: ( inner.declaration.children || [] ).map( child => ( {
|
|
1033
|
+
...child,
|
|
1034
|
+
flags: { ...child.flags, ...flagOverrides }
|
|
1035
|
+
} ) )
|
|
1036
|
+
}
|
|
1037
|
+
};
|
|
1038
|
+
} );
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
return [ type ];
|
|
1042
|
+
}
|
|
@@ -26,7 +26,7 @@ mixin renderStringValue( inlineObjectOrType )
|
|
|
26
26
|
//- TODO: Description.
|
|
27
27
|
//-
|
|
28
28
|
//- @param {Object} complexType
|
|
29
|
-
//- @param {'function'|'predicate'|'operator'|'generic'} complexType.type
|
|
29
|
+
//- @param {'function'|'predicate'|'operator'|'generic'|'intersection'|'tuple'|'conditional'} complexType.type
|
|
30
30
|
//- @param {Array.<*>} [complexType.params]
|
|
31
31
|
//- @param {String} [complexType.name]
|
|
32
32
|
//- @param {Array.<*>} [complexType.instances]
|
|
@@ -69,6 +69,26 @@ mixin renderComplexStructure( complexType )
|
|
|
69
69
|
if ( complexType.type === 'generic' && complexType.name && ( complexType.typeParameters || complexType.typeParameter ) )
|
|
70
70
|
+renderGenericType( complexType )
|
|
71
71
|
|
|
72
|
+
//- Intersection: `Foo & Bar & Baz`.
|
|
73
|
+
if ( complexType.type === 'intersection' && complexType.values )
|
|
74
|
+
+renderIntersection( complexType.values )
|
|
75
|
+
|
|
76
|
+
//- Tuple: `[ Type1, Type2 ]` or `[ name1: Type1, name2: Type2 ]`.
|
|
77
|
+
if ( complexType.type === 'tuple' && complexType.elements )
|
|
78
|
+
+renderTuple( complexType.elements )
|
|
79
|
+
|
|
80
|
+
//- Conditional: `CheckType extends ExtendsType ? TrueType : FalseType`.
|
|
81
|
+
if ( complexType.type === 'conditional' )
|
|
82
|
+
+renderType( complexType.checkType )
|
|
83
|
+
| !{ ' ' }
|
|
84
|
+
i !{ 'extends' }
|
|
85
|
+
| !{ ' ' }
|
|
86
|
+
+renderType( complexType.extendsType )
|
|
87
|
+
| !{ ' ? ' }
|
|
88
|
+
+renderType( complexType.trueType )
|
|
89
|
+
| !{ ' : ' }
|
|
90
|
+
+renderType( complexType.falseType )
|
|
91
|
+
|
|
72
92
|
|
|
73
93
|
//- Renders a structure for an union, an array or a single type specified as a string.
|
|
74
94
|
//-
|
|
@@ -110,6 +130,52 @@ mixin renderUnion( iterable )
|
|
|
110
130
|
if index < iterable.length - 1
|
|
111
131
|
| !{ ' | ' }
|
|
112
132
|
|
|
133
|
+
//- Renders an intersection structure, e.g., `Foo & Bar & Baz`.
|
|
134
|
+
//-
|
|
135
|
+
//- All types are linkable if they point to an existing JSDoc doclet.
|
|
136
|
+
//-
|
|
137
|
+
//- @param {Array.<String>} type
|
|
138
|
+
mixin renderIntersection( iterable )
|
|
139
|
+
each item, index in iterable
|
|
140
|
+
+renderType( item )
|
|
141
|
+
if index < iterable.length - 1
|
|
142
|
+
| !{ ' & ' }
|
|
143
|
+
|
|
144
|
+
//- Renders a tuple structure, e.g., `[ string, number ]`, `[ key: string, value: number ]`,
|
|
145
|
+
//- or `[ first: string, second?: number ]` (optional last element).
|
|
146
|
+
//-
|
|
147
|
+
//- For anonymous optional elements whose value renders with an infix operator
|
|
148
|
+
//- (`|`, `&`, ` ? `, ` => `), the value is wrapped in parentheses so the trailing `?`
|
|
149
|
+
//- unambiguously applies to the whole expression — matching TypeScript's `( T | U )?` source syntax.
|
|
150
|
+
//- Single tokens (`number?`, `Array<T>?`) and named members (`key?: T | U`) stay unwrapped.
|
|
151
|
+
//-
|
|
152
|
+
//- @param {Array.<{ name?: String, value: *, optional?: Boolean }>} elements
|
|
153
|
+
mixin renderTuple( elements )
|
|
154
|
+
| !{ '[ ' }
|
|
155
|
+
each element, index in elements
|
|
156
|
+
if ( element.name )
|
|
157
|
+
if ( element.optional )
|
|
158
|
+
| #{ element.name }?:
|
|
159
|
+
else
|
|
160
|
+
| #{ element.name }:
|
|
161
|
+
+renderType( element.value )
|
|
162
|
+
else
|
|
163
|
+
//- The trailing `?` binds tighter than `|`/`&`, so wrap compound values
|
|
164
|
+
//- to keep the source semantics. Plain strings and arrays (`Array<T>`,
|
|
165
|
+
//- which self-brackets) are unambiguous and need no parens.
|
|
166
|
+
- const v = element.value
|
|
167
|
+
- const wrap = element.optional && ( v instanceof Set || ( v && typeof v === 'object' && !Array.isArray( v ) && [ 'intersection', 'conditional', 'function' ].includes( v.type ) ) )
|
|
168
|
+
if ( wrap )
|
|
169
|
+
| !{ '( ' }
|
|
170
|
+
+renderType( element.value )
|
|
171
|
+
if ( wrap )
|
|
172
|
+
| !{ ' )' }
|
|
173
|
+
if ( element.optional )
|
|
174
|
+
| ?
|
|
175
|
+
if index < elements.length - 1
|
|
176
|
+
| !{ ', ' }
|
|
177
|
+
| !{ ' ]' }
|
|
178
|
+
|
|
113
179
|
//- Draws an inline callback structure.
|
|
114
180
|
//-
|
|
115
181
|
//- E.g.: `( ArgumentFoo | ArgumentBar, AnotherArgument ) => ReturnType`
|
|
@@ -12,8 +12,8 @@ mixin header({ withChooseProject = true, className = '' } = {})
|
|
|
12
12
|
.c-header__mobile.l-hide-desktop
|
|
13
13
|
.c-header__mobile-brand
|
|
14
14
|
a.b-link.u-display-inline-flex(
|
|
15
|
-
title='Navigate to the CKEditor
|
|
16
|
-
href=
|
|
15
|
+
title='Navigate to the CKEditor homepage',
|
|
16
|
+
href='https://ckeditor.com'
|
|
17
17
|
)
|
|
18
18
|
+inline-svg({ file: 'ckeditor-logo', ariaHidden: true, className: 'c-header__brand-logo' })
|
|
19
19
|
|
|
@@ -39,8 +39,8 @@ mixin header({ withChooseProject = true, className = '' } = {})
|
|
|
39
39
|
.c-header__brand-row
|
|
40
40
|
.c-header__brand-row-selector.u-flex-horizontal.u-align-items-center
|
|
41
41
|
a.b-link.u-display-inline-flex(
|
|
42
|
-
title='Navigate to the CKEditor
|
|
43
|
-
href=
|
|
42
|
+
title='Navigate to the CKEditor homepage',
|
|
43
|
+
href='https://ckeditor.com'
|
|
44
44
|
)
|
|
45
45
|
+inline-svg({ file: 'ckeditor-logo', ariaHidden: true, className: 'c-header__brand-logo' })
|
|
46
46
|
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
if googletagmanager
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
})( window, document, 'script', 'dataLayer', '!{ googletagmanager.gtm }' );
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// End Google Tag Manager
|
|
2
|
+
script.
|
|
3
|
+
if (!{ JSON.stringify(googletagmanager.domains) }.indexOf(location.hostname) !== -1) {
|
|
4
|
+
(function (w, d, s, l, i) {
|
|
5
|
+
w[l] = w[l] || [];
|
|
6
|
+
w[l].push({'gtm.start': new Date().getTime(), event: 'gtm.js'});
|
|
7
|
+
var f = d.getElementsByTagName(s)[0],
|
|
8
|
+
j = d.createElement(s),
|
|
9
|
+
dl = l != 'dataLayer' ? '&l=' + l : '';
|
|
10
|
+
j.async = true;
|
|
11
|
+
j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
|
|
12
|
+
f.parentNode.insertBefore(j, f);
|
|
13
|
+
})( window, document, 'script', 'dataLayer', '!{ googletagmanager.gtm }' );
|
|
14
|
+
}
|