@@ -8,24 +8,25 @@ import (
88 "github.com/FileFormatInfo/fflint/internal/shared"
99 "github.com/adrg/frontmatter"
1010 "github.com/spf13/cobra"
11- "gopkg.in/yaml.v2 "
11+ "gopkg.in/yaml.v3 "
1212)
1313
1414var (
15- fmStrict bool
16- fmStrictSet map [string ]bool
17- fmSorted bool
18- fmRequired []string
19- fmOptional []string
20- fmForbidden []string
21- fmDelimiters []string
15+ fmSchemaOptions shared.SchemaOptions
16+ fmStrict bool
17+ fmStrictSet map [string ]bool
18+ fmSorted bool
19+ fmRequired []string
20+ fmOptional []string
21+ fmForbidden []string
22+ fmDelimiters []string
2223)
2324var frontmatterCmd = & cobra.Command {
2425 Args : cobra .MinimumNArgs (1 ),
2526 Use : "frontmatter [options] files..." ,
2627 Short : "Validate frontmatter" ,
2728 Long : `Checks that the frontmatter in your files is valid` ,
28- PreRunE : frontmatterPrepare ,
29+ PreRunE : frontmatterInit ,
2930 RunE : shared .MakeFileCommand (frontmatterCheck ),
3031}
3132
@@ -39,8 +40,9 @@ func AddFrontmatterCommand(rootCmd *cobra.Command) {
3940 frontmatterCmd .Flags ().BoolVar (& fmSorted , "sorted" , false , "Keys need to be in alphabetical order" )
4041 frontmatterCmd .Flags ().StringSliceVar (& fmDelimiters , "delimiters" , []string {}, "Custom delimiters (if other than `---`, `+++` and `;;;`)" )
4142
43+ fmSchemaOptions .AddFlags (frontmatterCmd )
44+
4245 //LATER: report
43- //LATER: schema
4446}
4547
4648func frontmatterCheck (f * shared.FileContext ) {
@@ -53,8 +55,6 @@ func frontmatterCheck(f *shared.FileContext) {
5355 return
5456 }
5557
56- yamlData := make (map [interface {}]interface {})
57-
5858 var formats []* frontmatter.Format
5959
6060 if len (fmDelimiters ) > 0 {
@@ -68,7 +68,9 @@ func frontmatterCheck(f *shared.FileContext) {
6868 }
6969 }
7070
71- _ , parseErr := frontmatter .MustParse (bytes .NewReader (data ), & yamlData , formats ... )
71+ yamlRawData := make (map [string ]any )
72+ //LATER: maybe flag to require contents?
73+ _ , parseErr := frontmatter .MustParse (bytes .NewReader (data ), & yamlRawData , formats ... )
7274
7375 f .RecordResult ("frontmatterParse" , parseErr == nil , map [string ]interface {}{
7476 "error" : shared .ErrString (parseErr ),
@@ -77,6 +79,15 @@ func frontmatterCheck(f *shared.FileContext) {
7779 return
7880 }
7981
82+ /*
83+ yamlDataOrArray, stringKeysErr := shared.ToStringKeys(yamlRawData)
84+ f.RecordResult("frontmatterStringKeys", stringKeysErr == nil, map[string]interface{}{
85+ "error": stringKeysErr,
86+ })
87+ */
88+ yamlDataOrArray := convert (yamlRawData )
89+ yamlData := yamlDataOrArray .(map [string ]interface {})
90+
8091 if len (fmRequired ) > 0 {
8192 for _ , key := range fmRequired {
8293 _ , ok := yamlData [key ]
@@ -97,45 +108,28 @@ func frontmatterCheck(f *shared.FileContext) {
97108
98109 if fmStrict {
99110 for key := range yamlData {
100- keyStr , strErr := key .(string )
101- if ! strErr {
102- f .RecordResult ("frontmatterStrictParse" , false , map [string ]interface {}{
103- "err" : "key is not a string" ,
104- "key" : fmt .Sprintf ("%v" , key ),
105- })
106- continue
107- }
108- _ , ok := fmStrictSet [keyStr ]
111+ _ , ok := fmStrictSet [key ]
109112 f .RecordResult ("frontmatterStrict" , ok , map [string ]interface {}{
110- "key" : keyStr ,
113+ "key" : key ,
111114 })
112115 }
113116 }
114117
115118 if fmSorted {
116- sortedData := yaml.MapSlice {}
117-
118- frontmatter .Parse (bytes .NewReader (data ), & sortedData )
119119 previousKey := ""
120- for _ , item := range sortedData {
121- currentKey , strErr := item .Key .(string )
122- if ! strErr {
123- f .RecordResult ("frontmatterSortedParse" , false , map [string ]interface {}{
124- "err" : "key is not a string" ,
125- "key" : fmt .Sprintf ("%v" , item .Key ),
126- })
127- continue
128- }
120+ for currentKey := range yamlData {
129121 f .RecordResult ("frontmatterSorted" , previousKey < currentKey , map [string ]interface {}{
130122 "previous" : previousKey ,
131123 "current" : currentKey ,
132124 })
133125 previousKey = currentKey
134126 }
135127 }
128+
129+ fmSchemaOptions .Validate (f , yamlData )
136130}
137131
138- func frontmatterPrepare (cmd * cobra.Command , args []string ) error {
132+ func frontmatterInit (cmd * cobra.Command , args []string ) error {
139133 if fmStrict {
140134 fmStrictSet = make (map [string ]bool )
141135 for _ , key := range fmRequired {
@@ -150,5 +144,34 @@ func frontmatterPrepare(cmd *cobra.Command, args []string) error {
150144 fmt .Fprintf (os .Stderr , "ERROR: delimiter count must be <=2 (passed %d)" , len (fmDelimiters ))
151145 os .Exit (7 )
152146 }
147+
148+ schemaPrepErr := fmSchemaOptions .Prepare ()
149+ if schemaPrepErr != nil {
150+ return schemaPrepErr
151+ }
152+
153153 return nil
154154}
155+
156+ // from https://stackoverflow.com/a/40737676
157+ func convert (i interface {}) interface {} {
158+ switch x := i .(type ) {
159+ case map [interface {}]interface {}:
160+ m2 := map [string ]interface {}{}
161+ for k , v := range x {
162+ m2 [k .(string )] = convert (v )
163+ }
164+ return m2
165+ case map [string ]interface {}:
166+ m2 := map [string ]interface {}{}
167+ for k , v := range x {
168+ m2 [k ] = convert (v )
169+ }
170+ return m2
171+ case []interface {}:
172+ for i , v := range x {
173+ x [i ] = convert (v )
174+ }
175+ }
176+ return i
177+ }
0 commit comments