From 8b92ebe025076ecf51c2b49c10d2e064bfdf5d86 Mon Sep 17 00:00:00 2001 From: rogermparent Date: Mon, 27 Dec 2021 19:38:59 -0500 Subject: [PATCH 1/7] Move sidebar logic to theme --- .../build-sidebar-helpers.js | 238 ++++++++++++++++++ .../build-sidebar-helpers.test.js | 49 ++-- src/utils/shared/sidebar.js | 237 +---------------- 3 files changed, 256 insertions(+), 268 deletions(-) create mode 100644 plugins/gatsby-theme-iterative-docs/build-sidebar-helpers.js rename src/utils/shared/sidebar.test.js => plugins/gatsby-theme-iterative-docs/build-sidebar-helpers.test.js (83%) diff --git a/plugins/gatsby-theme-iterative-docs/build-sidebar-helpers.js b/plugins/gatsby-theme-iterative-docs/build-sidebar-helpers.js new file mode 100644 index 0000000000..f138b3d5e4 --- /dev/null +++ b/plugins/gatsby-theme-iterative-docs/build-sidebar-helpers.js @@ -0,0 +1,238 @@ +/* eslint-env node */ +/* + These helpers normalize sidebar structure and create all the resources needed. + This prevents future recalculations. + + Target structure example: + + { + label: "Add Files or Directories", + path: "/doc/start/add-files", + source: "/doc/start/add-files.md", + prev: "/doc/start/configure", + next: "/doc/start/share-data", + icon: "house", + style: "customClass", + tutorials: { + katacoda: "https://www.katacoda.com/dvc/courses/get-started" + } + children: [] + } +*/ + +const { titleCase } = require('title-case') + +const PATH_ROOT = '/doc' +const FILE_ROOT = '/docs/' +const FILE_EXTENSION = '.md' + +function dvcTitleCase(slug) { + return titleCase(slug.replace(/dvc/g, 'DVC').replace(/-/g, ' ')) +} + +function validateRawItem({ slug, source, children, type, url }) { + const isSourceDisabled = source === false + + switch (type) { + case 'external': + if (typeof url !== 'string') { + throw Error("'url' field is required in external sidebar.json entries") + } + break + default: + if (typeof slug !== 'string') { + throw Error("'slug' field is required in local sidebar.json entries") + } + + if (isSourceDisabled && (!children || !children.length)) { + throw Error( + 'Local sidebar.json entries with no source must have children' + ) + } + } +} + +function findItemByField(data, field, targetValue) { + if (data.length) { + for (let i = 0; i < data.length; i++) { + const { children } = data[i] + + if (data[i][field] === targetValue) { + return data[i] + } else if (children) { + const result = findItemByField(children, field, targetValue) + if (result) { + return result + } + } + } + } +} + +function findPrevItemWithSource(data, item) { + if (item && item.source) { + return item + } else if (item && item.prev) { + const prevItem = findItemByField(data, 'path', item.prev) + + return findPrevItemWithSource(data, prevItem) + } +} + +function normalizeItem({ rawItem, parentPath, resultRef, prevRef }) { + validateRawItem(rawItem) + + const { label, slug, source, tutorials, type, url, style, icon } = rawItem + + const sharedFields = { + style, + icon + } + + switch (type) { + case 'external': + return { + type, + path: url, + label, + ...sharedFields + } + default: + // If prev item doesn't have source we need to search for it + const prevItemWithSource = + prevRef && findPrevItemWithSource(resultRef, prevRef) + + const prev = prevItemWithSource && prevItemWithSource.path + + const sourceFileName = source ? source : slug + FILE_EXTENSION + const sourcePath = FILE_ROOT + parentPath + sourceFileName + + const relativePath = parentPath + slug + + return { + path: relativePath ? `${PATH_ROOT}/${relativePath}` : PATH_ROOT, + source: source === false ? false : sourcePath, + label: label ? label : dvcTitleCase(slug), + tutorials: tutorials || {}, + prev, + next: undefined, + ...sharedFields + } + } +} + +function normalizeSidebar({ + data, + parentPath, + parentResultRef, + startingPrevRef +}) { + const currentResult = [] + const resultRef = parentResultRef || currentResult + let prevRef = startingPrevRef + + data.forEach(rawItem => { + const isShortcut = typeof rawItem === 'string' + rawItem = isShortcut ? { slug: rawItem } : rawItem + const normalizedItem = normalizeItem({ + rawItem, + parentPath, + resultRef, + prevRef + }) + + if (prevRef) { + prevRef.next = normalizedItem.path + } + + if (rawItem.children) { + normalizedItem.children = normalizeSidebar({ + data: rawItem.children, + parentPath: `${parentPath}${rawItem.slug}/`, + parentResultRef: resultRef, + startingPrevRef: normalizedItem + }) + + prevRef = normalizedItem.children[normalizedItem.children.length - 1] + } else { + prevRef = normalizedItem + } + + currentResult.push(normalizedItem) + }) + + return currentResult +} + +/* + * Exports + */ + +function buildSidebarHelpers(sidebar) { + const normalizedSidebar = normalizeSidebar({ + data: sidebar, + parentPath: '' + }) + + function findChildWithSource(item) { + // Return item unchanged if isn't root-relative + if (!item.path.startsWith('/')) return item + return item.source + ? item + : findChildWithSource(item.children && item.children[0]) + } + + function getFirstPage() { + return findChildWithSource(normalizedSidebar[0]).path + } + + function getItemByPath(path) { + const normalizedPath = path.replace(/\/$/, '') + const isRoot = normalizedPath === PATH_ROOT + const item = isRoot + ? normalizedSidebar[0] + : findItemByField(normalizedSidebar, 'path', normalizedPath) + + if (!item) return false + + return findChildWithSource(item) + } + + function getItemBySource(source) { + const item = findItemByField(normalizedSidebar, 'source', source) + + return item || false + } + + function getPathWithSource(path) { + return getItemByPath(path).path + } + function getParentsListFromPath(path) { + // If path is the homepage, indicate that it's the only one active. + // This will have to change if we add children under home, but we don't currently. + if (path === PATH_ROOT) return [PATH_ROOT] + + let currentPath = PATH_ROOT + + return path + .replace(PATH_ROOT + '/', '') + .split('/') + .map(part => { + const path = `${currentPath}/${part}` + currentPath = path + + return path + }) + } + return { + structure: normalizedSidebar, + findChildWithSource, + getItemByPath, + getItemBySource, + getPathWithSource, + getParentsListFromPath, + getFirstPage + } +} + +module.exports = buildSidebarHelpers diff --git a/src/utils/shared/sidebar.test.js b/plugins/gatsby-theme-iterative-docs/build-sidebar-helpers.test.js similarity index 83% rename from src/utils/shared/sidebar.test.js rename to plugins/gatsby-theme-iterative-docs/build-sidebar-helpers.test.js index 36e2dd8b9f..170f66ec23 100644 --- a/src/utils/shared/sidebar.test.js +++ b/plugins/gatsby-theme-iterative-docs/build-sidebar-helpers.test.js @@ -1,4 +1,5 @@ /* eslint-env jest */ +const buildSidebarHelpers = require('./build-sidebar-helpers') describe('SidebarMenu/helper', () => { beforeEach(() => { @@ -19,8 +20,7 @@ describe('SidebarMenu/helper', () => { } ] - jest.doMock('../../../content/docs/sidebar.json', () => rawData) - const sidebarData = require('./sidebar').structure + const sidebarData = buildSidebarHelpers(rawData).structure expect(sidebarData).toEqual(result) }) @@ -38,8 +38,7 @@ describe('SidebarMenu/helper', () => { } ] - jest.doMock('../../../content/docs/sidebar.json', () => rawData) - const sidebarData = require('./sidebar').structure + const sidebarData = buildSidebarHelpers(rawData).structure expect(sidebarData).toEqual(result) }) @@ -57,8 +56,7 @@ describe('SidebarMenu/helper', () => { } ] - jest.doMock('../../../content/docs/sidebar.json', () => rawData) - const sidebarData = require('./sidebar').structure + const sidebarData = buildSidebarHelpers(rawData).structure expect(sidebarData).toEqual(result) }) @@ -76,8 +74,7 @@ describe('SidebarMenu/helper', () => { } ] - jest.doMock('../../../content/docs/sidebar.json', () => rawData) - const sidebarData = require('./sidebar').structure + const sidebarData = buildSidebarHelpers(rawData).structure expect(sidebarData).toEqual(result) }) @@ -104,8 +101,7 @@ describe('SidebarMenu/helper', () => { } ] - jest.doMock('../../../content/docs/sidebar.json', () => rawData) - const sidebarData = require('./sidebar').structure + const sidebarData = buildSidebarHelpers(rawData).structure expect(sidebarData).toEqual(result) }) @@ -148,8 +144,7 @@ describe('SidebarMenu/helper', () => { } ] - jest.doMock('../../../content/docs/sidebar.json', () => rawData) - const sidebarData = require('./sidebar').structure + const sidebarData = buildSidebarHelpers(rawData).structure expect(sidebarData).toEqual(result) }) @@ -188,8 +183,7 @@ describe('SidebarMenu/helper', () => { } ] - jest.doMock('../../../content/docs/sidebar.json', () => rawData) - const sidebarData = require('./sidebar').structure + const sidebarData = buildSidebarHelpers(rawData).structure expect(sidebarData).toEqual(result) }) @@ -228,8 +222,7 @@ describe('SidebarMenu/helper', () => { } ] - jest.doMock('../../../content/docs/sidebar.json', () => rawData) - const sidebarData = require('./sidebar').structure + const sidebarData = buildSidebarHelpers(rawData).structure expect(sidebarData).toEqual(result) }) @@ -284,8 +277,7 @@ describe('SidebarMenu/helper', () => { } ] - jest.doMock('../../../content/docs/sidebar.json', () => rawData) - const sidebarData = require('./sidebar').structure + const sidebarData = buildSidebarHelpers(rawData).structure expect(sidebarData).toEqual(result) }) @@ -293,9 +285,7 @@ describe('SidebarMenu/helper', () => { it("Throws error if external item doesn't have a url field", () => { const rawData = [{ type: 'external' }] - jest.doMock('../../../content/docs/sidebar.json', () => rawData) - - expect(() => require('./sidebar')).toThrow( + expect(() => buildSidebarHelpers(rawData)).toThrow( new Error("'url' field is required in external sidebar.json entries") ) }) @@ -303,9 +293,7 @@ describe('SidebarMenu/helper', () => { it("Throws error if local item doesn't have slug field", () => { const rawData = [{}] - jest.doMock('../../../content/docs/sidebar.json', () => rawData) - - expect(() => require('./sidebar')).toThrow( + expect(() => buildSidebarHelpers(rawData)).toThrow( new Error("'slug' field is required in local sidebar.json entries") ) }) @@ -314,9 +302,7 @@ describe('SidebarMenu/helper', () => { it("Throws error if item has source: false and doesn't have children", () => { const rawData = [{ slug: 'item-name', source: false }] - jest.doMock('../../../content/docs/sidebar.json', () => rawData) - - expect(() => require('./sidebar')).toThrow( + expect(() => buildSidebarHelpers(rawData)).toThrow( new Error( 'Local sidebar.json entries with no source must have children' ) @@ -336,8 +322,7 @@ describe('SidebarMenu/helper', () => { next: undefined } - jest.doMock('../../../content/docs/sidebar.json', () => rawData) - const { getItemByPath } = require('./sidebar') + const { getItemByPath } = buildSidebarHelpers(rawData) expect(getItemByPath('/doc')).toEqual(result) }) @@ -372,8 +357,7 @@ describe('SidebarMenu/helper', () => { next: undefined } - jest.doMock('../../../content/docs/sidebar.json', () => rawData) - const { getItemByPath } = require('./sidebar') + const { getItemByPath } = buildSidebarHelpers(rawData) expect(getItemByPath('/doc/item')).toEqual(result) expect(getItemByPath('/doc/item/nested')).toEqual(result) @@ -391,8 +375,7 @@ describe('SidebarMenu/helper', () => { '/doc/item-name/nested-item/subnested-item' ] - jest.doMock('../../../content/docs/sidebar.json', () => rawData) - const { getParentsListFromPath } = require('./sidebar') + const { getParentsListFromPath } = buildSidebarHelpers(rawData) expect(getParentsListFromPath(path)).toEqual(result) }) diff --git a/src/utils/shared/sidebar.js b/src/utils/shared/sidebar.js index 93bf0fe9ac..e3d0d2d12b 100644 --- a/src/utils/shared/sidebar.js +++ b/src/utils/shared/sidebar.js @@ -1,236 +1,3 @@ -/* eslint-env node */ -/* - These helpers normalize sidebar structure and create all the resources needed. - This prevents future recalculations. - - Target structure example: - - { - label: "Add Files or Directories", - path: "/doc/start/add-files", - source: "/doc/start/add-files.md", - prev: "/doc/start/configure", - next: "/doc/start/share-data", - icon: "house", - style: "customClass", - tutorials: { - katacoda: "https://www.katacoda.com/dvc/courses/get-started" - } - children: [] - } -*/ - -const { titleCase } = require('title-case') +const buildSidebarHelpers = require('../../../plugins/gatsby-theme-iterative-docs/build-sidebar-helpers') const sidebar = require('../../../content/docs/sidebar.json') - -const PATH_ROOT = '/doc' -const FILE_ROOT = '/docs/' -const FILE_EXTENSION = '.md' - -function dvcTitleCase(slug) { - return titleCase(slug.replace(/dvc/g, 'DVC').replace(/-/g, ' ')) -} - -function validateRawItem({ slug, source, children, type, url }) { - const isSourceDisabled = source === false - - switch (type) { - case 'external': - if (typeof url !== 'string') { - throw Error("'url' field is required in external sidebar.json entries") - } - break - default: - if (typeof slug !== 'string') { - throw Error("'slug' field is required in local sidebar.json entries") - } - - if (isSourceDisabled && (!children || !children.length)) { - throw Error( - 'Local sidebar.json entries with no source must have children' - ) - } - } -} - -function findItemByField(data, field, targetValue) { - if (data.length) { - for (let i = 0; i < data.length; i++) { - const { children } = data[i] - - if (data[i][field] === targetValue) { - return data[i] - } else if (children) { - const result = findItemByField(children, field, targetValue) - if (result) { - return result - } - } - } - } -} - -function findPrevItemWithSource(data, item) { - if (item && item.source) { - return item - } else if (item && item.prev) { - const prevItem = findItemByField(data, 'path', item.prev) - - return findPrevItemWithSource(data, prevItem) - } -} - -function normalizeItem({ rawItem, parentPath, resultRef, prevRef }) { - validateRawItem(rawItem) - - const { label, slug, source, tutorials, type, url, style, icon } = rawItem - - const sharedFields = { - style, - icon - } - - switch (type) { - case 'external': - return { - type, - path: url, - label, - ...sharedFields - } - default: - // If prev item doesn't have source we need to search for it - const prevItemWithSource = - prevRef && findPrevItemWithSource(resultRef, prevRef) - - const prev = prevItemWithSource && prevItemWithSource.path - - const sourceFileName = source ? source : slug + FILE_EXTENSION - const sourcePath = FILE_ROOT + parentPath + sourceFileName - - const relativePath = parentPath + slug - - return { - path: relativePath ? `${PATH_ROOT}/${relativePath}` : PATH_ROOT, - source: source === false ? false : sourcePath, - label: label ? label : dvcTitleCase(slug), - tutorials: tutorials || {}, - prev, - next: undefined, - ...sharedFields - } - } -} - -function normalizeSidebar({ - data, - parentPath, - parentResultRef, - startingPrevRef -}) { - const currentResult = [] - const resultRef = parentResultRef || currentResult - let prevRef = startingPrevRef - - data.forEach(rawItem => { - const isShortcut = typeof rawItem === 'string' - rawItem = isShortcut ? { slug: rawItem } : rawItem - const normalizedItem = normalizeItem({ - rawItem, - parentPath, - resultRef, - prevRef - }) - - if (prevRef) { - prevRef.next = normalizedItem.path - } - - if (rawItem.children) { - normalizedItem.children = normalizeSidebar({ - data: rawItem.children, - parentPath: `${parentPath}${rawItem.slug}/`, - parentResultRef: resultRef, - startingPrevRef: normalizedItem - }) - - prevRef = normalizedItem.children[normalizedItem.children.length - 1] - } else { - prevRef = normalizedItem - } - - currentResult.push(normalizedItem) - }) - - return currentResult -} - -/* - * Exports - */ - -const normalizedSidebar = normalizeSidebar({ - data: sidebar, - parentPath: '' -}) - -function findChildWithSource(item) { - // Return item unchanged if isn't root-relative - if (!item.path.startsWith('/')) return item - return item.source - ? item - : findChildWithSource(item.children && item.children[0]) -} - -function getFirstPage() { - return findChildWithSource(normalizedSidebar[0]).path -} - -function getItemByPath(path) { - const normalizedPath = path.replace(/\/$/, '') - const isRoot = normalizedPath === PATH_ROOT - const item = isRoot - ? normalizedSidebar[0] - : findItemByField(normalizedSidebar, 'path', normalizedPath) - - if (!item) return false - - return findChildWithSource(item) -} - -function getItemBySource(source) { - const item = findItemByField(normalizedSidebar, 'source', source) - - return item || false -} - -function getPathWithSource(path) { - return getItemByPath(path).path -} -function getParentsListFromPath(path) { - // If path is the homepage, indicate that it's the only one active. - // This will have to change if we add children under home, but we don't currently. - if (path === PATH_ROOT) return [PATH_ROOT] - - let currentPath = PATH_ROOT - - return path - .replace(PATH_ROOT + '/', '') - .split('/') - .map(part => { - const path = `${currentPath}/${part}` - currentPath = path - - return path - }) -} - -module.exports = { - structure: normalizedSidebar, - findChildWithSource, - getItemByPath, - getItemBySource, - getPathWithSource, - getParentsListFromPath, - getFirstPage -} +module.exports = buildSidebarHelpers(sidebar) From b73d69a23992f749aa5289b8d70592334482bad3 Mon Sep 17 00:00:00 2001 From: rogermparent Date: Tue, 28 Dec 2021 20:15:47 -0500 Subject: [PATCH 2/7] Split sidebar normalization and utils and import via shadowing --- plugins/gatsby-remark-dvc-linker/apiLinker.js | 7 +- .../gatsby-remark-dvc-linker/commandLinker.js | 12 +- .../gatsby-remark-dvc-linker/liveLinker.js | 7 +- .../gatsby-theme-iterative-docs/constants.js | 5 + ...idebar-helpers.js => normalize-sidebar.js} | 149 +++--------------- ...pers.test.js => normalize-sidebar.test.js} | 101 ++---------- .../resolve-sidebar.js | 6 + .../sidebar-helpers.js | 100 ++++++++++++ .../sidebar-helpers.test.js | 71 +++++++++ .../src/sidebar.d.ts | 9 ++ .../src/sidebar.js | 1 + src/components/Community/Learn/index.tsx | 5 +- .../Layout/SidebarMenu/index.tsx | 8 +- .../Documentation/Markdown/Main/index.tsx | 5 +- .../Documentation/WithJSX/index.tsx | 5 +- src/components/Documentation/index.tsx | 5 +- src/components/HamburgerMenu/index.tsx | 5 +- src/components/LayoutFooter/index.tsx | 5 +- .../LayoutHeader/Nav/LinkItems/index.tsx | 5 +- src/gatsby-theme-iterative-docs/sidebar.js | 3 + src/templates/doc-jsx.tsx | 5 +- src/templates/doc.tsx | 5 +- src/utils/shared/redirects.js | 9 +- src/utils/shared/sidebar.js | 3 - 24 files changed, 282 insertions(+), 254 deletions(-) create mode 100644 plugins/gatsby-theme-iterative-docs/constants.js rename plugins/gatsby-theme-iterative-docs/{build-sidebar-helpers.js => normalize-sidebar.js} (50%) rename plugins/gatsby-theme-iterative-docs/{build-sidebar-helpers.test.js => normalize-sidebar.test.js} (73%) create mode 100644 plugins/gatsby-theme-iterative-docs/resolve-sidebar.js create mode 100644 plugins/gatsby-theme-iterative-docs/sidebar-helpers.js create mode 100644 plugins/gatsby-theme-iterative-docs/sidebar-helpers.test.js create mode 100644 plugins/gatsby-theme-iterative-docs/src/sidebar.d.ts create mode 100644 plugins/gatsby-theme-iterative-docs/src/sidebar.js create mode 100644 src/gatsby-theme-iterative-docs/sidebar.js delete mode 100644 src/utils/shared/sidebar.js diff --git a/plugins/gatsby-remark-dvc-linker/apiLinker.js b/plugins/gatsby-remark-dvc-linker/apiLinker.js index 63dfe4c276..a7d72543ce 100644 --- a/plugins/gatsby-remark-dvc-linker/apiLinker.js +++ b/plugins/gatsby-remark-dvc-linker/apiLinker.js @@ -1,7 +1,10 @@ /* eslint-env node */ const { createLinkNode } = require('./helpers') -const { getItemByPath } = require('../../src/utils/shared/sidebar') +const { + getItemByPath +} = require('../gatsby-theme-iterative-docs/sidebar-helpers') +const sidebar = require('../gatsby-theme-iterative-docs/resolve-sidebar') const DVC_API_REGEXP = /dvc.api([a-z-._]*\(\)$)?/ const METHOD_REGEXP = /^[a-z-._]*\(\)$/ @@ -25,7 +28,7 @@ module.exports = astNode => { url = `${API_ROOT}${method}` } - const isMethodPageExists = getItemByPath(url) + const isMethodPageExists = getItemByPath(sidebar, url) if (isMethodPageExists) { createLinkNode(url, astNode) } diff --git a/plugins/gatsby-remark-dvc-linker/commandLinker.js b/plugins/gatsby-remark-dvc-linker/commandLinker.js index 2afe1f0cb6..95a5acb92f 100644 --- a/plugins/gatsby-remark-dvc-linker/commandLinker.js +++ b/plugins/gatsby-remark-dvc-linker/commandLinker.js @@ -1,7 +1,10 @@ /* eslint-env node */ const { createLinkNode } = require('./helpers') -const { getItemByPath } = require('../../src/utils/shared/sidebar') +const { + getItemByPath +} = require('../gatsby-theme-iterative-docs/sidebar-helpers') +const sidebar = require('../gatsby-theme-iterative-docs/resolve-sidebar') const DVC_REGEXP = /dvc\s+[a-z][a-z-.]*/ const COMMAND_REGEXP = /^[a-z][a-z-]*$/ @@ -16,11 +19,14 @@ module.exports = astNode => { let url const hasThirdSegment = parts[2] && COMMAND_REGEXP.test(parts[2]) - const isCommandPageExists = getItemByPath(`${COMMAND_ROOT}${parts[1]}`) + const isCommandPageExists = getItemByPath( + sidebar, + `${COMMAND_ROOT}${parts[1]}` + ) const isSubcommandPageExists = isCommandPageExists && hasThirdSegment && - getItemByPath(`${COMMAND_ROOT}${parts[1]}/${parts[2]}`) + getItemByPath(sidebar, `${COMMAND_ROOT}${parts[1]}/${parts[2]}`) if (isSubcommandPageExists) { url = `${COMMAND_ROOT}${parts[1]}/${parts[2]}` diff --git a/plugins/gatsby-remark-dvc-linker/liveLinker.js b/plugins/gatsby-remark-dvc-linker/liveLinker.js index 2b5c4fe15e..ade4aabb30 100644 --- a/plugins/gatsby-remark-dvc-linker/liveLinker.js +++ b/plugins/gatsby-remark-dvc-linker/liveLinker.js @@ -1,7 +1,10 @@ /* eslint-env node */ const { createLinkNode } = require('./helpers') -const { getItemByPath } = require('../../src/utils/shared/sidebar') +const { + getItemByPath +} = require('../gatsby-theme-iterative-docs/sidebar-helpers') +const sidebar = require('../gatsby-theme-iterative-docs/resolve-sidebar') const LIVE_API_REGEXP = /Live.([a-z-._]*\(\)$)?/ const METHOD_REGEXP = /^[a-z-._]*\(\)$/ @@ -17,7 +20,7 @@ module.exports = astNode => { const method = isMethod && parts[1].slice(0, -2) const url = `${API_ROOT}${method}` - const isMethodPageExists = getItemByPath(url) + const isMethodPageExists = getItemByPath(sidebar, url) if (isMethodPageExists) { createLinkNode(url, astNode) } diff --git a/plugins/gatsby-theme-iterative-docs/constants.js b/plugins/gatsby-theme-iterative-docs/constants.js new file mode 100644 index 0000000000..af3d7299dd --- /dev/null +++ b/plugins/gatsby-theme-iterative-docs/constants.js @@ -0,0 +1,5 @@ +module.exports = { + PATH_ROOT: '/doc', + FILE_ROOT: '/docs/', + FILE_EXTENSION: '.md' +} diff --git a/plugins/gatsby-theme-iterative-docs/build-sidebar-helpers.js b/plugins/gatsby-theme-iterative-docs/normalize-sidebar.js similarity index 50% rename from plugins/gatsby-theme-iterative-docs/build-sidebar-helpers.js rename to plugins/gatsby-theme-iterative-docs/normalize-sidebar.js index f138b3d5e4..e620c14ec5 100644 --- a/plugins/gatsby-theme-iterative-docs/build-sidebar-helpers.js +++ b/plugins/gatsby-theme-iterative-docs/normalize-sidebar.js @@ -1,35 +1,23 @@ -/* eslint-env node */ -/* - These helpers normalize sidebar structure and create all the resources needed. - This prevents future recalculations. - - Target structure example: - - { - label: "Add Files or Directories", - path: "/doc/start/add-files", - source: "/doc/start/add-files.md", - prev: "/doc/start/configure", - next: "/doc/start/share-data", - icon: "house", - style: "customClass", - tutorials: { - katacoda: "https://www.katacoda.com/dvc/courses/get-started" - } - children: [] - } -*/ +const { PATH_ROOT, FILE_ROOT, FILE_EXTENSION } = require('./constants') -const { titleCase } = require('title-case') +const { findItemByField } = require('./sidebar-helpers') -const PATH_ROOT = '/doc' -const FILE_ROOT = '/docs/' -const FILE_EXTENSION = '.md' +const { titleCase } = require('title-case') function dvcTitleCase(slug) { return titleCase(slug.replace(/dvc/g, 'DVC').replace(/-/g, ' ')) } +function findPrevItemWithSource(data, item) { + if (item && item.source) { + return item + } else if (item && item.prev) { + const prevItem = findItemByField(data, 'path', item.prev) + + return findPrevItemWithSource(data, prevItem) + } +} + function validateRawItem({ slug, source, children, type, url }) { const isSourceDisabled = source === false @@ -52,33 +40,6 @@ function validateRawItem({ slug, source, children, type, url }) { } } -function findItemByField(data, field, targetValue) { - if (data.length) { - for (let i = 0; i < data.length; i++) { - const { children } = data[i] - - if (data[i][field] === targetValue) { - return data[i] - } else if (children) { - const result = findItemByField(children, field, targetValue) - if (result) { - return result - } - } - } - } -} - -function findPrevItemWithSource(data, item) { - if (item && item.source) { - return item - } else if (item && item.prev) { - const prevItem = findItemByField(data, 'path', item.prev) - - return findPrevItemWithSource(data, prevItem) - } -} - function normalizeItem({ rawItem, parentPath, resultRef, prevRef }) { validateRawItem(rawItem) @@ -121,12 +82,10 @@ function normalizeItem({ rawItem, parentPath, resultRef, prevRef }) { } } -function normalizeSidebar({ +function normalizeSidebar( data, - parentPath, - parentResultRef, - startingPrevRef -}) { + { parentPath = '', parentResultRef, startingPrevRef } = {} +) { const currentResult = [] const resultRef = parentResultRef || currentResult let prevRef = startingPrevRef @@ -146,8 +105,7 @@ function normalizeSidebar({ } if (rawItem.children) { - normalizedItem.children = normalizeSidebar({ - data: rawItem.children, + normalizedItem.children = normalizeSidebar(rawItem.children, { parentPath: `${parentPath}${rawItem.slug}/`, parentResultRef: resultRef, startingPrevRef: normalizedItem @@ -164,75 +122,4 @@ function normalizeSidebar({ return currentResult } -/* - * Exports - */ - -function buildSidebarHelpers(sidebar) { - const normalizedSidebar = normalizeSidebar({ - data: sidebar, - parentPath: '' - }) - - function findChildWithSource(item) { - // Return item unchanged if isn't root-relative - if (!item.path.startsWith('/')) return item - return item.source - ? item - : findChildWithSource(item.children && item.children[0]) - } - - function getFirstPage() { - return findChildWithSource(normalizedSidebar[0]).path - } - - function getItemByPath(path) { - const normalizedPath = path.replace(/\/$/, '') - const isRoot = normalizedPath === PATH_ROOT - const item = isRoot - ? normalizedSidebar[0] - : findItemByField(normalizedSidebar, 'path', normalizedPath) - - if (!item) return false - - return findChildWithSource(item) - } - - function getItemBySource(source) { - const item = findItemByField(normalizedSidebar, 'source', source) - - return item || false - } - - function getPathWithSource(path) { - return getItemByPath(path).path - } - function getParentsListFromPath(path) { - // If path is the homepage, indicate that it's the only one active. - // This will have to change if we add children under home, but we don't currently. - if (path === PATH_ROOT) return [PATH_ROOT] - - let currentPath = PATH_ROOT - - return path - .replace(PATH_ROOT + '/', '') - .split('/') - .map(part => { - const path = `${currentPath}/${part}` - currentPath = path - - return path - }) - } - return { - structure: normalizedSidebar, - findChildWithSource, - getItemByPath, - getItemBySource, - getPathWithSource, - getParentsListFromPath, - getFirstPage - } -} - -module.exports = buildSidebarHelpers +module.exports = normalizeSidebar diff --git a/plugins/gatsby-theme-iterative-docs/build-sidebar-helpers.test.js b/plugins/gatsby-theme-iterative-docs/normalize-sidebar.test.js similarity index 73% rename from plugins/gatsby-theme-iterative-docs/build-sidebar-helpers.test.js rename to plugins/gatsby-theme-iterative-docs/normalize-sidebar.test.js index 170f66ec23..d613592c6a 100644 --- a/plugins/gatsby-theme-iterative-docs/build-sidebar-helpers.test.js +++ b/plugins/gatsby-theme-iterative-docs/normalize-sidebar.test.js @@ -1,11 +1,7 @@ /* eslint-env jest */ -const buildSidebarHelpers = require('./build-sidebar-helpers') +const normalizeSidebar = require('./normalize-sidebar') describe('SidebarMenu/helper', () => { - beforeEach(() => { - jest.resetModules() - }) - describe('default', () => { it('Resolves shortcuts to full syntax', () => { const rawData = ['item-name'] @@ -20,7 +16,7 @@ describe('SidebarMenu/helper', () => { } ] - const sidebarData = buildSidebarHelpers(rawData).structure + const sidebarData = normalizeSidebar(rawData) expect(sidebarData).toEqual(result) }) @@ -38,7 +34,7 @@ describe('SidebarMenu/helper', () => { } ] - const sidebarData = buildSidebarHelpers(rawData).structure + const sidebarData = normalizeSidebar(rawData) expect(sidebarData).toEqual(result) }) @@ -56,7 +52,7 @@ describe('SidebarMenu/helper', () => { } ] - const sidebarData = buildSidebarHelpers(rawData).structure + const sidebarData = normalizeSidebar(rawData) expect(sidebarData).toEqual(result) }) @@ -74,7 +70,7 @@ describe('SidebarMenu/helper', () => { } ] - const sidebarData = buildSidebarHelpers(rawData).structure + const sidebarData = normalizeSidebar(rawData) expect(sidebarData).toEqual(result) }) @@ -101,7 +97,7 @@ describe('SidebarMenu/helper', () => { } ] - const sidebarData = buildSidebarHelpers(rawData).structure + const sidebarData = normalizeSidebar(rawData) expect(sidebarData).toEqual(result) }) @@ -144,7 +140,7 @@ describe('SidebarMenu/helper', () => { } ] - const sidebarData = buildSidebarHelpers(rawData).structure + const sidebarData = normalizeSidebar(rawData) expect(sidebarData).toEqual(result) }) @@ -183,7 +179,7 @@ describe('SidebarMenu/helper', () => { } ] - const sidebarData = buildSidebarHelpers(rawData).structure + const sidebarData = normalizeSidebar(rawData) expect(sidebarData).toEqual(result) }) @@ -222,7 +218,7 @@ describe('SidebarMenu/helper', () => { } ] - const sidebarData = buildSidebarHelpers(rawData).structure + const sidebarData = normalizeSidebar(rawData) expect(sidebarData).toEqual(result) }) @@ -277,7 +273,7 @@ describe('SidebarMenu/helper', () => { } ] - const sidebarData = buildSidebarHelpers(rawData).structure + const sidebarData = normalizeSidebar(rawData) expect(sidebarData).toEqual(result) }) @@ -285,7 +281,7 @@ describe('SidebarMenu/helper', () => { it("Throws error if external item doesn't have a url field", () => { const rawData = [{ type: 'external' }] - expect(() => buildSidebarHelpers(rawData)).toThrow( + expect(() => normalizeSidebar(rawData)).toThrow( new Error("'url' field is required in external sidebar.json entries") ) }) @@ -293,7 +289,7 @@ describe('SidebarMenu/helper', () => { it("Throws error if local item doesn't have slug field", () => { const rawData = [{}] - expect(() => buildSidebarHelpers(rawData)).toThrow( + expect(() => normalizeSidebar(rawData)).toThrow( new Error("'slug' field is required in local sidebar.json entries") ) }) @@ -302,82 +298,11 @@ describe('SidebarMenu/helper', () => { it("Throws error if item has source: false and doesn't have children", () => { const rawData = [{ slug: 'item-name', source: false }] - expect(() => buildSidebarHelpers(rawData)).toThrow( + expect(() => normalizeSidebar(rawData)).toThrow( new Error( 'Local sidebar.json entries with no source must have children' ) ) }) }) - - describe('getItemByPath', () => { - it('Returns first child for the /doc path', () => { - const rawData = ['item-name'] - const result = { - label: 'Item Name', - path: '/doc/item-name', - source: '/docs/item-name.md', - tutorials: {}, - prev: undefined, - next: undefined - } - - const { getItemByPath } = buildSidebarHelpers(rawData) - - expect(getItemByPath('/doc')).toEqual(result) - }) - - // eslint-disable-next-line max-len - it('Returns first child with source for all parents with source:false', () => { - const rawData = [ - { - slug: 'item', - source: false, - children: [ - { - slug: 'nested', - source: false, - children: [ - { - slug: 'subnested', - source: false, - children: ['leaf-item'] - } - ] - } - ] - } - ] - const result = { - label: 'Leaf Item', - path: '/doc/item/nested/subnested/leaf-item', - source: '/docs/item/nested/subnested/leaf-item.md', - tutorials: {}, - prev: undefined, - next: undefined - } - - const { getItemByPath } = buildSidebarHelpers(rawData) - - expect(getItemByPath('/doc/item')).toEqual(result) - expect(getItemByPath('/doc/item/nested')).toEqual(result) - expect(getItemByPath('/doc/item/nested/subnested')).toEqual(result) - }) - }) - - describe('getParentsListFromPath', () => { - it("Returns array of current and parent's paths", () => { - const rawData = [] - const path = '/doc/item-name/nested-item/subnested-item' - const result = [ - '/doc/item-name', - '/doc/item-name/nested-item', - '/doc/item-name/nested-item/subnested-item' - ] - - const { getParentsListFromPath } = buildSidebarHelpers(rawData) - - expect(getParentsListFromPath(path)).toEqual(result) - }) - }) }) diff --git a/plugins/gatsby-theme-iterative-docs/resolve-sidebar.js b/plugins/gatsby-theme-iterative-docs/resolve-sidebar.js new file mode 100644 index 0000000000..48071b5fd6 --- /dev/null +++ b/plugins/gatsby-theme-iterative-docs/resolve-sidebar.js @@ -0,0 +1,6 @@ +const path = require('path') +module.exports = require(path.resolve( + 'src', + 'gatsby-theme-iterative-docs', + 'sidebar' +)) diff --git a/plugins/gatsby-theme-iterative-docs/sidebar-helpers.js b/plugins/gatsby-theme-iterative-docs/sidebar-helpers.js new file mode 100644 index 0000000000..aea03c660e --- /dev/null +++ b/plugins/gatsby-theme-iterative-docs/sidebar-helpers.js @@ -0,0 +1,100 @@ +/* eslint-env node */ +/* + These helpers normalize sidebar structure and create all the resources needed. + This prevents future recalculations. + + Target structure example: + + { + label: "Add Files or Directories", + path: "/doc/start/add-files", + source: "/doc/start/add-files.md", + prev: "/doc/start/configure", + next: "/doc/start/share-data", + icon: "house", + style: "customClass", + tutorials: { + katacoda: "https://www.katacoda.com/dvc/courses/get-started" + } + children: [] + } +*/ + +const { PATH_ROOT, FILE_ROOT, FILE_EXTENSION } = require('./constants') + +function findItemByField(data, field, targetValue) { + if (data.length) { + for (let i = 0; i < data.length; i++) { + const { children } = data[i] + + if (data[i][field] === targetValue) { + return data[i] + } else if (children) { + const result = findItemByField(children, field, targetValue) + if (result) { + return result + } + } + } + } +} + +function findChildWithSource(item) { + // Return item unchanged if isn't root-relative + if (!item.path.startsWith('/')) return item + return item.source + ? item + : findChildWithSource(item.children && item.children[0]) +} + +function getFirstPage(normalizedSidebar) { + return findChildWithSource(normalizedSidebar[0]).path +} + +function getItemByPath(normalizedSidebar, path) { + const normalizedPath = path.replace(/\/$/, '') + const isRoot = normalizedPath === PATH_ROOT + const item = isRoot + ? normalizedSidebar[0] + : findItemByField(normalizedSidebar, 'path', normalizedPath) + + if (!item) return false + + return findChildWithSource(item) +} + +function getItemBySource(normalizedSidebar, source) { + const item = findItemByField(normalizedSidebar, 'source', source) + + return item || false +} + +function getPathWithSource(normalizedSidebar, path) { + return getItemByPath(normalizedSidebar, path).path +} +function getParentsListFromPath(path) { + // If path is the homepage, indicate that it's the only one active. + // This will have to change if we add children under home, but we don't currently. + if (path === PATH_ROOT) return [PATH_ROOT] + + let currentPath = PATH_ROOT + + return path + .replace(PATH_ROOT + '/', '') + .split('/') + .map(part => { + const path = `${currentPath}/${part}` + currentPath = path + + return path + }) +} +module.exports = { + findItemByField, + findChildWithSource, + getItemByPath, + getItemBySource, + getPathWithSource, + getParentsListFromPath, + getFirstPage +} diff --git a/plugins/gatsby-theme-iterative-docs/sidebar-helpers.test.js b/plugins/gatsby-theme-iterative-docs/sidebar-helpers.test.js new file mode 100644 index 0000000000..79bf28aa76 --- /dev/null +++ b/plugins/gatsby-theme-iterative-docs/sidebar-helpers.test.js @@ -0,0 +1,71 @@ +/* eslint-env jest */ +const normalizeSidebar = require('./normalize-sidebar') +const { getItemByPath, getParentsListFromPath } = require('./sidebar-helpers') + +describe('SidebarMenu/helper', () => { + describe('getItemByPath', () => { + it('Returns first child for the /doc path', () => { + const sidebar = normalizeSidebar(['item-name']) + const result = { + label: 'Item Name', + path: '/doc/item-name', + source: '/docs/item-name.md', + tutorials: {}, + prev: undefined, + next: undefined + } + + expect(getItemByPath(sidebar, '/doc')).toEqual(result) + }) + + // eslint-disable-next-line max-len + it('Returns first child with source for all parents with source:false', () => { + const sidebar = normalizeSidebar([ + { + slug: 'item', + source: false, + children: [ + { + slug: 'nested', + source: false, + children: [ + { + slug: 'subnested', + source: false, + children: ['leaf-item'] + } + ] + } + ] + } + ]) + const result = { + label: 'Leaf Item', + path: '/doc/item/nested/subnested/leaf-item', + source: '/docs/item/nested/subnested/leaf-item.md', + tutorials: {}, + prev: undefined, + next: undefined + } + + expect(getItemByPath(sidebar, '/doc/item')).toEqual(result) + expect(getItemByPath(sidebar, '/doc/item/nested')).toEqual(result) + expect(getItemByPath(sidebar, '/doc/item/nested/subnested')).toEqual( + result + ) + }) + }) + + describe('getParentsListFromPath', () => { + it("Returns array of current and parent's paths", () => { + const path = '/doc/item-name/nested-item/subnested-item' + const result = [ + '/doc/item-name', + '/doc/item-name/nested-item', + '/doc/item-name/nested-item/subnested-item' + ] + + expect(getParentsListFromPath(path)).toEqual(result) + }) + }) +}) diff --git a/plugins/gatsby-theme-iterative-docs/src/sidebar.d.ts b/plugins/gatsby-theme-iterative-docs/src/sidebar.d.ts new file mode 100644 index 0000000000..0bbcfbf821 --- /dev/null +++ b/plugins/gatsby-theme-iterative-docs/src/sidebar.d.ts @@ -0,0 +1,9 @@ +declare interface NormalizedSidebarItem { + label: string + path: string + source: boolean | string +} + +declare const sidebar: NormalizedSidebarItem[] + +export default sidebar diff --git a/plugins/gatsby-theme-iterative-docs/src/sidebar.js b/plugins/gatsby-theme-iterative-docs/src/sidebar.js new file mode 100644 index 0000000000..d7faf17f9b --- /dev/null +++ b/plugins/gatsby-theme-iterative-docs/src/sidebar.js @@ -0,0 +1 @@ +module.exports = [] diff --git a/src/components/Community/Learn/index.tsx b/src/components/Community/Learn/index.tsx index 1221b703a6..f6f67cd71a 100644 --- a/src/components/Community/Learn/index.tsx +++ b/src/components/Community/Learn/index.tsx @@ -9,7 +9,8 @@ import Block from '../Block' import Section from '../Section' import { logEvent } from '../../../utils/front/plausible' -import { getFirstPage } from '../../../utils/shared/sidebar' +import { getFirstPage } from '../../../../plugins/gatsby-theme-iterative-docs/sidebar-helpers' +import sidebar from '../../../../plugins/gatsby-theme-iterative-docs/src/sidebar' import { useCommentsCount } from '../../../utils/front/api' import { useCommunityData } from '../../../utils/front/community' import getPosts from '../../../queries/posts' @@ -18,7 +19,7 @@ import { pluralizeComments } from '../../../utils/front/i18n' import * as sharedStyles from '../styles.module.css' import * as styles from './styles.module.css' -const docsPage = getFirstPage() +const docsPage = getFirstPage(sidebar) const log = (section: string, value: string) => logEvent('Community', { Section: 'learn', [`Learn ${section}`]: value }) diff --git a/src/components/Documentation/Layout/SidebarMenu/index.tsx b/src/components/Documentation/Layout/SidebarMenu/index.tsx index f65ebf595a..4209f35aae 100644 --- a/src/components/Documentation/Layout/SidebarMenu/index.tsx +++ b/src/components/Documentation/Layout/SidebarMenu/index.tsx @@ -14,10 +14,10 @@ import { ReactComponent as CMLIcon } from './cml_bw_logo.svg' import { ReactComponent as StudioIcon } from './studio_gray_icon.svg' import { - structure, getParentsListFromPath, getPathWithSource -} from '../../../../utils/shared/sidebar' +} from '../../../../../plugins/gatsby-theme-iterative-docs/sidebar-helpers' +import sidebar from '../../../../../plugins/gatsby-theme-iterative-docs/src/sidebar' import 'perfect-scrollbar/css/perfect-scrollbar.css' import * as styles from './styles.module.css' @@ -123,7 +123,7 @@ const SidebarMenuItem: React.FC = ({ ) : ( = ({ currentPath, onClick }) => { >
- {structure.map(item => ( + {sidebar.map(item => ( = ({ Next diff --git a/src/components/Documentation/WithJSX/index.tsx b/src/components/Documentation/WithJSX/index.tsx index 5ac53e647a..e87b2d6883 100644 --- a/src/components/Documentation/WithJSX/index.tsx +++ b/src/components/Documentation/WithJSX/index.tsx @@ -4,7 +4,8 @@ import MarkdownMain from '../Markdown/Main' import RightPanel from '../RightPanel' import { IHeading, getGithubLink } from '../' -import { getItemByPath } from '../../../utils/shared/sidebar' +import { getItemByPath } from '../../../../plugins/gatsby-theme-iterative-docs/sidebar-helpers' +import sidebar from '../../../../plugins/gatsby-theme-iterative-docs/src/sidebar' interface IWithJSXProps { path: string @@ -12,7 +13,7 @@ interface IWithJSXProps { } const WithJSX: React.FC = ({ children, path, headings }) => { - const { source, prev, next, tutorials } = getItemByPath(path) + const { source, prev, next, tutorials } = getItemByPath(sidebar, path) const githubLink = getGithubLink(source) return ( diff --git a/src/components/Documentation/index.tsx b/src/components/Documentation/index.tsx index a2d9c3e175..fe0825c650 100644 --- a/src/components/Documentation/index.tsx +++ b/src/components/Documentation/index.tsx @@ -4,7 +4,8 @@ import { Node } from 'unist' import Markdown from './Markdown' import RightPanel from './RightPanel' -import { getItemByPath } from '../../utils/shared/sidebar' +import { getItemByPath } from '../../../plugins/gatsby-theme-iterative-docs/sidebar-helpers' +import sidebar from '../../../plugins/gatsby-theme-iterative-docs/src/sidebar' export interface IHeading { slug: string @@ -25,7 +26,7 @@ const Documentation: React.FC = ({ path, headings }) => { - const { source, prev, next, tutorials } = getItemByPath(path) + const { source, prev, next, tutorials } = getItemByPath(sidebar, path) const githubLink = getGithubLink(source) return ( diff --git a/src/components/HamburgerMenu/index.tsx b/src/components/HamburgerMenu/index.tsx index 1fa2c4b969..6fb3e7996e 100644 --- a/src/components/HamburgerMenu/index.tsx +++ b/src/components/HamburgerMenu/index.tsx @@ -5,14 +5,15 @@ import HamburgerIcon from '../HamburgerIcon' import Link from '../Link' import { logEvent } from '../../utils/front/plausible' -import { getFirstPage } from '../../utils/shared/sidebar' +import { getFirstPage } from '../../../plugins/gatsby-theme-iterative-docs/sidebar-helpers' +import sidebar from '../../../plugins/gatsby-theme-iterative-docs/src/sidebar' import { ReactComponent as LogoSVG } from '../../../static/img/logo-white.svg' import { ReactComponent as TwitterIcon } from '../SocialIcon/twitter.svg' import { ReactComponent as GithubIcon } from '../SocialIcon/github.svg' import * as styles from './styles.module.css' -const docsPage = getFirstPage() +const docsPage = getFirstPage(sidebar) export type HamburgerHelpers = { opened: boolean diff --git a/src/components/LayoutFooter/index.tsx b/src/components/LayoutFooter/index.tsx index 1d68151531..f2d6e860f8 100644 --- a/src/components/LayoutFooter/index.tsx +++ b/src/components/LayoutFooter/index.tsx @@ -5,7 +5,8 @@ import LayoutWidthContainer from '../LayoutWidthContainer' import Link from '../Link' import SocialIcon, { ISocialIcon } from '../SocialIcon' import ShowOnly from '../ShowOnly' -import { getFirstPage } from '../../utils/shared/sidebar' +import { getFirstPage } from '../../../plugins/gatsby-theme-iterative-docs/sidebar-helpers' +import sidebar from '../../../plugins/gatsby-theme-iterative-docs/src/sidebar' import { ReactComponent as LogoSVG } from '../../../static/img/dvc_icon-color--square_vector.svg' import { ReactComponent as GithubSVG } from '../SocialIcon/github.svg' @@ -18,7 +19,7 @@ import { ReactComponent as MlemSVG } from '../../../static/img/mlem-icon.svg' import * as styles from './styles.module.css' -const docsPage = getFirstPage() +const docsPage = getFirstPage(sidebar) interface IFooterLinkData { href: string diff --git a/src/components/LayoutHeader/Nav/LinkItems/index.tsx b/src/components/LayoutHeader/Nav/LinkItems/index.tsx index ee086ccf3e..13ebd6c779 100644 --- a/src/components/LayoutHeader/Nav/LinkItems/index.tsx +++ b/src/components/LayoutHeader/Nav/LinkItems/index.tsx @@ -8,9 +8,10 @@ import { ReactComponent as ArrowUpSVG } from '../../../../../static/img/arrow-up import { ReactComponent as ArrowDownSVG } from '../../../../../static/img/arrow-down-icon.svg' import { logEvent } from '../../../../utils/front/plausible' -import { getFirstPage } from '../../../../utils/shared/sidebar' +import { getFirstPage } from '../../../../../plugins/gatsby-theme-iterative-docs/sidebar-helpers' +import sidebar from '../../../../../plugins/gatsby-theme-iterative-docs/src/sidebar' -const docsPage = getFirstPage() +const docsPage = getFirstPage(sidebar) import * as styles from './styles.module.css' diff --git a/src/gatsby-theme-iterative-docs/sidebar.js b/src/gatsby-theme-iterative-docs/sidebar.js new file mode 100644 index 0000000000..66ee2fb8f2 --- /dev/null +++ b/src/gatsby-theme-iterative-docs/sidebar.js @@ -0,0 +1,3 @@ +const normalizeSidebar = require('../../plugins/gatsby-theme-iterative-docs/normalize-sidebar') +const sidebar = require('../../content/docs/sidebar.json') +module.exports = normalizeSidebar(sidebar) diff --git a/src/templates/doc-jsx.tsx b/src/templates/doc-jsx.tsx index 085f39c1f2..a054cca854 100644 --- a/src/templates/doc-jsx.tsx +++ b/src/templates/doc-jsx.tsx @@ -1,5 +1,6 @@ import React from 'react' -import { getItemByPath } from '../utils/shared/sidebar' +import { getItemByPath } from '../../plugins/gatsby-theme-iterative-docs/sidebar-helpers' +import sidebar from '../../plugins/gatsby-theme-iterative-docs/src/sidebar' import SEO from '../components/SEO' @@ -19,7 +20,7 @@ const JSXDocPage: React.FC = ({ slug, headings }) => { - const { label } = getItemByPath(slug) + const { label } = getItemByPath(sidebar, slug) return ( <> diff --git a/src/templates/doc.tsx b/src/templates/doc.tsx index 35a20ffd61..caf8ed1ffa 100644 --- a/src/templates/doc.tsx +++ b/src/templates/doc.tsx @@ -1,7 +1,8 @@ import React from 'react' import { graphql } from 'gatsby' import { Node } from 'unist' -import { getItemByPath } from '../utils/shared/sidebar' +import { getItemByPath } from '../../plugins/gatsby-theme-iterative-docs/sidebar-helpers' +import sidebar from '../../plugins/gatsby-theme-iterative-docs/src/sidebar' import SEO from '../components/SEO' @@ -35,7 +36,7 @@ const DocPage: React.FC = ({ } } = data - const { label } = getItemByPath(slug) + const { label } = getItemByPath(sidebar, slug) return ( <> diff --git a/src/utils/shared/redirects.js b/src/utils/shared/redirects.js index 773f3244fd..ebc6b42887 100644 --- a/src/utils/shared/redirects.js +++ b/src/utils/shared/redirects.js @@ -1,12 +1,15 @@ /* eslint-env node */ const { navigate } = require('@reach/router') -const { structure, findChildWithSource } = require('./sidebar') +const sidebar = require('../../gatsby-theme-iterative-docs/sidebar') +const { + findChildWithSource +} = require('../../../plugins/gatsby-theme-iterative-docs/sidebar-helpers') const buildSidebarRedirects = (list, redirects = []) => { list.forEach(item => { if (!item.source && item.children) { - const redirectToChild = findChildWithSource(item) + const redirectToChild = findChildWithSource(sidebar, item) redirects.push(`^${item.path}/?$ ${redirectToChild.path} 307`) } @@ -39,7 +42,7 @@ const getRedirects = (() => { if (!allRedirects) { allRedirects = [ ...require('../../../redirects-list.json'), - ...buildSidebarRedirects(structure) + ...buildSidebarRedirects(sidebar) ].map(processRedirectString) } diff --git a/src/utils/shared/sidebar.js b/src/utils/shared/sidebar.js deleted file mode 100644 index e3d0d2d12b..0000000000 --- a/src/utils/shared/sidebar.js +++ /dev/null @@ -1,3 +0,0 @@ -const buildSidebarHelpers = require('../../../plugins/gatsby-theme-iterative-docs/build-sidebar-helpers') -const sidebar = require('../../../content/docs/sidebar.json') -module.exports = buildSidebarHelpers(sidebar) From 0f1c0fe008dcb4017f95b722d2d5cc2f1b8082e0 Mon Sep 17 00:00:00 2001 From: rogermparent Date: Tue, 28 Dec 2021 20:37:37 -0500 Subject: [PATCH 3/7] Fix usage of findChildWithSource --- src/utils/shared/redirects.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/shared/redirects.js b/src/utils/shared/redirects.js index ebc6b42887..12b77160ec 100644 --- a/src/utils/shared/redirects.js +++ b/src/utils/shared/redirects.js @@ -9,7 +9,7 @@ const { const buildSidebarRedirects = (list, redirects = []) => { list.forEach(item => { if (!item.source && item.children) { - const redirectToChild = findChildWithSource(sidebar, item) + const redirectToChild = findChildWithSource(item) redirects.push(`^${item.path}/?$ ${redirectToChild.path} 307`) } From 332644a66c901a7b0dcccf100147a4b2c2e94798 Mon Sep 17 00:00:00 2001 From: rogermparent Date: Tue, 28 Dec 2021 20:42:15 -0500 Subject: [PATCH 4/7] Fix lint-ts errors --- plugins/gatsby-theme-iterative-docs/sidebar-helpers.js | 2 +- plugins/gatsby-theme-iterative-docs/src/sidebar.d.ts | 4 ++-- src/gatsby-theme-iterative-docs/sidebar.js | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/gatsby-theme-iterative-docs/sidebar-helpers.js b/plugins/gatsby-theme-iterative-docs/sidebar-helpers.js index aea03c660e..ecaddb9c29 100644 --- a/plugins/gatsby-theme-iterative-docs/sidebar-helpers.js +++ b/plugins/gatsby-theme-iterative-docs/sidebar-helpers.js @@ -20,7 +20,7 @@ } */ -const { PATH_ROOT, FILE_ROOT, FILE_EXTENSION } = require('./constants') +const { PATH_ROOT } = require('./constants') function findItemByField(data, field, targetValue) { if (data.length) { diff --git a/plugins/gatsby-theme-iterative-docs/src/sidebar.d.ts b/plugins/gatsby-theme-iterative-docs/src/sidebar.d.ts index 0bbcfbf821..0d5fdd9a3c 100644 --- a/plugins/gatsby-theme-iterative-docs/src/sidebar.d.ts +++ b/plugins/gatsby-theme-iterative-docs/src/sidebar.d.ts @@ -1,9 +1,9 @@ -declare interface NormalizedSidebarItem { +declare interface INormalizedSidebarItem { label: string path: string source: boolean | string } -declare const sidebar: NormalizedSidebarItem[] +declare const sidebar: INormalizedSidebarItem[] export default sidebar diff --git a/src/gatsby-theme-iterative-docs/sidebar.js b/src/gatsby-theme-iterative-docs/sidebar.js index 66ee2fb8f2..9f1408540e 100644 --- a/src/gatsby-theme-iterative-docs/sidebar.js +++ b/src/gatsby-theme-iterative-docs/sidebar.js @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ const normalizeSidebar = require('../../plugins/gatsby-theme-iterative-docs/normalize-sidebar') const sidebar = require('../../content/docs/sidebar.json') module.exports = normalizeSidebar(sidebar) From c127d19fcff862eaa2d21ff016164dd4ac1a152f Mon Sep 17 00:00:00 2001 From: rogermparent Date: Wed, 29 Dec 2021 16:35:23 -0500 Subject: [PATCH 5/7] Move comment normalized item definition to d.ts --- .../sidebar-helpers.js | 22 ------------------- .../sidebar-helpers.test.js | 1 - .../src/sidebar.d.ts | 10 ++++++++- 3 files changed, 9 insertions(+), 24 deletions(-) diff --git a/plugins/gatsby-theme-iterative-docs/sidebar-helpers.js b/plugins/gatsby-theme-iterative-docs/sidebar-helpers.js index ecaddb9c29..d6a60ab573 100644 --- a/plugins/gatsby-theme-iterative-docs/sidebar-helpers.js +++ b/plugins/gatsby-theme-iterative-docs/sidebar-helpers.js @@ -1,25 +1,3 @@ -/* eslint-env node */ -/* - These helpers normalize sidebar structure and create all the resources needed. - This prevents future recalculations. - - Target structure example: - - { - label: "Add Files or Directories", - path: "/doc/start/add-files", - source: "/doc/start/add-files.md", - prev: "/doc/start/configure", - next: "/doc/start/share-data", - icon: "house", - style: "customClass", - tutorials: { - katacoda: "https://www.katacoda.com/dvc/courses/get-started" - } - children: [] - } -*/ - const { PATH_ROOT } = require('./constants') function findItemByField(data, field, targetValue) { diff --git a/plugins/gatsby-theme-iterative-docs/sidebar-helpers.test.js b/plugins/gatsby-theme-iterative-docs/sidebar-helpers.test.js index 79bf28aa76..bb15bf9aeb 100644 --- a/plugins/gatsby-theme-iterative-docs/sidebar-helpers.test.js +++ b/plugins/gatsby-theme-iterative-docs/sidebar-helpers.test.js @@ -1,4 +1,3 @@ -/* eslint-env jest */ const normalizeSidebar = require('./normalize-sidebar') const { getItemByPath, getParentsListFromPath } = require('./sidebar-helpers') diff --git a/plugins/gatsby-theme-iterative-docs/src/sidebar.d.ts b/plugins/gatsby-theme-iterative-docs/src/sidebar.d.ts index 0d5fdd9a3c..75d7957ff8 100644 --- a/plugins/gatsby-theme-iterative-docs/src/sidebar.d.ts +++ b/plugins/gatsby-theme-iterative-docs/src/sidebar.d.ts @@ -1,7 +1,15 @@ declare interface INormalizedSidebarItem { label: string path: string - source: boolean | string + source?: string + prev?: string + next?: string + icon?: string + style?: string + tutorials?: { + katacoda: string + } + children?: INormalizedSidebarItem[] } declare const sidebar: INormalizedSidebarItem[] From a24e1d68e466209be86b6ef7d4d6df77e7f4fbef Mon Sep 17 00:00:00 2001 From: rogermparent Date: Wed, 29 Dec 2021 16:46:46 -0500 Subject: [PATCH 6/7] Update and export INormalizedSidebarItem and use it in SidebarMenu --- .../src/sidebar.d.ts | 3 ++- .../Layout/SidebarMenu/index.tsx | 25 ++++++------------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/plugins/gatsby-theme-iterative-docs/src/sidebar.d.ts b/plugins/gatsby-theme-iterative-docs/src/sidebar.d.ts index 75d7957ff8..b2c97c4eb4 100644 --- a/plugins/gatsby-theme-iterative-docs/src/sidebar.d.ts +++ b/plugins/gatsby-theme-iterative-docs/src/sidebar.d.ts @@ -1,4 +1,4 @@ -declare interface INormalizedSidebarItem { +export interface INormalizedSidebarItem { label: string path: string source?: string @@ -10,6 +10,7 @@ declare interface INormalizedSidebarItem { katacoda: string } children?: INormalizedSidebarItem[] + type?: string } declare const sidebar: INormalizedSidebarItem[] diff --git a/src/components/Documentation/Layout/SidebarMenu/index.tsx b/src/components/Documentation/Layout/SidebarMenu/index.tsx index 4209f35aae..39548ac763 100644 --- a/src/components/Documentation/Layout/SidebarMenu/index.tsx +++ b/src/components/Documentation/Layout/SidebarMenu/index.tsx @@ -17,7 +17,9 @@ import { getParentsListFromPath, getPathWithSource } from '../../../../../plugins/gatsby-theme-iterative-docs/sidebar-helpers' -import sidebar from '../../../../../plugins/gatsby-theme-iterative-docs/src/sidebar' +import sidebar, { + INormalizedSidebarItem +} from '../../../../../plugins/gatsby-theme-iterative-docs/src/sidebar' import 'perfect-scrollbar/css/perfect-scrollbar.css' import * as styles from './styles.module.css' @@ -31,26 +33,15 @@ const ICONS: { [key: string]: React.FC<{ className?: string }> } = { } interface ISidebarMenuItemProps { - children?: Array<{ label: string; path: string; source: boolean | string }> - label: string - path: string - source: boolean | string + item: INormalizedSidebarItem onClick: (isLeafItemClicked: boolean) => void activePaths?: Array - type?: string - style?: string - icon?: string } const SidebarMenuItem: React.FC = ({ - children, - label, - path, + item: { children, label, path, style, icon, type }, activePaths, - onClick, - style, - icon, - type + onClick }) => { const [isExpanded, setIsExpanded] = useState( activePaths && includes(activePaths, path) @@ -154,7 +145,7 @@ const SidebarMenuItem: React.FC = ({ key={item.path} activePaths={activePaths} onClick={onClick} - {...item} + item={item} /> ))} @@ -233,7 +224,7 @@ const SidebarMenu: React.FC = ({ currentPath, onClick }) => { includes(activePaths, item.path) ? activePaths : undefined } onClick={onClick} - {...item} + item={item} /> ))}
From 978b27b7b1e398b587d4a547fc7a2ac26599b494 Mon Sep 17 00:00:00 2001 From: rogermparent Date: Wed, 29 Dec 2021 17:33:32 -0500 Subject: [PATCH 7/7] Remove resolve-sidebar since local remark plugins are dvc.org only --- plugins/gatsby-remark-dvc-linker/apiLinker.js | 2 +- plugins/gatsby-remark-dvc-linker/commandLinker.js | 2 +- plugins/gatsby-remark-dvc-linker/liveLinker.js | 2 +- plugins/gatsby-theme-iterative-docs/resolve-sidebar.js | 6 ------ 4 files changed, 3 insertions(+), 9 deletions(-) delete mode 100644 plugins/gatsby-theme-iterative-docs/resolve-sidebar.js diff --git a/plugins/gatsby-remark-dvc-linker/apiLinker.js b/plugins/gatsby-remark-dvc-linker/apiLinker.js index a7d72543ce..831b394159 100644 --- a/plugins/gatsby-remark-dvc-linker/apiLinker.js +++ b/plugins/gatsby-remark-dvc-linker/apiLinker.js @@ -4,7 +4,7 @@ const { createLinkNode } = require('./helpers') const { getItemByPath } = require('../gatsby-theme-iterative-docs/sidebar-helpers') -const sidebar = require('../gatsby-theme-iterative-docs/resolve-sidebar') +const sidebar = require('../../src/gatsby-theme-iterative-docs/sidebar') const DVC_API_REGEXP = /dvc.api([a-z-._]*\(\)$)?/ const METHOD_REGEXP = /^[a-z-._]*\(\)$/ diff --git a/plugins/gatsby-remark-dvc-linker/commandLinker.js b/plugins/gatsby-remark-dvc-linker/commandLinker.js index 95a5acb92f..86490d10b0 100644 --- a/plugins/gatsby-remark-dvc-linker/commandLinker.js +++ b/plugins/gatsby-remark-dvc-linker/commandLinker.js @@ -4,7 +4,7 @@ const { createLinkNode } = require('./helpers') const { getItemByPath } = require('../gatsby-theme-iterative-docs/sidebar-helpers') -const sidebar = require('../gatsby-theme-iterative-docs/resolve-sidebar') +const sidebar = require('../../src/gatsby-theme-iterative-docs/sidebar') const DVC_REGEXP = /dvc\s+[a-z][a-z-.]*/ const COMMAND_REGEXP = /^[a-z][a-z-]*$/ diff --git a/plugins/gatsby-remark-dvc-linker/liveLinker.js b/plugins/gatsby-remark-dvc-linker/liveLinker.js index ade4aabb30..9a8d0fe150 100644 --- a/plugins/gatsby-remark-dvc-linker/liveLinker.js +++ b/plugins/gatsby-remark-dvc-linker/liveLinker.js @@ -4,7 +4,7 @@ const { createLinkNode } = require('./helpers') const { getItemByPath } = require('../gatsby-theme-iterative-docs/sidebar-helpers') -const sidebar = require('../gatsby-theme-iterative-docs/resolve-sidebar') +const sidebar = require('../../src/gatsby-theme-iterative-docs/sidebar') const LIVE_API_REGEXP = /Live.([a-z-._]*\(\)$)?/ const METHOD_REGEXP = /^[a-z-._]*\(\)$/ diff --git a/plugins/gatsby-theme-iterative-docs/resolve-sidebar.js b/plugins/gatsby-theme-iterative-docs/resolve-sidebar.js deleted file mode 100644 index 48071b5fd6..0000000000 --- a/plugins/gatsby-theme-iterative-docs/resolve-sidebar.js +++ /dev/null @@ -1,6 +0,0 @@ -const path = require('path') -module.exports = require(path.resolve( - 'src', - 'gatsby-theme-iterative-docs', - 'sidebar' -))