Skip to content

Commit

Permalink
feat(path-meta): store source, path and extension in meta (#70)
Browse files Browse the repository at this point in the history
  • Loading branch information
farnabaz authored Mar 15, 2022
1 parent 7530c2c commit ae9a771
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 106 deletions.
3 changes: 1 addition & 2 deletions src/runtime/query/match/pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@ export function createPipelineFetcher<T> (getContentsList: () => Promise<Array<T
// Provide default sort order if not specified
if (!params.sortBy || !params.sortBy.length) {
params.sortBy = [
['slug', 'asc'],
['position', 'asc']
['path', 'asc']
]
}

Expand Down
23 changes: 12 additions & 11 deletions src/runtime/server/navigation.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { NavItem, ParsedContentMeta } from '../types'
import { generatePosition, generateTitle } from './transformer/plugin-path-meta'
import { generateTitle } from './transformer/plugin-path-meta'

type PrivateNavItem = NavItem & { path?: string }
/**
* Create NavItem array to be consumed from runtime plugin.
*/
Expand All @@ -19,12 +20,12 @@ export function createNav (contents: ParsedContentMeta[]) {
slug: content.slug,
draft: content.draft,
partial: content.partial,
position: content.position,
path: content.path,
children: []
}
}

const navItem: NavItem = getNavItem(content)
const navItem: PrivateNavItem = getNavItem(content)

// Push index
if (isIndex) {
Expand Down Expand Up @@ -54,14 +55,14 @@ export function createNav (contents: ParsedContentMeta[]) {
const currentPathSlug = '/' + parts.slice(0, i + 1).join('/')

// Find parent node
let parent = nodes.find(n => n.slug === currentPathSlug)
let parent: PrivateNavItem = nodes.find(n => n.slug === currentPathSlug)

// Create dummy parent if not found
if (!parent) {
parent = {
slug: currentPathSlug,
title: generateTitle(part),
position: generatePosition(idParts.slice(0, i + 1).join(':')),
path: idParts.slice(0, i + 1).join(':'),
children: []
}
nodes.push(parent)
Expand All @@ -72,16 +73,16 @@ export function createNav (contents: ParsedContentMeta[]) {
siblings.push(navItem)

return nav
}, [] as NavItem[])
}, [] as PrivateNavItem[])

return sortAndClear(nav)
}

/**
* Sort items by position and clear empty children keys.
* Sort items by path and clear empty children keys.
*/
function sortAndClear (nav: NavItem[]) {
const sorted = nav.sort((a, b) => a.position.localeCompare(b.position))
function sortAndClear (nav: PrivateNavItem[]) {
const sorted = nav.sort((a, b) => a.path.localeCompare(b.path))

for (const item of sorted) {
if (item.children.length) {
Expand All @@ -91,8 +92,8 @@ function sortAndClear (nav: NavItem[]) {
// Remove empty children
delete item.children
}
// Remove position after sort
delete item.position
// Remove path after sort
delete item.path
}

return nav
Expand Down
41 changes: 17 additions & 24 deletions src/runtime/server/transformer/plugin-path-meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,38 @@ import { privateConfig } from '#config'

const SEMVER_REGEX = /^(\d+)(\.\d+)*(\.x)?$/

const withoutExtension = (path: string) => path.replace(/\.[^.]+$/, '')
const describeId = (id: string) => {
const [source, ...parts] = id.split(':')

const [, filename, extension] = parts[parts.length - 1].match(/(.*)\.([^.]+)$/)
parts[parts.length - 1] = filename

return {
source,
path: parts.join('/'),
extension
}
}

export default defineContentPlugin({
name: 'path-meta',
extentions: ['.*'],
transform (content) {
const { locales, defaultLocale } = privateConfig.content || {}
const parts = withoutExtension(content.meta.id)
.split(/[/:]/)
// First part always represents the mount-point/source
.slice(1)
const { source, path, extension } = describeId(content.meta.id)
const parts = path.split('/')

// Check first part for locale name
const locale = locales.includes(parts[0]) ? parts.shift() : defaultLocale

const filePath = parts.join('/')

Object.assign(content.meta, {
source,
path,
extension,
title: content.meta.title || generateTitle(refineUrlPart(parts[parts.length - 1])),
slug: generateSlug(filePath),
position: generatePosition(filePath),
draft: isDraft(filePath),
partial: isPartial(filePath),
locale: locale || content.meta?.locale
Expand Down Expand Up @@ -88,21 +99,3 @@ export function refineUrlPart (name: string): string {
.replace(/\.draft/, '')
)
}

/**
* Generate position from file path
*/
export function generatePosition (path: string): string {
const position = path
.split(/[/:]/)
.filter(Boolean)
.map((part) => {
const match = part.match(/^[_.-]?(\d+)\./)
if (match && !SEMVER_REGEX.test(part)) {
return String(match[1]).padStart(4, '0')
}
return '9999' // Parts without a position are going down to the bottom
})
.join('')
return String(position).padEnd(12, '0').substring(0, 12)
}
13 changes: 8 additions & 5 deletions src/runtime/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ export interface ParsedContentMeta {
* Content id
*/
id: string
/**
* Content source
*/
source: string
/**
* Content path, this path is source agnostic and it the content my live in any source
*/
path: string
/**
* Content slug
*/
Expand All @@ -13,10 +21,6 @@ export interface ParsedContentMeta {
* Content title
*/
title?: string
/**
* Content position generated from file path
*/
position?: string
/**
* Content draft status
*/
Expand Down Expand Up @@ -187,7 +191,6 @@ export interface QueryPlugin {
// Navigation
export interface NavItem {
title: string
position: string
slug: string
id?: string
draft?: boolean
Expand Down
64 changes: 32 additions & 32 deletions test/__snapshots__/basic.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -91,29 +91,29 @@ exports[`fixtures:basic > Get navigation > basic-navigation 1`] = `
"children": [
{
"draft": false,
"id": "fa-ir:fa:index.md",
"id": "content:cats:index.md",
"partial": false,
"slug": "/",
"title": "سلام",
"slug": "/cats",
"title": "Cats list",
},
],
"id": "fa-ir:fa:index.md",
"slug": "/",
"title": "سلام",
},
{
"children": [
{
"draft": false,
"id": "content:index.md",
"id": "content:cats:persian.md",
"partial": false,
"slug": "/",
"title": "Index",
"slug": "/cats/persian",
"title": "Persian",
},
{
"draft": false,
"id": "content:cats:ragdoll.md",
"partial": false,
"slug": "/cats/ragdoll",
"title": "Ragdoll",
},
],
"id": "content:index.md",
"slug": "/",
"title": "Index",
"id": "content:cats:index.md",
"slug": "/cats",
"title": "Cats list",
},
{
"children": [
Expand All @@ -139,29 +139,29 @@ exports[`fixtures:basic > Get navigation > basic-navigation 1`] = `
"children": [
{
"draft": false,
"id": "content:cats:index.md",
"partial": false,
"slug": "/cats",
"title": "Cats list",
},
{
"draft": false,
"id": "content:cats:persian.md",
"id": "fa-ir:fa:index.md",
"partial": false,
"slug": "/cats/persian",
"title": "Persian",
"slug": "/",
"title": "سلام",
},
],
"id": "fa-ir:fa:index.md",
"slug": "/",
"title": "سلام",
},
{
"children": [
{
"draft": false,
"id": "content:cats:ragdoll.md",
"id": "content:index.md",
"partial": false,
"slug": "/cats/ragdoll",
"title": "Ragdoll",
"slug": "/",
"title": "Index",
},
],
"id": "content:cats:index.md",
"slug": "/cats",
"title": "Cats list",
"id": "content:index.md",
"slug": "/",
"title": "Index",
},
]
`;
Loading

0 comments on commit ae9a771

Please sign in to comment.