File Coverage

blib/lib/Code/TidyAll/Plugin/YAMLFrontMatter.pm
Criterion Covered Total %
statement 49 49 100.0
branch 8 8 100.0
condition n/a
subroutine 14 14 100.0
pod 1 1 100.0
total 72 72 100.0


line stmt bran cond sub pod time code
1             package Code::TidyAll::Plugin::YAMLFrontMatter;
2              
3 1     1   20713 use strict;
  1         3  
  1         24  
4 1     1   5 use warnings;
  1         2  
  1         22  
5 1     1   355 use namespace::autoclean;
  1         7679  
  1         4  
6              
7             our $VERSION = '1.000000';
8              
9 1     1   83 use Moo;
  1         2  
  1         7  
10              
11 1     1   812 use Encode qw( decode encode FB_CROAK );
  1         6911  
  1         66  
12 1     1   7 use Path::Tiny qw( path );
  1         2  
  1         38  
13 1     1   5 use Try::Tiny qw( catch try );
  1         2  
  1         46  
14 1     1   328 use YAML::XS qw( Load );
  1         1842  
  1         416  
15              
16             extends 'Code::TidyAll::Plugin';
17              
18             # This regular expression is based on the regex
19             # \A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?) (with the m flag)
20             # from the Jekyll source code here:
21             # https://github.com/jekyll/jekyll/blob/c7d98cae2652b2df7ebd3c60b4f8c87950760e47/lib/jekyll/document.rb#L13
22             my $YAML_REGEX = qr{
23             \A
24             # the starting ---, and anything up until...
25             (---\s*\n.*?\n?)
26              
27             # ...the first --- or ... on their own line
28             ^ (?:---|\.\.\.) \s* $ \n?
29             }mx;
30              
31             has encoding => (
32             is => 'ro',
33              
34             # By default Jekyll 2.0 and later defaults to utf-8, so this seems
35             # like a sensible default for us
36             default => 'UTF-8',
37             );
38              
39             has required_top_level_keys => (
40             is => 'ro',
41             default => q{},
42             );
43              
44             has _req_keys_hash => ( is => 'lazy' );
45              
46             sub _build__req_keys_hash {
47 5     5   45 my $self = shift;
48             return +{
49              
50             # note use of magical split on space to do automatic trimming
51 5         29 map { $_ => 1 } split q{ }, $self->required_top_level_keys
  4         24  
52             };
53             }
54              
55             sub validate_file {
56 9     9 1 72747 my ( $self, $filename ) = @_;
57              
58 9         33 my $src = path($filename)->slurp_raw;
59              
60             # YAML::XS always expects things to be in UTF-8 bytes
61 9         1208 my $encoding = $self->encoding;
62             try {
63 9     9   395 $src = decode( $encoding, $src, FB_CROAK );
64 8         3014 $src = encode( 'UTF-8', $src, FB_CROAK );
65             }
66             catch {
67 1     1   74 die "File does not match encoding '$encoding': $_";
68 9         66 };
69              
70             # is there a BOM? There's not meant to be a BOM!
71 8 100       445 if ( $src =~ /\A\x{EF}\x{BB}\x{BF}/ ) {
72 1         20 die "Starting document with UTF-8 BOM is not allowed\n";
73             }
74              
75             # match the YAML front matter.
76 7         15 my $yaml;
77 7 100       114 unless ( ($yaml) = $src =~ $YAML_REGEX ) {
78 1         4 die "'$filename' does not start with valid YAML Front Matter\n";
79             }
80              
81             # parse the YAML front matter.
82             my $ds = try {
83 6     6   407 Load($yaml);
84             }
85             catch {
86 1     1   23 die "Problem parsing YAML: $_";
87 6         39 };
88              
89             # check for required keys
90 5         70 my $errors = q{};
91 5         10 for ( sort keys %{ $self->_req_keys_hash } ) {
  5         104  
92 4 100       14 next if $ds->{$_};
93 2         6 $errors .= "Missing required YAML Front Matter key: '$_'\n";
94             }
95 5 100       29 die $errors if $errors;
96              
97 3         15 return;
98             }
99              
100             1;
101              
102             # ABSTRACT: TidyAll plugin for validating YAML Front Matter
103              
104             __END__
105              
106             =pod
107              
108             =encoding UTF-8
109              
110             =head1 NAME
111              
112             Code::TidyAll::Plugin::YAMLFrontMatter - TidyAll plugin for validating YAML Front Matter
113              
114             =head1 VERSION
115              
116             version 1.000000
117              
118             =head1 SYNOPSIS
119              
120             In your .tidyallrc file:
121              
122             [YAMLFrontMatter]
123             select = **/*.md
124             required_top_level_keys = title layout
125              
126             =head1 DESCRIPTION
127              
128             This is a validator plugin for L<Code::TidyAll> that can be used to check
129             that files have valid YAML Front Matter, like Jekyll et al use.
130              
131             It will complain if:
132              
133             =over
134              
135             =item There's no YAML Front Matter
136              
137             =item The YAML Front Matter isn't valid YAML
138              
139             =item There's a UTF-8 BOM at the start of the file
140              
141             =item The file isn't encoded in the configured encoding (UTF-8 by default)
142              
143             =item The YAML Front Matter is missing one or more configured top level keys
144              
145             =back
146              
147             =head2 Options
148              
149             =over
150              
151             =item C<required_top_level_keys>
152              
153             Keys that must be present at the top level of the YAML Front Matter.
154              
155             =item C<encoding>
156              
157             The encoding the file is in. Defaults to UTF-8 (just like Jekyll 2.0 and
158             later.)
159              
160             =back
161              
162             =head1 SEE ALSO
163              
164             L<Jekyll's Front Matter Documentation|https://jekyllrb.com/docs/frontmatter/>
165              
166             =head1 SUPPORT
167              
168             Please report all issues with this code using the GitHub issue tracker at
169             L<https://github.com/maxmind/Code-TidyAll-Plugin-YAMLFrontMatter/issues>.
170              
171             Bugs may be submitted through L<https://github.com/maxmind/Code-Tidyall-Plugin-YAMLFrontMatter/issues>.
172              
173             =head1 AUTHOR
174              
175             Mark Fowler <mfowler@maxmind.com>
176              
177             =head1 COPYRIGHT AND LICENSE
178              
179             This software is copyright (c) 2017 by MaxMind, Inc..
180              
181             This is free software; you can redistribute it and/or modify it under
182             the same terms as the Perl 5 programming language system itself.
183              
184             =cut