fdlint 0.1.3 → 0.2.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +2 -9
- data/Gemfile.lock +14 -4
- data/Rakefile +9 -85
- data/bin/fdlint +71 -8
- data/lib/fdlint/cli.rb +102 -0
- data/lib/{file_validator.rb → fdlint/file_validator.rb} +0 -0
- data/lib/fdlint/helper/code_type.rb +55 -0
- data/lib/fdlint/helper/file_reader.rb +19 -0
- data/lib/fdlint/helper/logger.rb +35 -0
- data/lib/fdlint/log_entry.rb +51 -0
- data/lib/fdlint/parser/base_parser.rb +151 -0
- data/lib/{css/parser.rb → fdlint/parser/css/css_parser.rb} +31 -28
- data/lib/{css → fdlint/parser/css}/struct.rb +5 -5
- data/lib/{encoding_error.rb → fdlint/parser/encoding_error.rb} +2 -2
- data/lib/{html/parser.rb → fdlint/parser/html/html_parser.rb} +26 -20
- data/lib/{html → fdlint/parser/html}/query.rb +0 -0
- data/lib/{html → fdlint/parser/html}/rule/check_tag_rule.rb +0 -0
- data/lib/{html → fdlint/parser/html}/struct.rb +82 -38
- data/lib/fdlint/parser/js/expr/expr.rb +71 -0
- data/lib/fdlint/parser/js/expr/left_hand.rb +65 -0
- data/lib/fdlint/parser/js/expr/operate.rb +94 -0
- data/lib/fdlint/parser/js/expr/primary.rb +168 -0
- data/lib/{js/parser.rb → fdlint/parser/js/js_parser.rb} +11 -9
- data/lib/fdlint/parser/js/stat/if.rb +27 -0
- data/lib/fdlint/parser/js/stat/iter.rb +88 -0
- data/lib/fdlint/parser/js/stat/stat.rb +120 -0
- data/lib/fdlint/parser/js/stat/switch.rb +67 -0
- data/lib/fdlint/parser/js/stat/try.rb +30 -0
- data/lib/fdlint/parser/js/stat/var.rb +42 -0
- data/lib/fdlint/parser/js/struct.rb +257 -0
- data/lib/fdlint/parser/node.rb +27 -0
- data/lib/fdlint/parser/parse_error.rb +10 -0
- data/lib/fdlint/parser/parser_visitable.rb +134 -0
- data/lib/{position_info.rb → fdlint/parser/position_info.rb} +12 -1
- data/lib/fdlint/parser.rb +3 -0
- data/lib/fdlint/printer/base_printer.rb +20 -0
- data/lib/fdlint/printer/console_printer.rb +80 -0
- data/lib/fdlint/printer/nocolor_printer.rb +29 -0
- data/lib/fdlint/printer/vim_printer.rb +21 -0
- data/lib/fdlint/printer.rb +1 -0
- data/lib/fdlint/rule/dsl.rb +83 -0
- data/lib/fdlint/rule/validation.rb +79 -0
- data/lib/fdlint/rule.rb +81 -0
- data/lib/fdlint/support/core/array.rb +5 -0
- data/lib/fdlint/support/core/file.rb +8 -0
- data/lib/fdlint/support/core/hash.rb +5 -0
- data/lib/fdlint/support/core/nil.rb +7 -0
- data/lib/fdlint/support/core/string.rb +7 -0
- data/lib/fdlint/support/core_ext.rb +5 -0
- data/lib/fdlint/validator.rb +102 -0
- data/lib/fdlint/version.rb +3 -0
- data/lib/fdlint.rb +5 -0
- data/rules.d/css.rule.rb +100 -0
- data/rules.d/filename.rule.rb +49 -0
- data/rules.d/html.rule.rb +169 -0
- data/rules.d/js.jquery.rule.rb +49 -0
- data/rules.d/js.rule.rb +205 -0
- data/test/default_test.rb +14 -0
- data/test/fixtures/js/scope-test.js +15 -2
- data/test/test_helper.rb +9 -0
- metadata +269 -221
- data/lib/base_parser.rb +0 -143
- data/lib/cmd_runner.rb +0 -145
- data/lib/context.rb +0 -31
- data/lib/css/reader.rb +0 -30
- data/lib/css/rule/check_compression_rule.rb +0 -48
- data/lib/css/rule/checklist.rb +0 -45
- data/lib/helper/code_type.rb +0 -50
- data/lib/helper/color_string.rb +0 -44
- data/lib/helper/file_reader.rb +0 -22
- data/lib/helper/strenc.rb +0 -65
- data/lib/js/expr/expr.rb +0 -66
- data/lib/js/expr/left_hand.rb +0 -63
- data/lib/js/expr/operate.rb +0 -92
- data/lib/js/expr/primary.rb +0 -166
- data/lib/js/rule/all.rb +0 -35
- data/lib/js/rule/checklist.rb +0 -41
- data/lib/js/rule/file_checker.rb +0 -42
- data/lib/js/rule/helper.rb +0 -96
- data/lib/js/rule/no_global.rb +0 -87
- data/lib/js/stat/if.rb +0 -25
- data/lib/js/stat/iter.rb +0 -85
- data/lib/js/stat/stat.rb +0 -117
- data/lib/js/stat/switch.rb +0 -65
- data/lib/js/stat/try.rb +0 -28
- data/lib/js/stat/var.rb +0 -40
- data/lib/js/struct.rb +0 -248
- data/lib/log_entry.rb +0 -49
- data/lib/node.rb +0 -28
- data/lib/parse_error.rb +0 -13
- data/lib/parser_visitable.rb +0 -138
- data/lib/printer/base_printer.rb +0 -24
- data/lib/printer/console_printer.rb +0 -66
- data/lib/printer/nocolor_printer.rb +0 -27
- data/lib/printer/vim_printer.rb +0 -19
- data/lib/rule.rb +0 -241
- data/lib/rule_helper.rb +0 -14
- data/lib/runner.rb +0 -225
- data/rules.d/css.rule +0 -127
- data/rules.d/html.dtd.rule +0 -22
- data/rules.d/html.prop.rule +0 -51
- data/rules.d/html.tag.rule +0 -136
- data/rules.d/js.file.rule +0 -13
- data/rules.d/js.jquery.rule +0 -56
- data/rules.d/js.mergefile.rule +0 -71
- data/rules.d/js.rule +0 -84
data/lib/runner.rb
DELETED
@@ -1,225 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
#require 'profile'
|
4
|
-
|
5
|
-
require 'logger'
|
6
|
-
require_relative 'base_parser'
|
7
|
-
require_relative 'rule'
|
8
|
-
require_relative 'parser_visitable'
|
9
|
-
require_relative 'file_validator'
|
10
|
-
require_relative 'log_entry'
|
11
|
-
require_relative 'css/reader'
|
12
|
-
require_relative 'css/parser'
|
13
|
-
require_relative 'css/rule/checklist'
|
14
|
-
require_relative 'html/parser'
|
15
|
-
require_relative 'html/rule/check_tag_rule'
|
16
|
-
require_relative 'js/parser'
|
17
|
-
require_relative 'js/rule/all'
|
18
|
-
require_relative 'js/rule/file_checker'
|
19
|
-
require_relative 'helper/file_reader'
|
20
|
-
require_relative 'helper/code_type'
|
21
|
-
|
22
|
-
|
23
|
-
module XRay
|
24
|
-
|
25
|
-
module CSS
|
26
|
-
class VisitableParser < Parser
|
27
|
-
include XRay::ParserVisitable
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
module HTML
|
32
|
-
class VisitableParser < Parser
|
33
|
-
include XRay::ParserVisitable
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
module JS
|
38
|
-
class VisitableParser < Parser
|
39
|
-
include XRay::ParserVisitable
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
|
44
|
-
class Runner
|
45
|
-
|
46
|
-
include Helper::FileReader
|
47
|
-
|
48
|
-
attr_reader :source, :rules
|
49
|
-
|
50
|
-
def initialize(opt={})
|
51
|
-
@opt = {
|
52
|
-
:encoding => 'utf-8',
|
53
|
-
:debug => false,
|
54
|
-
:log_level => :warn
|
55
|
-
}.merge opt
|
56
|
-
|
57
|
-
@rules = []
|
58
|
-
|
59
|
-
if @opt[:debug]
|
60
|
-
@logger = Logger.new(STDOUT)
|
61
|
-
@logger.level = Logger::INFO
|
62
|
-
end
|
63
|
-
|
64
|
-
Rule.import_all
|
65
|
-
|
66
|
-
|
67
|
-
end
|
68
|
-
|
69
|
-
def check_css(css, opt = {})
|
70
|
-
@source = css
|
71
|
-
parser = XRay::CSS::VisitableParser.new(css, @logger)
|
72
|
-
visitor = XRay::CSS::Rule::CheckListRule.new( opt )
|
73
|
-
parser.add_visitor visitor
|
74
|
-
run_parser( parser )
|
75
|
-
end
|
76
|
-
|
77
|
-
def check_css_file( file, opt={} )
|
78
|
-
results = []
|
79
|
-
begin
|
80
|
-
"".extend(XRay::Rule).check_css_file(file).each do |msg, level, *pos|
|
81
|
-
results.unshift LogEntry.new( msg, level, pos[0] || 0, pos[1] || 0 )
|
82
|
-
end
|
83
|
-
|
84
|
-
source = XRay::CSS::Reader.read( file, @opt )
|
85
|
-
results.concat check_css( source, opt.merge({
|
86
|
-
:scope => CodeType.scope(file)
|
87
|
-
}))
|
88
|
-
rescue EncodingError => e
|
89
|
-
results.unshift LogEntry.new( "File can't be read as #{@opt[:encoding]} charset", :fatal)
|
90
|
-
rescue => e
|
91
|
-
if @opt[:debug]
|
92
|
-
puts e
|
93
|
-
puts e.backtrace
|
94
|
-
end
|
95
|
-
results.unshift LogEntry.new( e.to_s, :fatal)
|
96
|
-
end
|
97
|
-
results
|
98
|
-
end
|
99
|
-
|
100
|
-
def check_js(js, opt={})
|
101
|
-
@source = js
|
102
|
-
parser = JS::VisitableParser.new(js, @logger)
|
103
|
-
parser.add_visitors JS::Rule::All.new
|
104
|
-
run_parser( parser )
|
105
|
-
end
|
106
|
-
|
107
|
-
def check_js_file(file, opt = {})
|
108
|
-
results = []
|
109
|
-
begin
|
110
|
-
results.concat JS::Rule::FileChecker.new.check_file(file)
|
111
|
-
|
112
|
-
source, encoding = readfile(file, opt)
|
113
|
-
results.concat check_js(source)
|
114
|
-
rescue EncodingError => e
|
115
|
-
results.unshift LogEntry.new( "File can't be read as #{@opt[:encoding]} charset", :fatal)
|
116
|
-
rescue => e
|
117
|
-
if @opt[:debug]
|
118
|
-
puts e
|
119
|
-
puts e.backtrace
|
120
|
-
end
|
121
|
-
results.unshift LogEntry.new( e.to_s, :fatal )
|
122
|
-
end
|
123
|
-
results
|
124
|
-
end
|
125
|
-
|
126
|
-
def check_html(text, opt={})
|
127
|
-
@source = text
|
128
|
-
parser = HTML::VisitableParser.new(text, @logger)
|
129
|
-
visitor = HTML::Rule::CheckTagRule.new( opt )
|
130
|
-
parser.add_visitor visitor
|
131
|
-
results = run_parser( parser )
|
132
|
-
unless @parsed_element.nil? or @parsed_element.empty?
|
133
|
-
results += check_scripts_in_html(opt)
|
134
|
-
results += check_styles_in_html(opt)
|
135
|
-
end
|
136
|
-
results
|
137
|
-
end
|
138
|
-
|
139
|
-
def check_scripts_in_html(opt={})
|
140
|
-
results = []
|
141
|
-
@parsed_element.query('script') do |script|
|
142
|
-
row = script.position.row
|
143
|
-
col = script.position.column
|
144
|
-
Runner.new.check_js(script.text, opt).each do |ret|
|
145
|
-
ret.column += script.outer_html[/^\s*<script*?>/].size if ret.row == 1
|
146
|
-
ret.row += row - 1
|
147
|
-
results << ret
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
results
|
152
|
-
end
|
153
|
-
|
154
|
-
def check_styles_in_html(opt={})
|
155
|
-
results = []
|
156
|
-
@parsed_element.query('style') do |style|
|
157
|
-
row = style.position.row
|
158
|
-
col = style.position.column
|
159
|
-
Runner.new.check_css(style.text, opt.merge({:scope => :in_page })).each do |ret|
|
160
|
-
ret.column += style.outer_html[/^\s*<style*?>/].size if ret.row == 1
|
161
|
-
ret.row += row - 1
|
162
|
-
results << ret
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
results
|
167
|
-
end
|
168
|
-
|
169
|
-
def check_html_file(file, opt={})
|
170
|
-
source, encoding = readfile file
|
171
|
-
check_html source
|
172
|
-
end
|
173
|
-
|
174
|
-
def check_file( file )
|
175
|
-
type = CodeType.guess_by_name(file)
|
176
|
-
send( "check_#{type}_file", file ) if CodeType.is_style_file? file
|
177
|
-
end
|
178
|
-
|
179
|
-
def check(text, filename="")
|
180
|
-
type = CodeType.guess(text, filename)
|
181
|
-
send "check_#{type}", text
|
182
|
-
end
|
183
|
-
|
184
|
-
def valid_file? file
|
185
|
-
CodeType.is_style_file?(file) and !minified_and_ignored(file) and type_ok?(file)
|
186
|
-
end
|
187
|
-
|
188
|
-
def minified_and_ignored(file)
|
189
|
-
!@opt[:check_min] && file.to_s =~ /-min\.(css|js)$/
|
190
|
-
end
|
191
|
-
|
192
|
-
def type_ok?(file)
|
193
|
-
if @opt[:type]
|
194
|
-
CodeType.guess_by_name(file) == @opt[:type]
|
195
|
-
else
|
196
|
-
true
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
def run_parser(parser)
|
201
|
-
@parsed_element = parser.parse_no_throw
|
202
|
-
filter_results( parser.results ).sort_by!(&:row)
|
203
|
-
end
|
204
|
-
|
205
|
-
def filter_results(results)
|
206
|
-
case log_level
|
207
|
-
when :warn
|
208
|
-
results
|
209
|
-
when :error
|
210
|
-
results.select {|r| r.level == :error || r.level == :fatal }
|
211
|
-
when :fatal
|
212
|
-
results.select {|r| r.level == :fatal }
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
def log_level
|
217
|
-
@opt[:log_level]
|
218
|
-
end
|
219
|
-
|
220
|
-
def log_level=(lvl)
|
221
|
-
@opt[:log_level] = lvl
|
222
|
-
end
|
223
|
-
|
224
|
-
end
|
225
|
-
end
|
data/rules.d/css.rule
DELETED
@@ -1,127 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
# vi: filetype=ruby
|
3
|
-
css
|
4
|
-
|
5
|
-
check_file_name_without_ad do |name|
|
6
|
-
unless defined? ADVERTISMENT
|
7
|
-
ADVERTISMENT = /(?:[^a-z0-9%_-]|^)ad(?:[sv][^a-z\r=\?]+|banner|click|ver|name|x|log|[^a-z\r_-]*[\.\/]|bot|c_|client|council|gifs|graph|images|img|fshow|pic|vert|view|info|click|sponsor)/
|
8
|
-
end
|
9
|
-
if name =~ ADVERTISMENT
|
10
|
-
['路径和文件名中不应该出现ad', :error]
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
check_file_name_without_underscore do |name|
|
15
|
-
if File.basename(name) =~ /_/
|
16
|
-
['文件名中单词的分隔符应该使用中横线“-”', :error]
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
check_file_name_seperator do |name|
|
21
|
-
if File.dirname(name) =~ /-(?!v?[\d.])/
|
22
|
-
['文件夹只有需要版本区分时才可用中横线分隔,如fdev-v3', :error]
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
check_file_name_downcase do |name|
|
27
|
-
win_disk = /^[a-zA-Z]:/
|
28
|
-
if name.sub( win_disk, '') =~ /[A-Z]/
|
29
|
-
['文件夹和文件命名必须用小写字母', :error]
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
check_selector_with_id do |selector|
|
34
|
-
if context.page_level? &&
|
35
|
-
selector =~ /#[-\w]+/
|
36
|
-
['页面级别样式不使用id', :error]
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
check_selector_with_global_tag do |selector|
|
41
|
-
if context.page_level? &&
|
42
|
-
selector =~ /^\w+$/
|
43
|
-
['页面级别样式不能全局定义标签样式', :error]
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
check_selector_level do |selector|
|
48
|
-
if selector.text.split(/[>\s]/).length > 4
|
49
|
-
['CSS级联深度不能超过4层', :error]
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
check_selector_with_star do |selector|
|
54
|
-
if selector =~ /^\*/
|
55
|
-
['禁止使用星号选择符', :error]
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
check_selector_redefine_lib_css do |selector|
|
60
|
-
if !context.lib? &&
|
61
|
-
selector =~ /^\.fd-\w+$/
|
62
|
-
['禁止修改或重载type中的样式', :error]
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
check_declaration_font do |dec|
|
67
|
-
if dec.property =~ /^font(-family)?$/ &&
|
68
|
-
dec.value.to_s.each_byte.any? {|b| b>127}
|
69
|
-
['字体名称中的中文必须用ascii字符表示', :error]
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
check_ruleset_redefine_a_hover_color do |ruleset|
|
74
|
-
if ruleset.selector &&
|
75
|
-
ruleset.selector.text == 'a:hover' &&
|
76
|
-
ruleset.declarations.find { |dec| dec.property.text == 'color' }
|
77
|
-
['禁止重写reset中定义的a标签的hover色(现为#ff7300)', :error]
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
check_declarations_sequence do |ruleset|
|
82
|
-
list = [
|
83
|
-
%w(position display visible z-index overflow float clear),
|
84
|
-
%w(width height top right bottom left margin padding border),
|
85
|
-
%w(background opacity),
|
86
|
-
%w(font color text line-height vertical-align)
|
87
|
-
]
|
88
|
-
|
89
|
-
now = 0
|
90
|
-
ruleset.declarations.each do |dec|
|
91
|
-
prop_text = dec.property.text
|
92
|
-
index = list.find_index do |bag|
|
93
|
-
bag.any? { |field| prop_text.index field }
|
94
|
-
end
|
95
|
-
|
96
|
-
next unless index
|
97
|
-
return ['建议使用Mozilla推荐CSS书写顺序'\
|
98
|
-
'http://wd.alibaba-inc.com/doc/page/regulations/css', :warn] if index < now
|
99
|
-
now = index
|
100
|
-
end
|
101
|
-
nil
|
102
|
-
end
|
103
|
-
|
104
|
-
check_selector_using_hack do |selector|
|
105
|
-
if selector =~ /\S\*/
|
106
|
-
['合理使用hack', :error]
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
check_property_hack do |property|
|
111
|
-
if property =~ /[^-a-z]/
|
112
|
-
['合理使用hack', :error]
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
check_value_use_css_expression do |value|
|
117
|
-
if value =~ /^expression\(/
|
118
|
-
['禁止使用CSS表达式', :error]
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
check_value_use_hack do |value|
|
123
|
-
if value =~ /\\\d$/
|
124
|
-
['合理使用hack', :error]
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
data/rules.d/html.dtd.rule
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
# vi: filetype=ruby
|
3
|
-
html
|
4
|
-
|
5
|
-
check_doc do |doc|
|
6
|
-
unless context.have_dtd?
|
7
|
-
["必须存在文档类型声明", :error]
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
check_dtd_type_must_be_html5 do |dtd|
|
12
|
-
unless dtd.type =~ /^html$/i
|
13
|
-
['新页面统一使用HTML 5 DTD', :warn]
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
check_dtd_upcase do |dtd|
|
18
|
-
unless dtd =~ /^<!DOCTYPE/
|
19
|
-
['必须使用大写的"DOCTYPE"', :warn]
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
data/rules.d/html.prop.rule
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
# vi: filetype=ruby
|
3
|
-
|
4
|
-
html
|
5
|
-
|
6
|
-
check_property_no_inline_style do |prop|
|
7
|
-
if prop.name =~ /^style$/im
|
8
|
-
["不能定义内嵌样式style", :error]
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
check_property_name_downcase do |prop|
|
13
|
-
if prop.name =~ /[A-Z]/
|
14
|
-
["属性名必须小写,连字符用中横线", :error]
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
check_property_id_prop_value_downcase do |prop|
|
19
|
-
if prop.name_equal? 'id' and prop.value =~ /[A-Z]/
|
20
|
-
["id名称全部小写,单词分隔使用中横线", :error]
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
check_property_class_prop_value_downcase do |prop|
|
25
|
-
if prop.name_equal? 'class' and prop.value =~ /[A-Z]/
|
26
|
-
["class名称全部小写,单词分隔使用中横线", :error]
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
check_property_value_sep do |prop|
|
31
|
-
if prop.value and prop.sep != '"'
|
32
|
-
["属性值必须使用双引号", :error]
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
check_property_value_exsit do |prop|
|
37
|
-
if prop.value.nil?
|
38
|
-
["不能仅有属性名", :error]
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
check_property_class_count do |prop|
|
43
|
-
if prop.name_equal? 'class'
|
44
|
-
names = prop.value.split /\s+/
|
45
|
-
names.reject! { |s| s =~ /^(fd-|layout|grid|w952)\b/ }
|
46
|
-
if names.size > 3
|
47
|
-
["一个节点上定义的class个数最多不超过3个(不含lib中的class)", :error]
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
data/rules.d/html.tag.rule
DELETED
@@ -1,136 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
# vi: filetype=ruby
|
3
|
-
|
4
|
-
html
|
5
|
-
|
6
|
-
check_tag_name_downcase do |tag|
|
7
|
-
if tag.tag_name =~ /[A-Z]/ || tag.ending =~ /[A-Z]/
|
8
|
-
["标签名必须小写", :error]
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
check_tag_img_must_have_alt do |tag|
|
13
|
-
if tag.tag_name_equal? 'img'
|
14
|
-
unless tag.has_prop?(:alt)
|
15
|
-
["img标签必须加上alt属性", :error]
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
check_tag_hyperlink_with_target do |tag|
|
21
|
-
|
22
|
-
if tag.tag_name_equal? 'base' and tag.prop_value(:target)
|
23
|
-
@has_target = true
|
24
|
-
end
|
25
|
-
|
26
|
-
unless @has_target
|
27
|
-
if tag.tag_name_equal? 'a' and tag.prop_value(:href) =~ /^#/ and tag.prop_value(:target) != '_self'
|
28
|
-
['功能a必须加target="_self",除非preventDefault过', :warn]
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
check_tag_hyperlink_with_title do |tag|
|
34
|
-
if tag.tag_name_equal? 'a' and tag.prop_value(:href) =~ /^[^#]/
|
35
|
-
unless (prop = tag.prop_value(:title)) and !prop.empty?
|
36
|
-
['非功能能点的a标签必须加上title属性', :error]
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
check_tag_unique_script_import do |tag|
|
42
|
-
if tag.tag_name_equal? 'script'
|
43
|
-
src = tag.prop_value(:src).to_s
|
44
|
-
if !src.empty? and context.script_used? src
|
45
|
-
["避免重复引用同一或相同功能文件", :error]
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
check_tag_unique_style_import do |tag|
|
51
|
-
if tag.tag_name_equal? 'link' and tag.prop_value(:rel) =~ /stylesheet/i
|
52
|
-
src = tag.prop_value(:href).to_s
|
53
|
-
if !src.empty? and context.style_used? src
|
54
|
-
["避免重复引用同一或相同功能文件", :error]
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
check_tag_no_import_in_style_tag do |tag|
|
60
|
-
if tag.tag_name_equal? 'style' and tag.inner_text =~ /@import\s/m
|
61
|
-
["不通过@import在页面上引入CSS", :error]
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
check_tag_head_contain_meta_and_title do |tag|
|
66
|
-
if tag.tag_name_equal? 'head'
|
67
|
-
children = tag.children
|
68
|
-
has_meta = children.any? { |e| e.tag_name_equal? 'meta' and e.prop_value('charset') }
|
69
|
-
has_title = children.any? { |e| e.tag_name_equal? 'title' }
|
70
|
-
unless has_meta and has_title
|
71
|
-
["head必须包含字符集meta和title", :error]
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
check_tag_block_in_block do |tag|
|
77
|
-
if !tag.tag_name_equal?('a') and tag.inline? and tag.children.any? { |e| !e.inline? }
|
78
|
-
["行内标签不得包含块级标签,a标签例外", :error]
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
check_tag_form_element_with_name do |tag|
|
83
|
-
if (tag.tag_name_equal?('input') and %w(text radio checkbox).include?(tag.prop_value('type').to_s.downcase) or
|
84
|
-
tag.tag_name_equal?('select') or
|
85
|
-
tag.tag_name_equal?('textarea'))
|
86
|
-
val = tag.prop_value('name')
|
87
|
-
unless val and !val.empty?
|
88
|
-
["text、radio、checkbox、textarea、select必须加name属性", :error]
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
check_tag_form_button do |tag|
|
94
|
-
if tag.tag_name_equal?('input') and %w(button submit reset).include?(tag.prop_value('type').to_s.downcase)
|
95
|
-
["所有按钮必须用button(button/submit/reset)", :error]
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
check_tag_css_in_head do |tag|
|
100
|
-
if tag.tag_name_equal?('link') and tag.prop_value(:rel) =~ /stylesheet/i
|
101
|
-
if tag.has_scope? and !tag.in_scope?('head')
|
102
|
-
["外链CSS置于head里(例外:应用里的footer样式)", :warn]
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
check_tag_closed do |tag|
|
108
|
-
if !tag.closed? or (tag.auto_close? and !tag.self_closed?)
|
109
|
-
["标签必须正确闭合", :error]
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
check_tag_html_template do |tag|
|
114
|
-
info = ["新页面按库中的HTML基本结构模板书写基本页面结构", :warn]
|
115
|
-
if tag.tag_name_equal?('head')
|
116
|
-
if !tag.children.any? { |e| e === 'meta[name==description]' } or
|
117
|
-
!tag.children.any? { |e| e === 'meta[name==keywords]' }
|
118
|
-
info
|
119
|
-
end
|
120
|
-
elsif tag.tag_name_equal?('body')
|
121
|
-
info unless tag.children.any? { |e| e === 'div#doc' }
|
122
|
-
elsif tag === 'div#doc'
|
123
|
-
if !tag.children.any? { |e| e === 'div#header' } or
|
124
|
-
!tag.children.any? { |e| e === 'div#footer' } or
|
125
|
-
!tag.children.any? { |e| e === 'div#alibar' } or
|
126
|
-
!tag.children.any? { |e| e === 'div#content' }
|
127
|
-
info
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
check_text_should_escape do |el|
|
133
|
-
if el.text =~ /[<>]/
|
134
|
-
["特殊HTML符号(>和<)必须转义", :error]
|
135
|
-
end
|
136
|
-
end
|
data/rules.d/js.file.rule
DELETED
data/rules.d/js.jquery.rule
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
# vi: filetype=ruby
|
3
|
-
|
4
|
-
js
|
5
|
-
|
6
|
-
JQ_IDS = %w(jQuery $ jQ jq)
|
7
|
-
|
8
|
-
check_expr_member_direct_jquery_call do |expr|
|
9
|
-
expr = context.find_expr_member(expr) do |expr|
|
10
|
-
['.', '(', '['].include?(expr.type) && expr.left.text == 'jQuery'
|
11
|
-
end
|
12
|
-
|
13
|
-
if expr
|
14
|
-
unless expr.type == '.' && expr.right.text == 'namespace'
|
15
|
-
['禁止直接使用jQuery变量,使用全局闭包写法"(function($, NS){....})(jQuery,Namespace);",jQuery.namespace例外', :error]
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
check_expr_member_forbit_method_call do |expr|
|
21
|
-
methods = %w(sub noConflict)
|
22
|
-
expr = context.find_expr_member(expr) do |expr|
|
23
|
-
expr.type == '.' && JQ_IDS.include?(expr.left.text) &&
|
24
|
-
methods.include?(expr.right.text)
|
25
|
-
end
|
26
|
-
|
27
|
-
['禁止使用jQuery.sub()和jQuery.noConflict方法', :error] if expr
|
28
|
-
end
|
29
|
-
|
30
|
-
check_expr_member_data_call_param do |expr|
|
31
|
-
expr = context.find_expr_member(expr) do |expr|
|
32
|
-
if expr.type == '('
|
33
|
-
name = expr.left
|
34
|
-
if name.is_a?(XRay::JS::Expression) && name.type == '.' &&
|
35
|
-
name.right.text == 'data'
|
36
|
-
param = expr.right[0]
|
37
|
-
param && param.text =~ /[-_]/
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
['使用".data()"读写自定义属性时需要转化成驼峰形式', :error] if expr
|
43
|
-
end
|
44
|
-
|
45
|
-
check_expr_member_ctor_selector do |expr|
|
46
|
-
expr = context.find_expr_member(expr) do |expr|
|
47
|
-
expr.type == '(' && JQ_IDS.include?(expr.left.text)
|
48
|
-
end
|
49
|
-
|
50
|
-
if expr
|
51
|
-
param = expr.right[0]
|
52
|
-
if param && param.type == 'string' && param.text !~ /^['"][#\w<]/
|
53
|
-
['使用选择器时,能确定tagName的,必须加上tagName', :warn]
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
data/rules.d/js.mergefile.rule
DELETED
@@ -1,71 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
# vi: filetype=ruby
|
3
|
-
|
4
|
-
js
|
5
|
-
|
6
|
-
check_merge_importing_one_line_one_import do |import, pathes, file|
|
7
|
-
same_line = pathes.select { |path| path[:row] == import[:row] }
|
8
|
-
if same_line.size > 1 and same_line.index(import) > 0
|
9
|
-
['一行只能有一个import文件', :error, import[:row], import[:col]]
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
check_merge_importing_strict_import_js do |import, pathes, file|
|
14
|
-
url = import[:url]
|
15
|
-
if context.lib_scope?(url) or context.relative?(url)
|
16
|
-
break
|
17
|
-
end
|
18
|
-
|
19
|
-
unless /ImportJavscript\.url\(['"]?([^'"]+)['"]?\);/ =~ import[:text]
|
20
|
-
['merge文件格式不正确', :error, import[:row], import[:col]]
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
check_merge_importing_global_cannot_import_page do |import, pathes, file|
|
25
|
-
url = import[:url]
|
26
|
-
if context.lib_scope?(url) or context.relative?(url)
|
27
|
-
break
|
28
|
-
end
|
29
|
-
|
30
|
-
if context.global_scope? file and context.page_scope?(url)
|
31
|
-
['产品线merge文件不能引用page文件', :error, import[:row], import[:col]]
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
check_merge_importing_can_only_import_from_same_app do |import, pathes, file|
|
36
|
-
url = import[:url]
|
37
|
-
if context.lib_scope?(url) or context.relative?(url)
|
38
|
-
break
|
39
|
-
end
|
40
|
-
|
41
|
-
app = context.app(file)
|
42
|
-
if app && app != context.app(url)
|
43
|
-
['merge文件引用非该产品线文件', :error, import[:row], import[:col]]
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
check_merge_importing_page_can_only_import_same_page do |import, pathes, file|
|
48
|
-
if context.page_scope?(file)
|
49
|
-
path = file.sub /\\/, '/'
|
50
|
-
url = import[:url]
|
51
|
-
prefix = File.basename(path).sub /-merge([-_]\d+)?\.js/, ''
|
52
|
-
page_pattern = %r"/page/#{prefix}(-min|(/.+))?\.js"
|
53
|
-
if context.page_scope?(file) && context.page_scope?(url) && url !~ page_pattern
|
54
|
-
['页面级别merge文件只允许merge当前页面所属js文件', :error, import[:row], import[:col]]
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
##Style 拆分之后可能merge的文件已经不存在
|
60
|
-
##stop checking this rule
|
61
|
-
#check_merge_importing_exist do |import, pathes, file|
|
62
|
-
#end
|
63
|
-
|
64
|
-
check_merge_importing_must_be_minified do |import, pathes, file|
|
65
|
-
if !context.min_file?(import[:url])
|
66
|
-
['merge文件需要引用压缩版的js, 如a-min.js', :warn,
|
67
|
-
import[:row],
|
68
|
-
import[:col] + import[:text].rindex(/\/|\\/) + 1
|
69
|
-
]
|
70
|
-
end
|
71
|
-
end
|