2023-05-30 22:02:20 +07:00
import matter from "gray-matter"
2023-07-23 07:27:41 +07:00
import remarkFrontmatter from "remark-frontmatter"
2023-05-30 22:02:20 +07:00
import { QuartzTransformerPlugin } from "../types"
2023-07-23 07:27:41 +07:00
import yaml from "js-yaml"
2023-08-26 00:25:46 +07:00
import toml from "toml"
2023-08-17 12:04:15 +07:00
import { slugTag } from "../../util/path"
2023-12-10 21:19:29 +07:00
import { QuartzPluginData } from "../vfile"
2024-01-28 12:39:16 +07:00
import chalk from "chalk"
2023-05-30 22:02:20 +07:00
export interface Options {
delims : string | string [ ]
2023-08-26 00:25:46 +07:00
language : "yaml" | "toml"
2023-05-30 22:02:20 +07:00
}
const defaultOptions : Options = {
2023-07-23 07:27:41 +07:00
delims : "---" ,
2023-08-26 00:25:46 +07:00
language : "yaml" ,
2024-01-28 12:39:16 +07:00
}
function coerceDate ( fp : string , d : unknown ) : Date | undefined {
if ( d === undefined || d === null ) return undefined
const dt = new Date ( d as string | number )
const invalidDate = isNaN ( dt . getTime ( ) ) || dt . getTime ( ) === 0
if ( invalidDate ) {
console . log (
chalk . yellow (
` \ nWarning: found invalid date " ${ d } " in \` ${ fp } \` . Supported formats: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#date_time_string_format ` ,
) ,
)
return undefined
}
return dt
}
function coalesceAliases ( data : { [ key : string ] : any } , aliases : string [ ] ) {
for ( const alias of aliases ) {
if ( data [ alias ] !== undefined && data [ alias ] !== null ) return data [ alias ]
}
}
function coerceToArray ( input : string | string [ ] ) : string [ ] | undefined {
if ( input === undefined || input === null ) return undefined
// coerce to array
if ( ! Array . isArray ( input ) ) {
input = input
. toString ( )
. split ( "," )
. map ( ( tag : string ) = > tag . trim ( ) )
}
// remove all non-strings
return input
. filter ( ( tag : unknown ) = > typeof tag === "string" || typeof tag === "number" )
. map ( ( tag : string | number ) = > tag . toString ( ) )
2023-05-30 22:02:20 +07:00
}
2023-06-12 13:26:43 +07:00
export const FrontMatter : QuartzTransformerPlugin < Partial < Options > | undefined > = ( userOpts ) = > {
const opts = { . . . defaultOptions , . . . userOpts }
return {
name : "FrontMatter" ,
markdownPlugins() {
return [
2023-08-26 12:52:23 +07:00
[ remarkFrontmatter , [ "yaml" , "toml" ] ] ,
2023-06-12 13:26:43 +07:00
( ) = > {
return ( _ , file ) = > {
2024-01-28 12:39:16 +07:00
const fp = file . data . filePath !
2023-12-19 00:48:40 +07:00
const { data } = matter ( Buffer . from ( file . value ) , {
2023-07-07 08:45:38 +07:00
. . . opts ,
engines : {
2023-07-23 07:27:41 +07:00
yaml : ( s ) = > yaml . load ( s , { schema : yaml.JSON_SCHEMA } ) as object ,
2023-08-26 00:25:46 +07:00
toml : ( s ) = > toml . parse ( s ) as object ,
2023-07-23 07:27:41 +07:00
} ,
2023-07-07 08:45:38 +07:00
} )
2023-06-12 13:26:43 +07:00
2023-12-10 21:19:29 +07:00
if ( data . title ) {
2023-09-26 08:15:55 +07:00
data . title = data . title . toString ( )
2023-12-10 21:19:29 +07:00
} else if ( data . title === null || data . title === undefined ) {
data . title = file . stem ? ? "Untitled"
2023-09-26 08:15:55 +07:00
}
2024-01-28 12:39:16 +07:00
const tags = coerceToArray ( coalesceAliases ( data , [ "tags" , "tag" ] ) )
if ( tags ) data . tags = [ . . . new Set ( tags . map ( ( tag : string ) = > slugTag ( tag ) ) ) ]
const aliases = coerceToArray ( coalesceAliases ( data , [ "aliases" , "alias" ] ) )
if ( aliases ) data . aliases = aliases
const cssclasses = coerceToArray ( coalesceAliases ( data , [ "cssclasses" , "cssclass" ] ) )
if ( cssclasses ) data . cssclasses = cssclasses
const created = coerceDate ( fp , coalesceAliases ( data , [ "created" , "date" ] ) )
2023-07-07 08:32:48 +07:00
2024-01-28 12:39:16 +07:00
if ( created ) data . created = created
const modified = coerceDate (
fp ,
coalesceAliases ( data , [ "modified" , "lastmod" , "updated" , "last-modified" ] ) ,
)
if ( modified ) data . modified = modified
const published = coerceDate ( fp , coalesceAliases ( data , [ "published" , "publishDate" ] ) )
if ( published ) data . published = published
2023-07-10 09:32:24 +07:00
2023-06-12 13:26:43 +07:00
// fill in frontmatter
2023-12-10 21:19:29 +07:00
file . data . frontmatter = data as QuartzPluginData [ "frontmatter" ]
2023-05-30 22:02:20 +07:00
}
2023-07-23 07:27:41 +07:00
} ,
2023-06-12 13:26:43 +07:00
]
} ,
2023-05-30 22:02:20 +07:00
}
}
2023-07-23 07:27:41 +07:00
declare module "vfile" {
2023-05-30 22:02:20 +07:00
interface DataMap {
2024-01-28 12:39:16 +07:00
frontmatter : { [ key : string ] : unknown } & {
2023-05-30 22:02:20 +07:00
title : string
2024-01-28 12:39:16 +07:00
} & Partial < {
tags : string [ ]
aliases : string [ ]
description : string
publish : boolean
draft : boolean
enableToc : string
cssclasses : string [ ]
created : Date
modified : Date
published : Date
} >
2023-05-30 22:02:20 +07:00
}
}