File Coverage

File:lib/CheckSpelling/Yaml.pm
Coverage:65.8%

linestmtbrancondsubtimecode
1#! -*-perl-*-
2
3package CheckSpelling::Yaml;
4
5our $VERSION='0.1.0';
6
1
1
1
110571
2
669
use CheckSpelling::Util;
7
8sub report {
9  my ($file, $start_line, $start_pos, $end, $message, $match, $report_match) = @_;
10  open(my $output, '>>', CheckSpelling::Util::get_file_from_env('output', '/dev/null'));
11  if (1 == $report_match) {
12    print "$match";
13    print $output "$match";
14  } else {
15    print "$file:$start_line:$start_pos ... $end, $message\n";
16    print $output "$file:$start_line:$start_pos ... $end, $message\n";
17  }
18  close $output;
19  exit;
20}
21
22sub get_yaml_value {
23
4
247
  my ($file, $path) = @_;
24
4
6
  my @path_split = split /\./, $path;
25
4
1
  my $level = 0;
26
4
3
  my @prefixes;
27
4
55
  open($yaml, '<', $file) || return '';
28
3
4
  my @result;
29  my $line_result;
30
3
0
  my $mode;
31
3
0
  my $last;
32
3
24
  while (<$yaml>) {
33
358
149
    chomp;
34
358
184
    next if /^\s*#/;
35
357
293
    if (/^(\s*)(\S.*)/) {
36
357
225
      my ($prefix, $remainder) = ($1, $2);
37
357
437
      while ($level && length $prefix < length $prefixes[$level - 1]) {
38
0
0
        delete $prefixes[$level--];
39      }
40
357
207
      if (@result && $level < scalar @path_split) {
41
0
0
        $last = 1;
42
0
0
        last;
43      }
44
357
152
      last if $last;
45
357
393
      if (!$level || length $prefix > length $prefixes[$level - 1]) {
46
357
150
        if ($level == scalar @path_split) {
47
0
0
          push @result, $remainder;
48        } else {
49
357
139
          my $next = $path_split[$level];
50
357
550
          if ($remainder =~ /$next:(.*)$/) {
51
7
7
            $prefixes[$level++] = $prefix;
52
7
9
            if ($level == scalar @path_split) {
53
3
2
              $mode = $1;
54
3
10
              if ($mode =~ /\s*([-+>|]+)\s*$/) {
55
0
0
                $mode = $1;
56              } elsif ($mode =~ /\s*(\S.*?)\s*$/) {
57
3
3
                my $value = $1;
58
3
2
                $value =~ s/^'(.*)'$/$1/;
59
3
1
                $line_result = $value;
60
3
3
                last;
61              }
62            }
63          }
64        }
65      }
66    } elsif (/^\s*$/ && @result) {
67
0
0
      push @result, '';
68    }
69  }
70
3
13
  close $yaml;
71
3
10
  return $line_result unless @result;
72
0
0
  $mode =~ /([-+])/;
73
0
0
  my $newlines = $1;
74
0
0
  $mode =~ /([|>]?)/;
75
0
0
  $mode = $1;
76
0
0
  my $suffix;
77
0
0
  if ($newlines eq '') {
78
0
0
    $suffix = "\n";
79  }
80
0
0
  unless ($newlines eq '+') {
81
0
0
    pop @result while ($result[$#result] eq '');
82  }
83
0
0
  if ($mode eq '') {
84
0
0
    return (join ' ', @result).$suffix;
85  }
86
0
0
  if ($mode eq '|') {
87
0
0
    return (join "\n", @result).$suffix;
88  }
89
0
0
  if ($mode eq '>') {
90
0
0
    my @output;
91    my $tentative;
92
0
0
    while (@result) {
93
0
0
      my $line = shift @result;
94
0
0
      if ($line eq '') {
95
0
0
        push @output, $tentative;
96
0
0
        $tentative = '';
97      } else {
98
0
0
        $tentative .= $line;
99      }
100    }
101
0
0
    push @output, $tentative;
102
0
0
    return (join "\n", @output).$suffix;
103  }
104
0
0
  return (join ' ? ', @result).$suffix;
105}
106
107sub check_yaml_key_value {
108
4
6
  my ($key, $value, $message, $report_match, $file, $content) = @_;
109
4
3
  my ($state, $gh_yaml_mode) = (0, '');
110
4
2
  my @nests;
111
4
3
  my ($start_line, $start_pod, $end);
112
4
7
  my @lines = split /\n/, $content;
113
4
3
  my $line = 0;
114
115
4
3
  for (@lines) {
116
52
21
    ++$line;
117
52
37
    if (/^(\s*)#/) {
118
4
2
      $end += length $_ if ($state == 3);
119
4
3
      next;
120    }
121
48
26
    if ($state == 0) {
122
45
45
      next unless /^(\s*)\S+\s*:/;
123
27
19
      my $spaces = $1;
124
27
7
      my $len = length $spaces;
125
27
36
      while (scalar @nests && $len < $nests[$#nests]) {
126
4
8
        pop @nests;
127      }
128
27
33
      push @nests, $len if (! scalar @nests || $len > $nests[$#nests]);
129
27
225
      if (/^\s*(($key)\s*:\s*([|>](?:[-+]\d*)?|\$\{\{.*|(?:"\s*|)$value))\s*$/) {
130
3
2
        $gh_yaml_mode = $3;
131
3
7
        ($start_line, $start_pos, $end, $match) = ($line, $-[2] + 1, $+[3] + 1, $1);
132
3
29
        report($file, $start_line, $start_pos, $end, $message, $match, $report_match) if ($gh_yaml_mode =~ /$value|\$\{\{/);
133
3
1583
        if ($report_match) {
134
2
3
          $_ =~ /^\s*(.*)/;
135
2
2
          $match = "$_\n";
136        } else {
137
1
1
          $match = "$key: ";
138        }
139
3
2
        $state = 1;
140      }
141    } elsif ($state == 1) {
142
3
5
      if (/^\s*(?:#.*|)$/) {
143
0
0
        $end += length $_;
144
0
0
        continue;
145      }
146
3
5
      /^(\s*)(\S.*?)\s*$/;
147
3
3
      my ($spaces, $v) = ($1, $2);
148
3
2
      $len = length $spaces;
149
3
19
      if (scalar @nests && $len > $nests[$#nests] && $v =~ /$value/) {
150
2
1
        $end += $len + length $v;
151
2
3
        if ($report_match) {
152
1
1
          $match .= $_;
153        } else {
154
1
1
          $match .= $v;
155        }
156
2
2
        report($file, $start_line, $start_pos, $end, $message, $match, $report_match);
157      }
158
3
2911
      pop @nests;
159
3
2
      $state = 0;
160    }
161  }
162}
163
1641;