@docusaurus/plugin-content-docs 0.0.0-4240 → 0.0.0-4244

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 (62) hide show
  1. package/lib/.tsbuildinfo +1 -1
  2. package/lib/categoryGeneratedIndex.d.ts +12 -0
  3. package/lib/categoryGeneratedIndex.js +37 -0
  4. package/lib/cli.js +5 -23
  5. package/lib/docs.d.ts +22 -2
  6. package/lib/docs.js +71 -29
  7. package/lib/index.js +34 -62
  8. package/lib/options.js +2 -0
  9. package/lib/props.js +35 -6
  10. package/lib/routes.d.ts +27 -0
  11. package/lib/routes.js +105 -0
  12. package/lib/sidebars/generator.d.ts +2 -1
  13. package/lib/sidebars/generator.js +55 -13
  14. package/lib/sidebars/index.d.ts +5 -4
  15. package/lib/sidebars/index.js +18 -9
  16. package/lib/sidebars/normalization.d.ts +8 -3
  17. package/lib/sidebars/normalization.js +36 -17
  18. package/lib/sidebars/processor.d.ts +5 -3
  19. package/lib/sidebars/processor.js +33 -18
  20. package/lib/sidebars/types.d.ts +43 -2
  21. package/lib/sidebars/utils.d.ts +18 -6
  22. package/lib/sidebars/utils.js +149 -24
  23. package/lib/sidebars/validation.d.ts +2 -0
  24. package/lib/sidebars/validation.js +44 -8
  25. package/lib/slug.d.ts +4 -3
  26. package/lib/slug.js +26 -14
  27. package/lib/translations.js +51 -7
  28. package/lib/types.d.ts +18 -3
  29. package/package.json +8 -8
  30. package/src/__tests__/__fixtures__/versioned-site/versioned_sidebars/version-1.0.1-sidebars.json +2 -2
  31. package/src/__tests__/__snapshots__/cli.test.ts.snap +48 -106
  32. package/src/__tests__/__snapshots__/index.test.ts.snap +279 -28
  33. package/src/__tests__/__snapshots__/translations.test.ts.snap +45 -0
  34. package/src/__tests__/docs.test.ts +122 -7
  35. package/src/__tests__/index.test.ts +27 -1
  36. package/src/__tests__/options.test.ts +2 -0
  37. package/src/__tests__/slug.test.ts +127 -20
  38. package/src/__tests__/translations.test.ts +7 -0
  39. package/src/categoryGeneratedIndex.ts +57 -0
  40. package/src/cli.ts +5 -35
  41. package/src/docs.ts +103 -45
  42. package/src/index.ts +55 -93
  43. package/src/options.ts +4 -0
  44. package/src/plugin-content-docs.d.ts +71 -8
  45. package/src/props.ts +48 -9
  46. package/src/routes.ts +173 -0
  47. package/src/sidebars/__tests__/__snapshots__/index.test.ts.snap +21 -6
  48. package/src/sidebars/__tests__/generator.test.ts +105 -1
  49. package/src/sidebars/__tests__/index.test.ts +26 -24
  50. package/src/sidebars/__tests__/processor.test.ts +110 -19
  51. package/src/sidebars/__tests__/utils.test.ts +320 -20
  52. package/src/sidebars/__tests__/validation.test.ts +105 -0
  53. package/src/sidebars/generator.ts +82 -19
  54. package/src/sidebars/index.ts +23 -13
  55. package/src/sidebars/normalization.ts +47 -23
  56. package/src/sidebars/processor.ts +57 -27
  57. package/src/sidebars/types.ts +64 -3
  58. package/src/sidebars/utils.ts +217 -42
  59. package/src/sidebars/validation.ts +52 -8
  60. package/src/slug.ts +32 -17
  61. package/src/translations.ts +74 -8
  62. package/src/types.ts +22 -5
package/src/props.ts CHANGED
@@ -8,25 +8,28 @@
8
8
  import type {LoadedVersion, VersionTag, DocMetadata} from './types';
9
9
  import type {
10
10
  SidebarItemDoc,
11
- SidebarItemLink,
12
11
  SidebarItem,
12
+ SidebarItemCategory,
13
+ SidebarItemCategoryLink,
14
+ PropVersionDocs,
13
15
  } from './sidebars/types';
14
16
  import type {
15
17
  PropSidebars,
16
18
  PropVersionMetadata,
17
19
  PropSidebarItem,
20
+ PropSidebarItemCategory,
18
21
  PropTagDocList,
19
22
  PropTagDocListDoc,
23
+ PropSidebarItemLink,
20
24
  } from '@docusaurus/plugin-content-docs';
21
25
  import {compact, keyBy, mapValues} from 'lodash';
26
+ import {createDocsByIdIndex} from './docs';
22
27
 
23
28
  export function toSidebarsProp(loadedVersion: LoadedVersion): PropSidebars {
24
- const docsById = keyBy(loadedVersion.docs, (doc) => doc.id);
29
+ const docsById = createDocsByIdIndex(loadedVersion.docs);
25
30
 
26
- const convertDocLink = (item: SidebarItemDoc): SidebarItemLink => {
27
- const docId = item.id;
31
+ function getDocById(docId: string): DocMetadata {
28
32
  const docMetadata = docsById[docId];
29
-
30
33
  if (!docMetadata) {
31
34
  throw new Error(
32
35
  `Invalid sidebars file. The document with id "${docId}" was used in the sidebar, but no document with this id could be found.
@@ -34,26 +37,49 @@ Available document ids are:
34
37
  - ${Object.keys(docsById).sort().join('\n- ')}`,
35
38
  );
36
39
  }
40
+ return docMetadata;
41
+ }
37
42
 
43
+ const convertDocLink = (item: SidebarItemDoc): PropSidebarItemLink => {
44
+ const docMetadata = getDocById(item.id);
38
45
  const {
39
46
  title,
40
47
  permalink,
41
48
  frontMatter: {sidebar_label: sidebarLabel},
42
49
  } = docMetadata;
43
-
44
50
  return {
45
51
  type: 'link',
46
52
  label: sidebarLabel || item.label || title,
47
53
  href: permalink,
48
54
  className: item.className,
49
55
  customProps: item.customProps,
56
+ docId: docMetadata.unversionedId,
50
57
  };
51
58
  };
52
59
 
53
- const normalizeItem = (item: SidebarItem): PropSidebarItem => {
60
+ function getCategoryLinkHref(
61
+ link: SidebarItemCategoryLink | undefined,
62
+ ): string | undefined {
63
+ switch (link?.type) {
64
+ case 'doc':
65
+ return getDocById(link.id).permalink;
66
+ case 'generated-index':
67
+ return link.permalink;
68
+ default:
69
+ return undefined;
70
+ }
71
+ }
72
+
73
+ function convertCategory(item: SidebarItemCategory): PropSidebarItemCategory {
74
+ const {link, ...rest} = item;
75
+ const href = getCategoryLinkHref(link);
76
+ return {...rest, items: item.items.map(normalizeItem), ...(href && {href})};
77
+ }
78
+
79
+ function normalizeItem(item: SidebarItem): PropSidebarItem {
54
80
  switch (item.type) {
55
81
  case 'category':
56
- return {...item, items: item.items.map(normalizeItem)};
82
+ return convertCategory(item);
57
83
  case 'ref':
58
84
  case 'doc':
59
85
  return convertDocLink(item);
@@ -61,7 +87,7 @@ Available document ids are:
61
87
  default:
62
88
  return item;
63
89
  }
64
- };
90
+ }
65
91
 
66
92
  // Transform the sidebar so that all sidebar item will be in the
67
93
  // form of 'link' or 'category' only.
@@ -69,6 +95,18 @@ Available document ids are:
69
95
  return mapValues(loadedVersion.sidebars, (items) => items.map(normalizeItem));
70
96
  }
71
97
 
98
+ function toVersionDocsProp(loadedVersion: LoadedVersion): PropVersionDocs {
99
+ return mapValues(
100
+ keyBy(loadedVersion.docs, (doc) => doc.unversionedId),
101
+ (doc) => ({
102
+ id: doc.unversionedId,
103
+ title: doc.title,
104
+ description: doc.description,
105
+ sidebar: doc.sidebar,
106
+ }),
107
+ );
108
+ }
109
+
72
110
  export function toVersionMetadataProp(
73
111
  pluginId: string,
74
112
  loadedVersion: LoadedVersion,
@@ -82,6 +120,7 @@ export function toVersionMetadataProp(
82
120
  className: loadedVersion.versionClassName,
83
121
  isLast: loadedVersion.isLast,
84
122
  docsSidebars: toSidebarsProp(loadedVersion),
123
+ docs: toVersionDocsProp(loadedVersion),
85
124
  };
86
125
  }
87
126
 
package/src/routes.ts ADDED
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ import {PluginContentLoadedActions, RouteConfig} from '@docusaurus/types';
9
+ import {docuHash, createSlugger} from '@docusaurus/utils';
10
+ import {
11
+ CategoryGeneratedIndexMetadata,
12
+ DocMetadata,
13
+ LoadedVersion,
14
+ } from './types';
15
+ import type {PropCategoryGeneratedIndex} from '@docusaurus/plugin-content-docs';
16
+ import {toVersionMetadataProp} from './props';
17
+ import chalk from 'chalk';
18
+
19
+ export async function createCategoryGeneratedIndexRoutes({
20
+ version,
21
+ actions,
22
+ docCategoryGeneratedIndexComponent,
23
+ }: {
24
+ version: LoadedVersion;
25
+ actions: PluginContentLoadedActions;
26
+ docCategoryGeneratedIndexComponent: string;
27
+ }): Promise<RouteConfig[]> {
28
+ const slugs = createSlugger();
29
+
30
+ async function createCategoryGeneratedIndexRoute(
31
+ categoryGeneratedIndex: CategoryGeneratedIndexMetadata,
32
+ ): Promise<RouteConfig> {
33
+ const {sidebar, title, description, slug, permalink, previous, next} =
34
+ categoryGeneratedIndex;
35
+
36
+ const propFileName = slugs.slug(
37
+ `${version.versionPath}-${categoryGeneratedIndex.sidebar}-category-${categoryGeneratedIndex.title}`,
38
+ );
39
+
40
+ const prop: PropCategoryGeneratedIndex = {
41
+ title,
42
+ description,
43
+ slug,
44
+ permalink,
45
+ navigation: {
46
+ previous,
47
+ next,
48
+ },
49
+ };
50
+
51
+ const propData = await actions.createData(
52
+ `${docuHash(`category/${propFileName}`)}.json`,
53
+ JSON.stringify(prop, null, 2),
54
+ );
55
+
56
+ return {
57
+ path: permalink,
58
+ component: docCategoryGeneratedIndexComponent,
59
+ exact: true,
60
+ modules: {
61
+ categoryGeneratedIndex: propData,
62
+ },
63
+ // Same as doc, this sidebar route attribute permits to associate this subpage to the given sidebar
64
+ ...(sidebar && {sidebar}),
65
+ };
66
+ }
67
+
68
+ return Promise.all(
69
+ version.categoryGeneratedIndices.map(createCategoryGeneratedIndexRoute),
70
+ );
71
+ }
72
+
73
+ export async function createDocRoutes({
74
+ docs,
75
+ actions,
76
+ docItemComponent,
77
+ }: {
78
+ docs: DocMetadata[];
79
+ actions: PluginContentLoadedActions;
80
+ docItemComponent: string;
81
+ }): Promise<RouteConfig[]> {
82
+ return Promise.all(
83
+ docs.map(async (metadataItem) => {
84
+ await actions.createData(
85
+ // Note that this created data path must be in sync with
86
+ // metadataPath provided to mdx-loader.
87
+ `${docuHash(metadataItem.source)}.json`,
88
+ JSON.stringify(metadataItem, null, 2),
89
+ );
90
+
91
+ const docRoute: RouteConfig = {
92
+ path: metadataItem.permalink,
93
+ component: docItemComponent,
94
+ exact: true,
95
+ modules: {
96
+ content: metadataItem.source,
97
+ },
98
+ // Because the parent (DocPage) comp need to access it easily
99
+ // This permits to render the sidebar once without unmount/remount when navigating (and preserve sidebar state)
100
+ ...(metadataItem.sidebar && {
101
+ sidebar: metadataItem.sidebar,
102
+ }),
103
+ };
104
+
105
+ return docRoute;
106
+ }),
107
+ );
108
+ }
109
+
110
+ export async function createVersionRoutes({
111
+ loadedVersion,
112
+ actions,
113
+ docItemComponent,
114
+ docLayoutComponent,
115
+ docCategoryGeneratedIndexComponent,
116
+ pluginId,
117
+ aliasedSource,
118
+ }: {
119
+ loadedVersion: LoadedVersion;
120
+ actions: PluginContentLoadedActions;
121
+ docLayoutComponent: string;
122
+ docItemComponent: string;
123
+ docCategoryGeneratedIndexComponent: string;
124
+ pluginId: string;
125
+ aliasedSource: (str: string) => string;
126
+ }): Promise<void> {
127
+ async function doCreateVersionRoutes(version: LoadedVersion): Promise<void> {
128
+ const versionMetadata = toVersionMetadataProp(pluginId, version);
129
+ const versionMetadataPropPath = await actions.createData(
130
+ `${docuHash(`version-${version.versionName}-metadata-prop`)}.json`,
131
+ JSON.stringify(versionMetadata, null, 2),
132
+ );
133
+
134
+ async function createVersionSubRoutes() {
135
+ const [docRoutes, sidebarsRoutes] = await Promise.all([
136
+ createDocRoutes({docs: version.docs, actions, docItemComponent}),
137
+ createCategoryGeneratedIndexRoutes({
138
+ version,
139
+ actions,
140
+ docCategoryGeneratedIndexComponent,
141
+ }),
142
+ ]);
143
+
144
+ const routes = [...docRoutes, ...sidebarsRoutes];
145
+ return routes.sort((a, b) => a.path.localeCompare(b.path));
146
+ }
147
+
148
+ actions.addRoute({
149
+ path: version.versionPath,
150
+ // allow matching /docs/* as well
151
+ exact: false,
152
+ // main docs component (DocPage)
153
+ component: docLayoutComponent,
154
+ // sub-routes for each doc
155
+ routes: await createVersionSubRoutes(),
156
+ modules: {
157
+ versionMetadata: aliasedSource(versionMetadataPropPath),
158
+ },
159
+ priority: version.routePriority,
160
+ });
161
+ }
162
+
163
+ try {
164
+ return await doCreateVersionRoutes(loadedVersion);
165
+ } catch (e) {
166
+ console.error(
167
+ chalk.red(
168
+ `Can't create version routes for version "${loadedVersion.versionName}"`,
169
+ ),
170
+ );
171
+ throw e;
172
+ }
173
+ }
@@ -1,6 +1,6 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
- exports[`loadUnprocessedSidebars sidebars link 1`] = `
3
+ exports[`loadNormalizedSidebars sidebars link 1`] = `
4
4
  Object {
5
5
  "docs": Array [
6
6
  Object {
@@ -14,13 +14,14 @@ Object {
14
14
  },
15
15
  ],
16
16
  "label": "Test",
17
+ "link": undefined,
17
18
  "type": "category",
18
19
  },
19
20
  ],
20
21
  }
21
22
  `;
22
23
 
23
- exports[`loadUnprocessedSidebars sidebars with category.collapsed property 1`] = `
24
+ exports[`loadNormalizedSidebars sidebars with category.collapsed property 1`] = `
24
25
  Object {
25
26
  "docs": Array [
26
27
  Object {
@@ -37,10 +38,12 @@ Object {
37
38
  },
38
39
  ],
39
40
  "label": "Introduction",
41
+ "link": undefined,
40
42
  "type": "category",
41
43
  },
42
44
  ],
43
45
  "label": "Test",
46
+ "link": undefined,
44
47
  "type": "category",
45
48
  },
46
49
  Object {
@@ -57,17 +60,19 @@ Object {
57
60
  },
58
61
  ],
59
62
  "label": "Powering MDX",
63
+ "link": undefined,
60
64
  "type": "category",
61
65
  },
62
66
  ],
63
67
  "label": "Reference",
68
+ "link": undefined,
64
69
  "type": "category",
65
70
  },
66
71
  ],
67
72
  }
68
73
  `;
69
74
 
70
- exports[`loadUnprocessedSidebars sidebars with category.collapsed property at first level 1`] = `
75
+ exports[`loadNormalizedSidebars sidebars with category.collapsed property at first level 1`] = `
71
76
  Object {
72
77
  "docs": Array [
73
78
  Object {
@@ -80,6 +85,7 @@ Object {
80
85
  },
81
86
  ],
82
87
  "label": "Introduction",
88
+ "link": undefined,
83
89
  "type": "category",
84
90
  },
85
91
  Object {
@@ -92,13 +98,14 @@ Object {
92
98
  },
93
99
  ],
94
100
  "label": "Powering MDX",
101
+ "link": undefined,
95
102
  "type": "category",
96
103
  },
97
104
  ],
98
105
  }
99
106
  `;
100
107
 
101
- exports[`loadUnprocessedSidebars sidebars with deep level of category 1`] = `
108
+ exports[`loadNormalizedSidebars sidebars with deep level of category 1`] = `
102
109
  Object {
103
110
  "docs": Array [
104
111
  Object {
@@ -139,14 +146,17 @@ Object {
139
146
  },
140
147
  ],
141
148
  "label": "deeper more more",
149
+ "link": undefined,
142
150
  "type": "category",
143
151
  },
144
152
  ],
145
153
  "label": "level 4",
154
+ "link": undefined,
146
155
  "type": "category",
147
156
  },
148
157
  ],
149
158
  "label": "level 3",
159
+ "link": undefined,
150
160
  "type": "category",
151
161
  },
152
162
  Object {
@@ -155,17 +165,19 @@ Object {
155
165
  },
156
166
  ],
157
167
  "label": "level 2",
168
+ "link": undefined,
158
169
  "type": "category",
159
170
  },
160
171
  ],
161
172
  "label": "level 1",
173
+ "link": undefined,
162
174
  "type": "category",
163
175
  },
164
176
  ],
165
177
  }
166
178
  `;
167
179
 
168
- exports[`loadUnprocessedSidebars sidebars with first level not a category 1`] = `
180
+ exports[`loadNormalizedSidebars sidebars with first level not a category 1`] = `
169
181
  Object {
170
182
  "docs": Array [
171
183
  Object {
@@ -178,6 +190,7 @@ Object {
178
190
  },
179
191
  ],
180
192
  "label": "Getting Started",
193
+ "link": undefined,
181
194
  "type": "category",
182
195
  },
183
196
  Object {
@@ -188,7 +201,7 @@ Object {
188
201
  }
189
202
  `;
190
203
 
191
- exports[`loadUnprocessedSidebars sidebars with known sidebar item type 1`] = `
204
+ exports[`loadNormalizedSidebars sidebars with known sidebar item type 1`] = `
192
205
  Object {
193
206
  "docs": Array [
194
207
  Object {
@@ -214,6 +227,7 @@ Object {
214
227
  },
215
228
  ],
216
229
  "label": "Test",
230
+ "link": undefined,
217
231
  "type": "category",
218
232
  },
219
233
  Object {
@@ -226,6 +240,7 @@ Object {
226
240
  },
227
241
  ],
228
242
  "label": "Guides",
243
+ "link": undefined,
229
244
  "type": "category",
230
245
  },
231
246
  ],
@@ -129,9 +129,15 @@ describe('DefaultSidebarItemsGenerator', () => {
129
129
 
130
130
  test('generates complex nested sidebar', async () => {
131
131
  mockCategoryMetadataFiles({
132
- '02-Guides/_category_.json': {collapsed: false},
132
+ '02-Guides/_category_.json': {collapsed: false} as CategoryMetadataFile,
133
133
  '02-Guides/01-SubGuides/_category_.yml': {
134
134
  label: 'SubGuides (metadata file label)',
135
+ link: {
136
+ type: 'generated-index',
137
+ slug: 'subguides-generated-index-slug',
138
+ title: 'subguides-title',
139
+ description: 'subguides-description',
140
+ },
135
141
  },
136
142
  });
137
143
 
@@ -153,6 +159,13 @@ describe('DefaultSidebarItemsGenerator', () => {
153
159
  sidebarPosition: 1,
154
160
  frontMatter: {},
155
161
  },
162
+ {
163
+ id: 'tutorials-index',
164
+ source: 'index.md',
165
+ sourceDirName: '01-Tutorials',
166
+ sidebarPosition: 2,
167
+ frontMatter: {},
168
+ },
156
169
  {
157
170
  id: 'tutorial2',
158
171
  source: 'tutorial2.md',
@@ -167,6 +180,12 @@ describe('DefaultSidebarItemsGenerator', () => {
167
180
  sidebarPosition: 1,
168
181
  frontMatter: {},
169
182
  },
183
+ {
184
+ id: 'guides-index',
185
+ source: '02-Guides.md', // TODO should we allow to just use "Guides.md" to have an index?
186
+ sourceDirName: '02-Guides',
187
+ frontMatter: {},
188
+ },
170
189
  {
171
190
  id: 'guide2',
172
191
  source: 'guide2.md',
@@ -209,6 +228,10 @@ describe('DefaultSidebarItemsGenerator', () => {
209
228
  label: 'Tutorials',
210
229
  collapsed: true,
211
230
  collapsible: true,
231
+ link: {
232
+ type: 'doc',
233
+ id: 'tutorials-index',
234
+ },
212
235
  items: [
213
236
  {type: 'doc', id: 'tutorial1'},
214
237
  {type: 'doc', id: 'tutorial2'},
@@ -219,6 +242,10 @@ describe('DefaultSidebarItemsGenerator', () => {
219
242
  label: 'Guides',
220
243
  collapsed: false,
221
244
  collapsible: true,
245
+ link: {
246
+ type: 'doc',
247
+ id: 'guides-index',
248
+ },
222
249
  items: [
223
250
  {type: 'doc', id: 'guide1'},
224
251
  {
@@ -227,6 +254,12 @@ describe('DefaultSidebarItemsGenerator', () => {
227
254
  collapsed: true,
228
255
  collapsible: true,
229
256
  items: [{type: 'doc', id: 'nested-guide'}],
257
+ link: {
258
+ type: 'generated-index',
259
+ slug: 'subguides-generated-index-slug',
260
+ title: 'subguides-title',
261
+ description: 'subguides-description',
262
+ },
230
263
  },
231
264
  {type: 'doc', id: 'guide2'},
232
265
  ],
@@ -354,4 +387,75 @@ describe('DefaultSidebarItemsGenerator', () => {
354
387
  },
355
388
  ] as Sidebar);
356
389
  });
390
+
391
+ test('uses explicit link over the index/readme.{md,mdx} naming convention', async () => {
392
+ mockCategoryMetadataFiles({
393
+ 'Category/_category_.yml': {
394
+ label: 'Category label',
395
+ link: {
396
+ type: 'doc',
397
+ id: 'doc3', // Using a "local doc id" ("doc1" instead of "parent/doc1") on purpose
398
+ },
399
+ },
400
+ });
401
+
402
+ const sidebarSlice = await DefaultSidebarItemsGenerator({
403
+ numberPrefixParser: DefaultNumberPrefixParser,
404
+ item: {
405
+ type: 'autogenerated',
406
+ dirName: '.',
407
+ },
408
+ version: {
409
+ versionName: 'current',
410
+ contentPath: '',
411
+ },
412
+ docs: [
413
+ {
414
+ id: 'parent/doc1',
415
+ source: 'index.md',
416
+ sourceDirName: 'Category',
417
+ frontMatter: {},
418
+ },
419
+ {
420
+ id: 'parent/doc2',
421
+ source: 'index.md',
422
+ sourceDirName: 'Category',
423
+ frontMatter: {},
424
+ },
425
+ {
426
+ id: 'parent/doc3',
427
+ source: 'doc3.md',
428
+ sourceDirName: 'Category',
429
+ frontMatter: {},
430
+ },
431
+ ],
432
+ options: {
433
+ sidebarCollapsed: true,
434
+ sidebarCollapsible: true,
435
+ },
436
+ });
437
+
438
+ expect(sidebarSlice).toEqual([
439
+ {
440
+ type: 'category',
441
+ label: 'Category label',
442
+ collapsed: true,
443
+ collapsible: true,
444
+ link: {
445
+ id: 'parent/doc3',
446
+ type: 'doc',
447
+ },
448
+ items: [
449
+ {
450
+ id: 'parent/doc1',
451
+ type: 'doc',
452
+ },
453
+ {
454
+ id: 'parent/doc2',
455
+ type: 'doc',
456
+ },
457
+ ],
458
+ },
459
+ ] as Sidebar);
460
+ });
357
461
  });