From 2bc2f1a8d5c3680d914f17a752527a367040860f Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Fri, 14 Oct 2022 17:08:11 +0200 Subject: [PATCH 1/5] sort `defaultMeta` by `frontMatter.date`, if missing by `frontMatter.title` and after by page name --- .changeset/tender-papayas-walk.md | 5 ++ packages/nextra/__test__/sort-pages.test.ts | 73 +++++++++++++++++++++ packages/nextra/src/plugin.ts | 12 ++-- packages/nextra/src/utils.ts | 29 +++++++- 4 files changed, 111 insertions(+), 8 deletions(-) create mode 100644 .changeset/tender-papayas-walk.md create mode 100644 packages/nextra/__test__/sort-pages.test.ts diff --git a/.changeset/tender-papayas-walk.md b/.changeset/tender-papayas-walk.md new file mode 100644 index 0000000000..eb7361bbaf --- /dev/null +++ b/.changeset/tender-papayas-walk.md @@ -0,0 +1,5 @@ +--- +'nextra': patch +--- + +sort `defaultMeta` by `frontMatter.date`, if missing by `frontMatter.title` and after by page name diff --git a/packages/nextra/__test__/sort-pages.test.ts b/packages/nextra/__test__/sort-pages.test.ts new file mode 100644 index 0000000000..da087455e2 --- /dev/null +++ b/packages/nextra/__test__/sort-pages.test.ts @@ -0,0 +1,73 @@ +import { describe, expect, it } from 'vitest' +import { sortPages } from '../src/utils' +import { MdxFile } from '../src/types' + +function enhanceDefaultData( + data: Pick +): MdxFile { + return { + kind: 'MdxPage', + route: '', + ...data + } +} + +describe('sortPages()', () => { + it('should should sort by date', () => { + const data = sortPages( + [ + { name: 'baz', frontMatter: { date: new Date('1995-10-21') } }, + { name: 'foo', frontMatter: { date: new Date('1992-10-21') } }, + { name: 'quz', frontMatter: { date: new Date('1998-10-21') } } + ].map(enhanceDefaultData) + ) + expect(data).toEqual([ + ['quz', 'Quz'], + ['baz', 'Baz'], + ['foo', 'Foo'] + ]) + }) + + it('should should sort by date first and after by title', () => { + const data = sortPages( + [ + { name: 'quz' }, + { name: 'foo', frontMatter: { date: new Date('1992-10-21') } }, + { name: 'baz' } + ].map(enhanceDefaultData) + ) + expect(data).toEqual([ + ['foo', 'Foo'], + ['baz', 'Baz'], + ['quz', 'Quz'] + ]) + }) + + it('should take priority `frontMatter.title` over name', () => { + const data = sortPages( + [ + { name: 'baz' }, + { name: 'foo', frontMatter: { title: 'abc' } }, + { name: 'quz' } + ].map(enhanceDefaultData) + ) + expect(data).toEqual([ + ['foo', 'abc'], + ['baz', 'Baz'], + ['quz', 'Quz'] + ]) + }) + + it('should sort numeric', () => { + const data = sortPages( + [{ name: '10-baz' }, { name: '0-foo' }, { name: '2.5-quz' }].map( + enhanceDefaultData + ) + ) + expect(data).toEqual([ + ['0-foo', '0 Foo'], + ['2.5-quz', '2.5 Quz'], + ['10-baz', '10 Baz'] + ]) + }) +}) diff --git a/packages/nextra/src/plugin.ts b/packages/nextra/src/plugin.ts index 655c7a47df..badd9f330d 100644 --- a/packages/nextra/src/plugin.ts +++ b/packages/nextra/src/plugin.ts @@ -10,7 +10,7 @@ import { } from './types' import fs from 'graceful-fs' import { promisify } from 'node:util' -import { parseFileName, parseJsonFile, truthy } from './utils' +import { parseFileName, parseJsonFile, sortPages, truthy } from './utils' import path from 'node:path' import slash from 'slash' import grayMatter from 'gray-matter' @@ -106,15 +106,13 @@ export async function collectFiles( const metaIndex = items.findIndex( item => item.kind === 'Meta' && item.locale === locale ) - const defaultMeta: [string, string][] = mdxPages - .filter(item => item.locale === locale) - .map(item => [ - item.name, - item.frontMatter?.title || title(item.name.replace(/[-_]/g, ' ')) - ]) + + const defaultMeta = sortPages(mdxPages, locale) + const metaFilename = locale ? META_FILENAME.replace('.', `.${locale}.`) : META_FILENAME + const metaPath = path.join(dir, metaFilename) as MetaJsonPath if (metaIndex === -1) { diff --git a/packages/nextra/src/utils.ts b/packages/nextra/src/utils.ts index 097995a35f..9a1cce2850 100644 --- a/packages/nextra/src/utils.ts +++ b/packages/nextra/src/utils.ts @@ -1,6 +1,7 @@ import path from 'node:path' +import title from 'title' import { LOCALE_REGEX } from './constants' -import { Meta } from './types' +import { MdxFile, Meta } from './types' export function parseFileName(filePath: string): { name: string @@ -41,3 +42,29 @@ export function truthy(value: T): value is Truthy { export function normalizeMeta(meta: Meta): Exclude { return typeof meta === 'string' ? { title: meta } : meta } + +export function sortPages( + pages: MdxFile[], + locale?: string +): [string, string][] { + return pages + .filter(item => item.locale === locale) + .map(item => ({ + name: item.name, + date: item.frontMatter?.date, + title: item.frontMatter?.title || title(item.name.replace(/[-_]/g, ' ')) + })) + .sort((a, b) => { + if (a.date && b.date) { + return new Date(b.date).getTime() - new Date(a.date).getTime() + } + if (a.date) { + return -1 // sort a before b + } + if (b.date) { + return 1 // sort a after b + } + return a.title.localeCompare(b.title, locale, { numeric: true }) + }) + .map(item => [item.name, item.title]) +} From ed1fa92572b80db0469e8aaf87b5c56adc4edb70 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Fri, 14 Oct 2022 17:20:10 +0200 Subject: [PATCH 2/5] refactor to have less code --- packages/nextra/__test__/sort-pages.test.ts | 57 ++++++++------------- packages/nextra/src/utils.ts | 2 +- 2 files changed, 21 insertions(+), 38 deletions(-) diff --git a/packages/nextra/__test__/sort-pages.test.ts b/packages/nextra/__test__/sort-pages.test.ts index da087455e2..062ad39267 100644 --- a/packages/nextra/__test__/sort-pages.test.ts +++ b/packages/nextra/__test__/sort-pages.test.ts @@ -1,26 +1,13 @@ import { describe, expect, it } from 'vitest' import { sortPages } from '../src/utils' -import { MdxFile } from '../src/types' - -function enhanceDefaultData( - data: Pick -): MdxFile { - return { - kind: 'MdxPage', - route: '', - ...data - } -} describe('sortPages()', () => { it('should should sort by date', () => { - const data = sortPages( - [ - { name: 'baz', frontMatter: { date: new Date('1995-10-21') } }, - { name: 'foo', frontMatter: { date: new Date('1992-10-21') } }, - { name: 'quz', frontMatter: { date: new Date('1998-10-21') } } - ].map(enhanceDefaultData) - ) + const data = sortPages([ + { name: 'baz', frontMatter: { date: new Date('1995-10-21') } }, + { name: 'foo', frontMatter: { date: new Date('1992-10-21') } }, + { name: 'quz', frontMatter: { date: new Date('1998-10-21') } } + ]) expect(data).toEqual([ ['quz', 'Quz'], ['baz', 'Baz'], @@ -29,13 +16,11 @@ describe('sortPages()', () => { }) it('should should sort by date first and after by title', () => { - const data = sortPages( - [ - { name: 'quz' }, - { name: 'foo', frontMatter: { date: new Date('1992-10-21') } }, - { name: 'baz' } - ].map(enhanceDefaultData) - ) + const data = sortPages([ + { name: 'quz' }, + { name: 'foo', frontMatter: { date: new Date('1992-10-21') } }, + { name: 'baz' } + ]) expect(data).toEqual([ ['foo', 'Foo'], ['baz', 'Baz'], @@ -44,13 +29,11 @@ describe('sortPages()', () => { }) it('should take priority `frontMatter.title` over name', () => { - const data = sortPages( - [ - { name: 'baz' }, - { name: 'foo', frontMatter: { title: 'abc' } }, - { name: 'quz' } - ].map(enhanceDefaultData) - ) + const data = sortPages([ + { name: 'baz' }, + { name: 'foo', frontMatter: { title: 'abc' } }, + { name: 'quz' } + ]) expect(data).toEqual([ ['foo', 'abc'], ['baz', 'Baz'], @@ -59,11 +42,11 @@ describe('sortPages()', () => { }) it('should sort numeric', () => { - const data = sortPages( - [{ name: '10-baz' }, { name: '0-foo' }, { name: '2.5-quz' }].map( - enhanceDefaultData - ) - ) + const data = sortPages([ + { name: '10-baz' }, + { name: '0-foo' }, + { name: '2.5-quz' } + ]) expect(data).toEqual([ ['0-foo', '0 Foo'], ['2.5-quz', '2.5 Quz'], diff --git a/packages/nextra/src/utils.ts b/packages/nextra/src/utils.ts index 9a1cce2850..c2ce968ddc 100644 --- a/packages/nextra/src/utils.ts +++ b/packages/nextra/src/utils.ts @@ -44,7 +44,7 @@ export function normalizeMeta(meta: Meta): Exclude { } export function sortPages( - pages: MdxFile[], + pages: Pick[], locale?: string ): [string, string][] { return pages From 232925ee7edd59be559af91a4dceb0a962038f7b Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Fri, 14 Oct 2022 18:13:09 +0200 Subject: [PATCH 3/5] Update .changeset/tender-papayas-walk.md --- .changeset/tender-papayas-walk.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/tender-papayas-walk.md b/.changeset/tender-papayas-walk.md index eb7361bbaf..35934609c7 100644 --- a/.changeset/tender-papayas-walk.md +++ b/.changeset/tender-papayas-walk.md @@ -2,4 +2,4 @@ 'nextra': patch --- -sort `defaultMeta` by `frontMatter.date`, if missing by `frontMatter.title` and after by page name +sort `defaultMeta` by `frontMatter.date`, if missing by `frontMatter.title` and after by capitalized page name From f1bceea83850270aaa62825fbb0f29a5f3f487de Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 15 Oct 2022 03:16:15 +0200 Subject: [PATCH 4/5] Apply suggestions from code review --- packages/nextra/__test__/sort-pages.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nextra/__test__/sort-pages.test.ts b/packages/nextra/__test__/sort-pages.test.ts index 062ad39267..52af2d6e1b 100644 --- a/packages/nextra/__test__/sort-pages.test.ts +++ b/packages/nextra/__test__/sort-pages.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest' import { sortPages } from '../src/utils' describe('sortPages()', () => { - it('should should sort by date', () => { + it('should sort by date', () => { const data = sortPages([ { name: 'baz', frontMatter: { date: new Date('1995-10-21') } }, { name: 'foo', frontMatter: { date: new Date('1992-10-21') } }, @@ -15,7 +15,7 @@ describe('sortPages()', () => { ]) }) - it('should should sort by date first and after by title', () => { + it('should sort by date first and after by title', () => { const data = sortPages([ { name: 'quz' }, { name: 'foo', frontMatter: { date: new Date('1992-10-21') } }, From da5d6f13d93213156d58916662fa44471e277069 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Thu, 20 Oct 2022 01:18:54 +0200 Subject: [PATCH 5/5] capitalize sidebar's folders names if item is missing in `_meta.json` (#895) --- .changeset/wet-trainers-sleep.md | 5 +++ .../__snapshots__/page-map.test.ts.snap | 6 +++ packages/nextra/__test__/sort-pages.test.ts | 39 +++++++++++++------ packages/nextra/src/plugin.ts | 7 +++- packages/nextra/src/utils.ts | 15 ++++--- 5 files changed, 53 insertions(+), 19 deletions(-) create mode 100644 .changeset/wet-trainers-sleep.md diff --git a/.changeset/wet-trainers-sleep.md b/.changeset/wet-trainers-sleep.md new file mode 100644 index 0000000000..acd4564941 --- /dev/null +++ b/.changeset/wet-trainers-sleep.md @@ -0,0 +1,5 @@ +--- +'nextra': patch +--- + +capitalize sidebar's folders names if item is missing in `_meta.json` diff --git a/packages/nextra/__test__/__snapshots__/page-map.test.ts.snap b/packages/nextra/__test__/__snapshots__/page-map.test.ts.snap index 6f2b448cdc..b020554959 100644 --- a/packages/nextra/__test__/__snapshots__/page-map.test.ts.snap +++ b/packages/nextra/__test__/__snapshots__/page-map.test.ts.snap @@ -550,6 +550,10 @@ exports[`Page Process > pageMap en-US 1`] = ` "data": { "404": "404", "500": "500", + "about": "About", + "blog": "Blog", + "docs": "Docs", + "examples": "Examples", }, "kind": "Meta", }, @@ -564,6 +568,7 @@ exports[`Page Process > pageMap zh-CN 1`] = ` [ { "data": { + "about": "About", "blog": { "title": "博客", "type": "page", @@ -683,6 +688,7 @@ exports[`Page Process > pageMap zh-CN 1`] = ` "data": { "cache": "缓存", "file-name.with.DOTS": "带点的文件名", + "more": "More", "performance": "性能", "react-native": "React Native", }, diff --git a/packages/nextra/__test__/sort-pages.test.ts b/packages/nextra/__test__/sort-pages.test.ts index 52af2d6e1b..19a9d4714c 100644 --- a/packages/nextra/__test__/sort-pages.test.ts +++ b/packages/nextra/__test__/sort-pages.test.ts @@ -1,12 +1,14 @@ import { describe, expect, it } from 'vitest' import { sortPages } from '../src/utils' +const kind = 'MdxPage' + describe('sortPages()', () => { it('should sort by date', () => { const data = sortPages([ - { name: 'baz', frontMatter: { date: new Date('1995-10-21') } }, - { name: 'foo', frontMatter: { date: new Date('1992-10-21') } }, - { name: 'quz', frontMatter: { date: new Date('1998-10-21') } } + { kind, name: 'baz', frontMatter: { date: new Date('1995-10-21') } }, + { kind, name: 'foo', frontMatter: { date: new Date('1992-10-21') } }, + { kind, name: 'quz', frontMatter: { date: new Date('1998-10-21') } } ]) expect(data).toEqual([ ['quz', 'Quz'], @@ -17,9 +19,9 @@ describe('sortPages()', () => { it('should sort by date first and after by title', () => { const data = sortPages([ - { name: 'quz' }, - { name: 'foo', frontMatter: { date: new Date('1992-10-21') } }, - { name: 'baz' } + { kind, name: 'quz' }, + { kind, name: 'foo', frontMatter: { date: new Date('1992-10-21') } }, + { kind, name: 'baz' } ]) expect(data).toEqual([ ['foo', 'Foo'], @@ -30,9 +32,9 @@ describe('sortPages()', () => { it('should take priority `frontMatter.title` over name', () => { const data = sortPages([ - { name: 'baz' }, - { name: 'foo', frontMatter: { title: 'abc' } }, - { name: 'quz' } + { kind, name: 'baz' }, + { kind, name: 'foo', frontMatter: { title: 'abc' } }, + { kind, name: 'quz' } ]) expect(data).toEqual([ ['foo', 'abc'], @@ -43,9 +45,9 @@ describe('sortPages()', () => { it('should sort numeric', () => { const data = sortPages([ - { name: '10-baz' }, - { name: '0-foo' }, - { name: '2.5-quz' } + { kind, name: '10-baz' }, + { kind, name: '0-foo' }, + { kind, name: '2.5-quz' } ]) expect(data).toEqual([ ['0-foo', '0 Foo'], @@ -53,4 +55,17 @@ describe('sortPages()', () => { ['10-baz', '10 Baz'] ]) }) + + it('should capitalize `Folder`', () => { + const data = sortPages([ + { kind, name: 'quz' }, + { kind: 'Folder', name: 'foo' }, + { kind, name: 'baz' } + ]) + expect(data).toEqual([ + ['baz', 'Baz'], + ['foo', 'Foo'], + ['quz', 'Quz'] + ]) + }) }) diff --git a/packages/nextra/src/plugin.ts b/packages/nextra/src/plugin.ts index badd9f330d..a7a114e972 100644 --- a/packages/nextra/src/plugin.ts +++ b/packages/nextra/src/plugin.ts @@ -98,9 +98,12 @@ export async function collectFiles( const items = (await Promise.all(promises)).filter(truthy) const mdxPages = items.filter( - (item): item is MdxFile => item.kind === 'MdxPage' + (item): item is MdxFile | Folder => + item.kind === 'MdxPage' || item.kind === 'Folder' ) - const locales = mdxPages.map(item => item.locale) + const locales = mdxPages + .filter((item): item is MdxFile => item.kind === 'MdxPage') + .map(item => item.locale) for (const locale of locales) { const metaIndex = items.findIndex( diff --git a/packages/nextra/src/utils.ts b/packages/nextra/src/utils.ts index c2ce968ddc..5a907af300 100644 --- a/packages/nextra/src/utils.ts +++ b/packages/nextra/src/utils.ts @@ -1,7 +1,7 @@ import path from 'node:path' import title from 'title' import { LOCALE_REGEX } from './constants' -import { MdxFile, Meta } from './types' +import { Folder, MdxFile, Meta } from './types' export function parseFileName(filePath: string): { name: string @@ -44,15 +44,20 @@ export function normalizeMeta(meta: Meta): Exclude { } export function sortPages( - pages: Pick[], + pages: ( + | Pick + | Pick + )[], locale?: string ): [string, string][] { return pages - .filter(item => item.locale === locale) + .filter(item => item.kind === 'Folder' || item.locale === locale) .map(item => ({ name: item.name, - date: item.frontMatter?.date, - title: item.frontMatter?.title || title(item.name.replace(/[-_]/g, ' ')) + date: 'frontMatter' in item && item.frontMatter?.date, + title: + ('frontMatter' in item && item.frontMatter?.title) || + title(item.name.replace(/[-_]/g, ' ')) })) .sort((a, b) => { if (a.date && b.date) {