@@ -4,12 +4,13 @@ use serde::{Deserialize, Serialize};
44/// The front matter of a markdown blog post.
55#[ derive( Debug , PartialEq , Serialize , Deserialize ) ]
66pub struct FrontMatter {
7+ pub layout : String ,
78 pub title : String ,
89 pub author : String ,
9- #[ serde( default ) ]
10- pub release : bool ,
10+ pub description : Option < String > ,
1111 pub team : Option < String > ,
12- pub layout : String ,
12+ #[ serde( default , skip_serializing_if = "std::ops::Not::not" ) ]
13+ pub release : bool ,
1314}
1415
1516/// Extracts the front matter from a markdown file.
@@ -27,3 +28,78 @@ pub fn parse(markdown: &str) -> eyre::Result<(FrontMatter, &str)> {
2728
2829 Ok ( ( toml:: from_str ( front_matter) ?, content) )
2930}
31+
32+ /// Normalizes the front matter of a markdown file.
33+ pub fn normalize ( markdown : & str ) -> eyre:: Result < String > {
34+ let ( front_matter, content) = parse ( markdown) ?;
35+
36+ Ok ( format ! (
37+ "\
38+ +++
39+ {}\
40+ +++
41+ {content}" ,
42+ toml:: to_string_pretty( & front_matter) ?
43+ ) )
44+ }
45+
46+ #[ cfg( test) ]
47+ mod tests {
48+ use std:: { env, fs, path:: PathBuf } ;
49+
50+ use super :: * ;
51+
52+ #[ test]
53+ fn front_matter_is_normalized ( ) {
54+ let repo_root = PathBuf :: from ( env ! ( "CARGO_MANIFEST_DIR" ) ) . join ( ".." ) ;
55+
56+ let posts = fs:: read_dir ( repo_root. join ( "posts" ) )
57+ . unwrap ( )
58+ . chain ( fs:: read_dir ( repo_root. join ( "posts/inside-rust" ) ) . unwrap ( ) )
59+ . map ( |p| p. unwrap ( ) . path ( ) )
60+ . filter ( |p| p. extension ( ) == Some ( "md" . as_ref ( ) ) ) ;
61+
62+ for post in posts {
63+ let content = fs:: read_to_string ( & post) . unwrap ( ) ;
64+ let normalized = normalize ( & content) . unwrap ( ) ;
65+
66+ if content != normalized {
67+ if env:: var ( "FIX_FRONT_MATTER" ) . is_ok ( ) {
68+ fs:: write ( post, normalized) . unwrap ( ) ;
69+ continue ;
70+ }
71+
72+ let post = post. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) ;
73+ let actual = content
74+ . rsplit_once ( "+++" )
75+ . map ( |( f, _) | format ! ( "{f}+++" ) )
76+ . unwrap_or ( content) ;
77+ let expected = normalized
78+ . rsplit_once ( "+++" )
79+ . map ( |( f, _) | format ! ( "{f}+++" ) )
80+ . unwrap_or ( normalized) ;
81+
82+ // better error message than assert_eq!()
83+ panic ! (
84+ "
85+ The post {post} has abnormal front matter.
86+
87+ actual:
88+ {actual}
89+
90+ expected:
91+ {expected}
92+
93+ ┌──────────────────────────────────────────────────────────────────────────┐
94+ │ │
95+ │ You can fix this automatically by running: │
96+ │ │
97+ │ FIX_FRONT_MATTER=1 cargo test --all front_matter_is_normalized │
98+ │ │
99+ └──────────────────────────────────────────────────────────────────────────┘
100+ " ,
101+ )
102+ } ;
103+ }
104+ }
105+ }
0 commit comments