-
Notifications
You must be signed in to change notification settings - Fork 631
/
Copy pathdocument.rb
149 lines (109 loc) · 3.27 KB
/
document.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# frozen_string_literal: true
class Linter
class Document
attr_accessor :filename, :yaml, :content
attr_accessor :lang, :author, :translator, :date
def initialize(filename)
@filename = filename
@yaml, @content = read_yaml_and_content(filename)
@lang = yaml["lang"]
@author = yaml["author"]
@translator = yaml["translator"]
@date = yaml["date"]
end
# identifier displayed in error messages
def name
filename
end
def post?
filename.match? %r{/_posts/}
end
def release_post?
post? && filename.match?(%r{released\.md})
end
# posts from before the migration to the Jekyll site
# (they follow different rules; e.g. they have no YAML date variable,
# filenames of translations differ from original `en' post, ...)
def old_post?
post? && Time.utc(*filename_date_string.split("/")) < Time.utc(2013, 4, 1)
end
def lang_invalid?
lang.nil? || !valid_string(lang)
end
def lang_not_matching_filename?
!lang_invalid? && !filename.start_with?("#{lang}/")
end
def author_invalid?
author.nil? || !valid_string(author)
end
# translator variable must be present but can be nil
def translator_missing?
!yaml.key?("translator")
end
def translator_invalid?
return nil if translator.nil?
!valid_string(translator)
end
def date_missing?
date.nil?
end
def date_invalid?
return nil if date_missing?
!date.is_a?(Time)
end
def date_mismatch?
return nil if date_missing? || date_invalid?
date_utc_string != filename_date_string
end
def date_utc_string
date.getutc.strftime("%Y/%m/%d")
end
def filename_date_string
File.basename(filename).split("-", 4)[0..2].join("/")
end
def date_not_utc?
return nil if date_missing? || date_invalid?
date.utc_offset != 0
end
def crlf_line_breaks?
content.match?(/\r\n/)
end
def no_newline_at_eof?
!content.end_with?("\n")
end
def blank_line_at_eof?
content.end_with?("\n\n")
end
def trailing_whitespace?
content.match?(/ $/)
end
def sha1_length_invalid?
matchdata = content.match(/SHA1: *(?<sha>[{0-9a-f]*)/)
return nil unless matchdata
return nil if matchdata[:sha].start_with?("{{") # {{ Liquid output }}
matchdata[:sha].size != 40
end
def sha256_length_invalid?
matchdata = content.match(/SHA256: *(?<sha>[{0-9a-f]*)/)
return nil unless matchdata
return nil if matchdata[:sha].start_with?("{{") # {{ Liquid output }}
matchdata[:sha].size != 64
end
def sha512_length_invalid?
matchdata = content.match(/SHA512: *(?<sha>[{0-9a-f]*)/)
return nil unless matchdata
return nil if matchdata[:sha].start_with?("{{") # {{ Liquid output }}
matchdata[:sha].size != 128
end
private
def read_yaml_and_content(filename)
content = File.read(filename)
matchdata = content.match(/\A(---\s*\n.*?\n?)^(---\s*$\n?)/m)
yaml = YAML.load(matchdata[1], permitted_classes: [Date, Time]) if matchdata
[yaml || {}, content || ""]
end
def valid_string(obj)
obj.is_a?(String) && !obj.empty?
end
end
end