2023-05-30 08:02:20 -07:00
import matter from "gray-matter"
2023-07-22 17:27:41 -07:00
import remarkFrontmatter from "remark-frontmatter"
2023-05-30 08:02:20 -07:00
import { QuartzTransformerPlugin } from "../types"
2023-07-22 17:27:41 -07:00
import yaml from "js-yaml"
2023-08-25 22:55:46 +05:30
import toml from "toml"
2023-08-16 22:04:15 -07:00
import { slugTag } from "../../util/path"
2023-12-10 06:19:29 -08:00
import { QuartzPluginData } from "../vfile"
2024-01-27 21:39:16 -08:00
import chalk from "chalk"
2023-05-30 08:02:20 -07:00
export interface Options {
delims : string | string [ ]
2023-08-25 22:55:46 +05:30
language : "yaml" | "toml"
2023-05-30 08:02:20 -07:00
}
const defaultOptions : Options = {
2023-07-22 17:27:41 -07:00
delims : "---" ,
2023-08-25 22:55:46 +05:30
language : "yaml" ,
2024-01-27 21:39:16 -08: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 08:02:20 -07:00
}
2023-06-11 23:26:43 -07:00
export const FrontMatter : QuartzTransformerPlugin < Partial < Options > | undefined > = ( userOpts ) = > {
const opts = { . . . defaultOptions , . . . userOpts }
return {
name : "FrontMatter" ,
markdownPlugins() {
return [
2023-08-26 11:22:23 +05:30
[ remarkFrontmatter , [ "yaml" , "toml" ] ] ,
2023-06-11 23:26:43 -07:00
( ) = > {
return ( _ , file ) = > {
2024-01-27 21:39:16 -08:00
const fp = file . data . filePath !
2023-12-18 09:48:40 -08:00
const { data } = matter ( Buffer . from ( file . value ) , {
2023-07-06 18:45:38 -07:00
. . . opts ,
engines : {
2023-07-22 17:27:41 -07:00
yaml : ( s ) = > yaml . load ( s , { schema : yaml.JSON_SCHEMA } ) as object ,
2023-08-25 22:55:46 +05:30
toml : ( s ) = > toml . parse ( s ) as object ,
2023-07-22 17:27:41 -07:00
} ,
2023-07-06 18:45:38 -07:00
} )
2023-06-11 23:26:43 -07:00
2023-12-10 06:19:29 -08:00
if ( data . title ) {
2023-09-25 18:15:55 -07:00
data . title = data . title . toString ( )
2023-12-10 06:19:29 -08:00
} else if ( data . title === null || data . title === undefined ) {
data . title = file . stem ? ? "Untitled"
2023-09-25 18:15:55 -07:00
}
2024-01-27 21:39:16 -08: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-06 18:32:48 -07:00
2024-01-27 21:39:16 -08: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-09 19:32:24 -07:00
2023-06-11 23:26:43 -07:00
// fill in frontmatter
2023-12-10 06:19:29 -08:00
file . data . frontmatter = data as QuartzPluginData [ "frontmatter" ]
2023-05-30 08:02:20 -07:00
}
2023-07-22 17:27:41 -07:00
} ,
2023-06-11 23:26:43 -07:00
]
} ,
2023-05-30 08:02:20 -07:00
}
}
2023-07-22 17:27:41 -07:00
declare module "vfile" {
2023-05-30 08:02:20 -07:00
interface DataMap {
2024-01-27 21:39:16 -08:00
frontmatter : { [ key : string ] : unknown } & {
2023-05-30 08:02:20 -07:00
title : string
2024-01-27 21:39:16 -08: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 08:02:20 -07:00
}
}