diff --git a/jest.config.js b/jest.config.js index 8bb2ddeeff71..66bbe01be9d8 100644 --- a/jest.config.js +++ b/jest.config.js @@ -27,5 +27,5 @@ module.exports = { transform: { '^.+\\.[jt]sx?$': 'babel-jest', }, - setupFiles: ['./jest/stylelint-rule-test.js'], + setupFiles: ['./jest/stylelint-rule-test.js', 'array-flat-polyfill'], }; diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/sidebars/sidebars-category-shorthand.js b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/sidebars/sidebars-category-shorthand.js new file mode 100644 index 000000000000..296be1742dc8 --- /dev/null +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/sidebars/sidebars-category-shorthand.js @@ -0,0 +1,34 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +module.exports = { + docs: [ + { + 'level 1': [ + 'a', + { + 'level 2': [ + { + 'level 3': [ + 'c', + { + 'level 4': [ + 'd', + { + 'deeper more more': ['e'], + }, + ], + }, + ], + }, + 'f', + ], + }, + ], + }, + ], +}; diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/sidebars/sidebars-invalid-item.json b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/sidebars/sidebars-invalid-item.json deleted file mode 100644 index 71088ca369d4..000000000000 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/sidebars/sidebars-invalid-item.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "docs": [ - { - "a": "b", - "c": "d" - } - ] -} diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/sidebars.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/sidebars.test.ts index 0e3b8a0015b4..49a788dfd90d 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/sidebars.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/sidebars.test.ts @@ -24,6 +24,17 @@ describe('loadSidebars', () => { expect(result).toMatchSnapshot(); }); + test('sidebars shortand and longform lead to exact same sidebar', async () => { + const sidebarPath1 = path.join(fixtureDir, 'sidebars-category.js'); + const sidebarPath2 = path.join( + fixtureDir, + 'sidebars-category-shorthand.js', + ); + const sidebar1 = loadSidebars([sidebarPath1]); + const sidebar2 = loadSidebars([sidebarPath2]); + expect(sidebar1).toEqual(sidebar2); + }); + test('sidebars with category but category.items is not an array', async () => { const sidebarPath = path.join( fixtureDir, @@ -93,15 +104,6 @@ describe('loadSidebars', () => { ); }); - test('sidebars with invalid sidebar item', async () => { - const sidebarPath = path.join(fixtureDir, 'sidebars-invalid-item.json'); - expect(() => - loadSidebars([sidebarPath]), - ).toThrowErrorMatchingInlineSnapshot( - `"Unknown sidebar item \\"{\\"a\\":\\"b\\",\\"c\\":\\"d\\"}\\"."`, - ); - }); - test('sidebars with unknown sidebar item type', async () => { const sidebarPath = path.join(fixtureDir, 'sidebars-unknown-type.json'); expect(() => diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars.ts b/packages/docusaurus-plugin-content-docs/src/sidebars.ts index 73c2a6b2a555..81018e50ebb3 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars.ts @@ -15,8 +15,28 @@ import { SidebarItemRaw, SidebarItemLink, SidebarItemDoc, + SidebarCategoryShorthandRaw, } from './types'; +function isCategoryShorthand( + item: SidebarItemRaw, +): item is SidebarCategoryShorthandRaw { + return typeof item !== 'string' && !item.type; +} + +/** + * Convert {category1: [item1,item2]} shorthand syntax to long-form syntax + */ +function normalizeCategoryShorthand( + sidebar: SidebarCategoryShorthandRaw, +): SidebarItemCategoryRaw[] { + return Object.entries(sidebar).map(([label, items]) => ({ + type: 'category', + label, + items, + })); +} + /** * Check that item contains only allowed keys. */ @@ -75,27 +95,29 @@ function assertIsLink(item: any): asserts item is SidebarItemLink { * Normalizes recursively item and all its children. Ensures that at the end * each item will be an object with the corresponding type. */ -function normalizeItem(item: SidebarItemRaw): SidebarItem { +function normalizeItem(item: SidebarItemRaw): SidebarItem[] { if (typeof item === 'string') { - return { - type: 'doc', - id: item, - }; + return [ + { + type: 'doc', + id: item, + }, + ]; } - if (!item.type) { - throw new Error(`Unknown sidebar item "${JSON.stringify(item)}".`); + if (isCategoryShorthand(item)) { + return normalizeCategoryShorthand(item).flatMap(normalizeItem); } switch (item.type) { case 'category': assertIsCategory(item); - return {...item, items: item.items.map(normalizeItem)}; + return [{...item, items: item.items.flatMap(normalizeItem)}]; case 'link': assertIsLink(item); - return item; + return [item]; case 'ref': case 'doc': assertIsDoc(item); - return item; + return [item]; default: throw new Error(`Unknown sidebar item type: ${item.type}`); } @@ -107,20 +129,11 @@ function normalizeItem(item: SidebarItemRaw): SidebarItem { function normalizeSidebar(sidebars: SidebarRaw): Sidebar { return Object.entries(sidebars).reduce( (acc: Sidebar, [sidebarId, sidebar]) => { - let normalizedSidebar: SidebarItemRaw[]; - - if (!Array.isArray(sidebar)) { - // Convert sidebar to a more generic structure. - normalizedSidebar = Object.entries(sidebar).map(([label, items]) => ({ - type: 'category', - label, - items, - })); - } else { - normalizedSidebar = sidebar; - } - - acc[sidebarId] = normalizedSidebar.map(normalizeItem); + const normalizedSidebar: SidebarItemRaw[] = Array.isArray(sidebar) + ? sidebar + : normalizeCategoryShorthand(sidebar); + + acc[sidebarId] = normalizedSidebar.flatMap(normalizeItem); return acc; }, diff --git a/packages/docusaurus-plugin-content-docs/src/types.ts b/packages/docusaurus-plugin-content-docs/src/types.ts index fe56ac27143e..4929797c598b 100644 --- a/packages/docusaurus-plugin-content-docs/src/types.ts +++ b/packages/docusaurus-plugin-content-docs/src/types.ts @@ -55,6 +55,7 @@ export type SidebarItem = export type SidebarItemRaw = | string + | SidebarCategoryShorthandRaw | SidebarItemDoc | SidebarItemLink | SidebarItemCategoryRaw @@ -63,13 +64,13 @@ export type SidebarItemRaw = [key: string]: any; }; +export interface SidebarCategoryShorthandRaw { + [sidebarCategory: string]: SidebarItemRaw[]; +} + // Sidebar given by user that is not normalized yet. e.g: sidebars.json export interface SidebarRaw { - [sidebarId: string]: - | { - [sidebarCategory: string]: SidebarItemRaw[]; - } - | SidebarItemRaw[]; + [sidebarId: string]: SidebarCategoryShorthandRaw | SidebarItemRaw[]; } export interface Sidebar { diff --git a/packages/docusaurus/package.json b/packages/docusaurus/package.json index 46fc80402ef1..1d576a5b888f 100644 --- a/packages/docusaurus/package.json +++ b/packages/docusaurus/package.json @@ -41,6 +41,7 @@ "@babel/runtime": "^7.7.4", "@docusaurus/utils": "^2.0.0-alpha.48", "@endiliey/static-site-generator-webpack-plugin": "^4.0.0", + "array-flat-polyfill": "^1.0.1", "babel-loader": "^8.0.6", "babel-plugin-dynamic-import-node": "^2.3.0", "cache-loader": "^4.1.0", diff --git a/packages/docusaurus/src/index.ts b/packages/docusaurus/src/index.ts index 543b405a3b93..4f79a8a343d9 100644 --- a/packages/docusaurus/src/index.ts +++ b/packages/docusaurus/src/index.ts @@ -5,6 +5,8 @@ * LICENSE file in the root directory of this source tree. */ +import 'array-flat-polyfill'; + export {build} from './commands/build'; export {start} from './commands/start'; export {swizzle} from './commands/swizzle'; diff --git a/tsconfig.json b/tsconfig.json index c2f71bbdfb65..bf338b3df6bf 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "target": "es2017", "module": "commonjs", - "lib": ["es2017"], + "lib": ["es2017","es2019.array"], "declaration": true, "declarationMap": true, diff --git a/website/docs/sidebar.md b/website/docs/sidebar.md index 1978b05e2c65..67b432425aba 100644 --- a/website/docs/sidebar.md +++ b/website/docs/sidebar.md @@ -50,7 +50,7 @@ module.exports = { }; ``` -If you don't want to rely on iteration order of JavaScript object keys for the category name, the following sidebar object is also equivalent of the above. +Keep in mind that EcmaScript does not guarantee `Object.keys({a,b}) === ['a','b']` (yet, this is generally true). If you don't want to rely on iteration order of JavaScript object keys for the category name, the following sidebar object is also equivalent of the above shorthand syntax. ```js // sidebars.js @@ -221,7 +221,23 @@ module.exports = { { type: 'category', label: 'Docs', - items: ['markdown-features', 'sidebar'], + items: ['markdown-features', 'sidebar', 'versioning'], + }, + ], + }, +}; +``` + +**Note**: it's possible to use the shorthand syntax to create nested categories: + +```js +// sidebars.js +module.exports = { + docs: { + Guides: [ + 'creating-pages', + { + Docs: ['markdown-features', 'sidebar', 'versioning'], }, ], }, diff --git a/website/sidebars.js b/website/sidebars.js index d7ed65a2e9ab..d24d7328a9de 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -19,9 +19,7 @@ module.exports = { 'styling-layout', 'static-assets', { - type: 'category', - label: 'Docs', - items: ['markdown-features', 'sidebar', 'versioning'], + Docs: ['markdown-features', 'sidebar', 'versioning'], }, 'blog', 'search', diff --git a/yarn.lock b/yarn.lock index a1891e3a2fcb..c0f9b13e0870 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3147,6 +3147,11 @@ array-find-index@^1.0.1: resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= +array-flat-polyfill@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/array-flat-polyfill/-/array-flat-polyfill-1.0.1.tgz#1e3a4255be619dfbffbfd1d635c1cf357cd034e7" + integrity sha512-hfJmKupmQN0lwi0xG6FQ5U8Rd97RnIERplymOv/qpq8AoNKPPAnxJadjFA23FNWm88wykh9HmpLJUUwUtNU/iw== + array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" @@ -7225,7 +7230,7 @@ github-from-package@0.0.0: resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4= -github-slugger@^1.0.0, github-slugger@^1.2.1: +github-slugger@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-1.2.1.tgz#47e904e70bf2dccd0014748142d31126cfd49508" integrity sha512-SsZUjg/P03KPzQBt7OxJPasGw6NRO5uOgiZ5RGXVud5iSIZ0eNZeNp5rTwCxtavrRUa/A77j8mePVc5lEvk0KQ== @@ -7561,11 +7566,6 @@ has-ansi@^2.0.0: dependencies: ansi-regex "^2.0.0" -has-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" - integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo= - has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -9111,14 +9111,6 @@ jest-pnp-resolver@^1.2.1: resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz#ecdae604c077a7fbc70defb6d517c3c1c898923a" integrity sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ== -jest-preset-stylelint@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/jest-preset-stylelint/-/jest-preset-stylelint-1.3.0.tgz#4e511ab95149a660cc73b2a9da32a5a1ef76c06f" - integrity sha512-W+KA2WVFLEqB5NItdCdFP5eP84VdAq4Y9QpJkU5J8dNWjNX9nS0OnD/97p2nUroprL4cAu7hry6z8ZMX/rWjYg== - dependencies: - lodash "^4.17.5" - postcss-less "^1.1.5" - jest-regex-util@^24.3.0, jest-regex-util@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.9.0.tgz#c13fb3380bde22bf6575432c493ea8fe37965636" @@ -9295,11 +9287,6 @@ jpegtran-bin@^4.0.0: bin-wrapper "^4.0.0" logalot "^2.0.0" -js-base64@^2.1.9: - version "2.5.2" - resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.2.tgz#313b6274dda718f714d00b3330bbae6e38e90209" - integrity sha512-Vg8czh0Q7sFBSUMWWArX/miJeBWYBPpdU/3M/DKSaekLMqrqVPaedp+5mZhie/r0lgrcaYBfwXatEew6gwgiQQ== - js-levenshtein@^1.1.3: version "1.1.6" resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d" @@ -10211,7 +10198,7 @@ mdast-util-to-hast@6.0.2: unist-util-visit "^1.1.0" xtend "^4.0.1" -mdast-util-to-string@^1.0.0, mdast-util-to-string@^1.0.7: +mdast-util-to-string@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-1.0.7.tgz#62d8e9c6b2113070d8b497c7dc35bf12796f06ee" integrity sha512-P+gdtssCoHOX+eJUrrC30Sixqao86ZPlVjR5NEAoy0U79Pfxb1Y0Gntei0+GrnQD4T04X9xA8tcugp90cSmNow== @@ -12122,13 +12109,6 @@ postcss-lab-function@^2.0.1: postcss "^7.0.2" postcss-values-parser "^2.0.0" -postcss-less@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/postcss-less/-/postcss-less-1.1.5.tgz#a6f0ce180cf3797eeee1d4adc0e9e6d6db665609" - integrity sha512-QQIiIqgEjNnquc0d4b6HDOSFZxbFQoy4MPpli2lSLpKhMyBkKwwca2HFqu4xzxlKID/F2fxSOowwtKpgczhF7A== - dependencies: - postcss "^5.2.16" - postcss-less@^3.1.4: version "3.1.4" resolved "https://registry.yarnpkg.com/postcss-less/-/postcss-less-3.1.4.tgz#369f58642b5928ef898ffbc1a6e93c958304c5ad" @@ -12596,16 +12576,6 @@ postcss-values-parser@^2.0.0, postcss-values-parser@^2.0.1: indexes-of "^1.0.1" uniq "^1.0.1" -postcss@^5.2.16: - version "5.2.18" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.18.tgz#badfa1497d46244f6390f58b319830d9107853c5" - integrity sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg== - dependencies: - chalk "^1.1.3" - js-base64 "^2.1.9" - source-map "^0.5.6" - supports-color "^3.2.3" - postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.23, postcss@^7.0.5, postcss@^7.0.6: version "7.0.25" resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.25.tgz#dd2a2a753d50b13bed7a2009b4a18ac14d9db21e" @@ -13579,15 +13549,6 @@ remark-parse@^6.0.0: vfile-location "^2.0.0" xtend "^4.0.1" -remark-slug@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/remark-slug/-/remark-slug-5.1.2.tgz#715ecdef8df1226786204b1887d31ab16aa24609" - integrity sha512-DWX+Kd9iKycqyD+/B+gEFO3jjnt7Yg1O05lygYSNTe5i5PIxxxPjp5qPBDxPIzp5wreF7+1ROCwRgjEcqmzr3A== - dependencies: - github-slugger "^1.0.0" - mdast-util-to-string "^1.0.0" - unist-util-visit "^1.0.0" - remark-squeeze-paragraphs@3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/remark-squeeze-paragraphs/-/remark-squeeze-paragraphs-3.0.4.tgz#9fe50c3bf3b572dd88754cd426ada007c0b8dc5f" @@ -14993,13 +14954,6 @@ supports-color@^2.0.0: resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= -supports-color@^3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" - integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY= - dependencies: - has-flag "^1.0.0" - supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -15682,6 +15636,11 @@ unist-builder@1.0.4, unist-builder@^1.0.1: dependencies: object-assign "^4.1.0" +unist-builder@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/unist-builder/-/unist-builder-2.0.3.tgz#77648711b5d86af0942f334397a33c5e91516436" + integrity sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw== + unist-util-find-all-after@^1.0.2: version "1.0.5" resolved "https://registry.yarnpkg.com/unist-util-find-all-after/-/unist-util-find-all-after-1.0.5.tgz#5751a8608834f41d117ad9c577770c5f2f1b2899" @@ -15716,6 +15675,13 @@ unist-util-remove-position@^1.0.0: dependencies: unist-util-visit "^1.1.0" +unist-util-remove-position@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz#5d19ca79fdba712301999b2b73553ca8f3b352cc" + integrity sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA== + dependencies: + unist-util-visit "^2.0.0" + unist-util-remove@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/unist-util-remove/-/unist-util-remove-1.0.3.tgz#58ec193dfa84b52d5a055ffbc58e5444eb8031a3" @@ -15766,6 +15732,15 @@ unist-util-visit@^1.0.0, unist-util-visit@^1.1.0, unist-util-visit@^1.4.0: dependencies: unist-util-visit-parents "^2.0.0" +unist-util-visit@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-2.0.2.tgz#3843782a517de3d2357b4c193b24af2d9366afb7" + integrity sha512-HoHNhGnKj6y+Sq+7ASo2zpVdfdRifhTgX2KTU3B/sO/TTlZchp7E3S4vjRzDJ7L60KmrCPsQkVK3lEF3cz36XQ== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^4.0.0" + unist-util-visit-parents "^3.0.0" + universal-user-agent@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-4.0.0.tgz#27da2ec87e32769619f68a14996465ea1cb9df16"