fdlint 0.2.0.pre → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +36 -15
- data/Rakefile +1 -1
- data/bin/fdlint +30 -9
- data/lib/fdlint/cli.rb +62 -10
- data/lib/fdlint/helper/logger.rb +1 -1
- data/lib/fdlint/log_entry.rb +14 -0
- data/lib/fdlint/parser/html/html_parser.rb +10 -12
- data/lib/fdlint/parser/html/query.rb +64 -50
- data/lib/fdlint/parser/html/struct.rb +20 -3
- data/lib/fdlint/parser/parser_visitable.rb +11 -5
- data/lib/fdlint/printer/base_printer.rb +6 -0
- data/lib/fdlint/printer/console_printer.rb +15 -23
- data/lib/fdlint/rule.rb +4 -4
- data/lib/fdlint/support/core/object.rb +6 -0
- data/lib/fdlint/support/core_ext.rb +1 -0
- data/lib/fdlint/validator.rb +60 -8
- data/lib/fdlint/version.rb +1 -1
- data/lib/hook/git_pre_commit +18 -0
- data/rules.d/css.rule.rb +1 -1
- data/rules.d/filename.rule.rb +3 -1
- data/rules.d/html.rule.rb +45 -32
- data/rules.d/js.rule.rb +2 -2
- data/test/all_tests.rb +28 -42
- data/test/css/mac_line_end_support_test.rb +10 -12
- data/test/css/parser_test.rb +4 -5
- data/test/css/rule/check_encoding_test.rb +7 -8
- data/test/css/rule/check_list_rule_test.rb +85 -102
- data/test/css/rule/file_name_test.rb +18 -39
- data/test/default_test.rb +1 -14
- data/test/fixtures/css/ad.css +0 -0
- data/test/fixtures/css/adver/test.css +0 -0
- data/test/fixtures/css/camelCase.css +0 -0
- data/test/fixtures/css/min/ad.css +0 -0
- data/test/fixtures/css/min/ad.min.css +0 -0
- data/test/fixtures/html/mixed_log_levels.html +1 -0
- data/test/fixtures/html/mixed_types.html +3 -0
- data/test/helper.rb +116 -16
- data/test/html/mixed_type_test.rb +14 -20
- data/test/html/parser/parse_comment_test.rb +4 -4
- data/test/html/parser/parse_dtd_test.rb +7 -7
- data/test/html/parser/parse_script_tag_test.rb +21 -14
- data/test/html/parser/parse_with_auto_close_tag_test.rb +12 -10
- data/test/html/parser/parse_with_diff_case_test.rb +8 -9
- data/test/html/parser/parse_with_emtpy_test.rb +5 -3
- data/test/html/parser/parse_with_multi_children_test.rb +4 -4
- data/test/html/parser/parse_with_multi_line_test.rb +5 -5
- data/test/html/parser/parse_with_prop_test.rb +10 -10
- data/test/html/parser/parse_with_script_tag_test.rb +4 -4
- data/test/html/parser/parse_with_selfclosing_test.rb +11 -11
- data/test/html/parser/parse_with_simple_tag_test.rb +7 -7
- data/test/html/parser/parse_with_simple_tree_test.rb +6 -6
- data/test/html/parser/parse_with_style_tag_test.rb +4 -4
- data/test/html/parser/parse_with_text_test.rb +7 -7
- data/test/html/parser_test.rb +19 -19
- data/test/html/query_test.rb +18 -18
- data/test/html/rule/check_block_level_element_test.rb +22 -24
- data/test/html/rule/check_button_test.rb +9 -9
- data/test/html/rule/check_css_in_head_test.rb +11 -32
- data/test/html/rule/check_dtd_test.rb +15 -11
- data/test/html/rule/check_form_element_name_test.rb +10 -9
- data/test/html/rule/check_head_contain_meta_and_title_test.rb +28 -34
- data/test/html/rule/check_hyperlink_with_target_test.rb +23 -17
- data/test/html/rule/check_hyperlink_with_title_test.rb +13 -20
- data/test/html/rule/check_id_n_class_downcase_test.rb +8 -19
- data/test/html/rule/check_img_with_alt_prop_test.rb +11 -12
- data/test/html/rule/check_no_import_css_test.rb +20 -20
- data/test/html/rule/check_prop_have_value_test.rb +9 -13
- data/test/html/rule/check_prop_seperator_test.rb +9 -13
- data/test/html/rule/check_style_prop_test.rb +7 -12
- data/test/html/rule/check_tag_closed_test.rb +15 -40
- data/test/html/rule/check_tag_downcase_test.rb +31 -28
- data/test/html/rule/check_unescape_char_test.rb +17 -17
- data/test/html/rule/check_unique_import_test.rb +15 -33
- data/test/html/rule_test.rb +2 -6
- data/test/js/expr/expr.rb +1 -1
- data/test/js/expr/left_hand.rb +1 -1
- data/test/js/expr/operate.rb +1 -1
- data/test/js/expr/primary.rb +1 -1
- data/test/js/parser_test.rb +3 -6
- data/test/js/rule/alert_check_test.rb +5 -19
- data/test/js/rule/base_test.rb +5 -19
- data/test/js/rule/jq_check_test.rb +26 -58
- data/test/js/rule/nest_try_catch_test.rb +26 -43
- data/test/js/rule/new_object_and_new_array_test.rb +5 -21
- data/test/js/rule/no_eval_test.rb +3 -19
- data/test/js/rule/no_global_test.rb +34 -73
- data/test/js/rule/private_method_check_test.rb +14 -43
- data/test/js/rule/semicolon_test.rb +18 -47
- data/test/js/rule/stat_if_with_brace_test.rb +30 -53
- data/test/js/rule/stat_if_with_muti_else_test.rb +36 -53
- data/test/js/rule/use_strict_equal_test.rb +16 -29
- data/test/js/rule_test.rb +2 -4
- data/test/js/stat/if.rb +1 -1
- data/test/js/stat/iter.rb +1 -1
- data/test/js/stat/stat.rb +1 -1
- data/test/js/stat/switch.rb +1 -1
- data/test/js/stat/try.rb +1 -1
- data/test/js/stat/var.rb +1 -1
- data/test/parser_visitable_test.rb +14 -36
- data/test/position_info_test.rb +4 -5
- data/test/runner/log_level_test.rb +30 -25
- metadata +11 -14
- data/lib/fdlint/file_validator.rb +0 -38
- data/lib/fdlint/parser/html/rule/check_tag_rule.rb +0 -80
- data/test/css/rule/compression_test.rb +0 -53
- data/test/html/rule/check_class_count_test.rb +0 -36
- data/test/html/rule/check_html_template_test.rb +0 -103
- data/test/js/rule/all_test.rb +0 -23
- data/test/js/rule/file_checker_test.rb +0 -131
- data/test/rule_dsl/dsl_basic_test.rb +0 -91
- data/test/rule_dsl/importing_test.rb +0 -48
- data/test/test_helper.rb +0 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5010fb8a0b8b08e6b4ebd130f35c425d62cfef80
|
|
4
|
+
data.tar.gz: d01fccdb793cbc4900f291c74599e2dfef319509
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b21da480340bc0c23af7851ec02baf2b16e424fbc544e5da2ae963f32b5c0001ad4b54ca87a25db756321a5b88b179df025ee48d86d1de26efe118d255aef988
|
|
7
|
+
data.tar.gz: 99aa6f8d89edabee672f97202ecfffbe359d88c1eeab7b9445e20006c3ab1b57263b64d7ac31193c343bb6da2a036c019b61a846213f79e8efbbe6257e3e6491
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
fdlint -- 让前端code review更轻松
|
|
2
2
|
=================================
|
|
3
3
|
|
|
4
|
-

|
|
5
5
|
|
|
6
|
-
fdlint
|
|
6
|
+
fdlint 是根据阿里巴巴前端开发checklist开发的自动代码扫描工具。
|
|
7
7
|
可以扫描出前端程序中不符合开发规范的地方。
|
|
8
8
|
|
|
9
9
|
[](http://travis-ci.org/qhwa/fdlint)
|
|
@@ -29,28 +29,49 @@ fdlint (开发代号xray) 是根据阿里巴巴前端开发checklist开发的自
|
|
|
29
29
|
|
|
30
30
|
gem install fdlint
|
|
31
31
|
|
|
32
|
-
运行方式
|
|
32
|
+
运行方式(命令行):
|
|
33
33
|
|
|
34
34
|
fdlint [参数] <目标文件或目录>
|
|
35
|
+
fdlint [全局参数] 命令 [命令选项] [路径...]
|
|
35
36
|
|
|
36
37
|
或者使用管道:
|
|
37
38
|
|
|
38
|
-
echo '* {}' | fdlint
|
|
39
|
+
echo '* {}' | fdlint check
|
|
39
40
|
|
|
40
41
|
参数列表:
|
|
41
42
|
|
|
42
43
|
~~~
|
|
43
|
-
Usage:
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
-d, --debug
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
44
|
+
Usage:
|
|
45
|
+
fdlint [全局参数] 命令 [命令参数] [路径...]
|
|
46
|
+
|
|
47
|
+
全局参数
|
|
48
|
+
|
|
49
|
+
-d, --debug - 打印调试信息
|
|
50
|
+
--help - 显示帮助信息
|
|
51
|
+
--version - 显示版本号
|
|
52
|
+
|
|
53
|
+
子命令
|
|
54
|
+
|
|
55
|
+
help - 打印某个子命令的帮助,例如 fdlint help fdlint
|
|
56
|
+
review, check - 检查代码。例如:
|
|
57
|
+
* fdlint check test.js
|
|
58
|
+
* fdlint check public/app/
|
|
59
|
+
* echo '<body></body>' | fdlint check
|
|
60
|
+
* fdlint check
|
|
61
|
+
rule - 显示导入的规则
|
|
62
|
+
~~~
|
|
63
|
+
|
|
64
|
+
`fdlint check` 的参数:
|
|
65
|
+
|
|
66
|
+
~~~
|
|
67
|
+
--format=arg - 输出格式,可以是'vim', 'console' 或 'nocolor'. (默认: console)
|
|
68
|
+
--html - 仅检查 html 文件,或指定语法为 html
|
|
69
|
+
--css - 仅检查 css 文件,或指定语法为 css
|
|
70
|
+
--js - 仅检查 js 文件,或指定语法为 js
|
|
71
|
+
-l, --list - 等同于 '--format=list'
|
|
72
|
+
--loglevel=arg - 指定位于某个级别或更严重的错误才显示,可以是 'warn', 'error' 或 'fatal'
|
|
73
|
+
(默认: warn)
|
|
74
|
+
-m, --[no-]checkmin - 检查已经被压缩的 js 或 css 文件。当扫描路径时,默认会忽略压缩文件
|
|
54
75
|
~~~
|
|
55
76
|
|
|
56
77
|
### Web
|
data/Rakefile
CHANGED
data/bin/fdlint
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
begin # XXX: Remove this begin/rescue before distributing your app
|
|
4
4
|
require 'fdlint'
|
|
5
5
|
require 'fdlint/cli'
|
|
@@ -10,6 +10,10 @@ rescue LoadError
|
|
|
10
10
|
exit 64
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
+
require 'gli'
|
|
14
|
+
require 'fdlint'
|
|
15
|
+
require 'fdlint/cli'
|
|
16
|
+
|
|
13
17
|
include GLI::App
|
|
14
18
|
|
|
15
19
|
program_desc 'Code reviewer for web developing. Check your HTML/JS/CSS codes against bad smells.'
|
|
@@ -32,17 +36,13 @@ command [:review, :check] do |c|
|
|
|
32
36
|
c.default_value :console
|
|
33
37
|
c.flag :format, must_match: %w[console nocolor vim]
|
|
34
38
|
|
|
35
|
-
c.desc "
|
|
39
|
+
c.desc "check minified files too"
|
|
36
40
|
c.default_value false
|
|
37
|
-
c.switch [:m, :"
|
|
41
|
+
c.switch [:m, :"checkmin"]
|
|
38
42
|
|
|
39
43
|
c.desc "shortcut for '--format=list'"
|
|
40
44
|
c.switch [:l, :list], negatable: false
|
|
41
45
|
|
|
42
|
-
c.desc "charset for reading files"
|
|
43
|
-
c.default_value 'utf-8'
|
|
44
|
-
c.flag [:c, :charset]
|
|
45
|
-
|
|
46
46
|
c.desc "the log level for filter results"
|
|
47
47
|
c.default_value 'warn'
|
|
48
48
|
c.flag [:loglevel], must_match: %s[warn error faltal]
|
|
@@ -59,7 +59,7 @@ command [:review, :check] do |c|
|
|
|
59
59
|
|
|
60
60
|
options = {
|
|
61
61
|
|
|
62
|
-
:log_level => opt[:loglevel],
|
|
62
|
+
:log_level => opt[:loglevel].intern,
|
|
63
63
|
:format => opt[:list] ? :nocolor : opt[:format],
|
|
64
64
|
:encoding => opt[:encoding],
|
|
65
65
|
:syntax => opt[:css] ? :css :
|
|
@@ -67,11 +67,32 @@ command [:review, :check] do |c|
|
|
|
67
67
|
opt[:html] ? :html : nil,
|
|
68
68
|
:debug => global[:debug],
|
|
69
69
|
:files => args,
|
|
70
|
-
:text => source
|
|
70
|
+
:text => source,
|
|
71
|
+
:checkmin => opt[:m]
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
Fdlint::CLI.run options
|
|
74
75
|
end
|
|
75
76
|
end
|
|
76
77
|
|
|
78
|
+
desc 'list imported rules'
|
|
79
|
+
command 'rule' do |c|
|
|
80
|
+
c.action do |global, opt, args|
|
|
81
|
+
Fdlint::CLI.list_rules debug: global[:debug]
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
desc 'add git hook (svn hook is not supported yet)'
|
|
86
|
+
command 'hook' do |c|
|
|
87
|
+
c.action do |global, opt|
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
on_error do |err|
|
|
92
|
+
if defined? Bundler
|
|
93
|
+
puts err.message
|
|
94
|
+
puts err.backtrace.join( "\n" )
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
77
98
|
exit run(ARGV)
|
data/lib/fdlint/cli.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
require 'optparse'
|
|
3
3
|
require 'find'
|
|
4
4
|
require 'logger'
|
|
5
|
+
require 'fdlint/helper/logger'
|
|
5
6
|
require 'fdlint/printer'
|
|
6
7
|
require 'fdlint/printer/vim_printer'
|
|
7
8
|
require 'fdlint/printer/nocolor_printer'
|
|
@@ -15,16 +16,23 @@ module Fdlint
|
|
|
15
16
|
Runner.new( options ).run
|
|
16
17
|
end
|
|
17
18
|
|
|
19
|
+
def self.list_rules( options )
|
|
20
|
+
Runner.new( options ).list_rules
|
|
21
|
+
end
|
|
22
|
+
|
|
18
23
|
class Runner
|
|
19
24
|
|
|
25
|
+
include Fdlint::Helper::Logger
|
|
26
|
+
|
|
20
27
|
attr_reader :options, :files
|
|
21
28
|
|
|
22
29
|
def initialize( options={} )
|
|
23
|
-
@options = options
|
|
24
|
-
@files = options[:files]
|
|
25
|
-
end
|
|
26
30
|
|
|
27
|
-
|
|
31
|
+
@options = options
|
|
32
|
+
@files = options[:files]
|
|
33
|
+
# 默认不检查已经被压缩的文件
|
|
34
|
+
@checkmin = options[:checkmin]
|
|
35
|
+
|
|
28
36
|
# Windows 下默认是ANSI编码
|
|
29
37
|
# 我们需要使用 UTF-8 编码输出
|
|
30
38
|
IO.popen "chcp 65001" if ENV['OS'] =~ /windows/i
|
|
@@ -32,6 +40,9 @@ module Fdlint
|
|
|
32
40
|
$logger = Logger.new(STDOUT).tap do |l|
|
|
33
41
|
l.level = options[:debug] ? Logger::DEBUG : Logger::FATAL
|
|
34
42
|
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def run
|
|
35
46
|
|
|
36
47
|
trap("SIGINT") { puts "\nGoodbye!"; exit! }
|
|
37
48
|
|
|
@@ -42,13 +53,21 @@ module Fdlint
|
|
|
42
53
|
end
|
|
43
54
|
end
|
|
44
55
|
|
|
56
|
+
def list_rules
|
|
57
|
+
::Fdlint::Rule.rules.each do |syntax, rules|
|
|
58
|
+
puts "----> #{syntax} (#{rules.size})\n\n"
|
|
59
|
+
rules.each do |rule|
|
|
60
|
+
print " " * 6
|
|
61
|
+
print rule
|
|
62
|
+
print "\n"
|
|
63
|
+
end
|
|
64
|
+
print "\n"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
45
68
|
protected
|
|
46
69
|
|
|
47
70
|
def validate_content
|
|
48
|
-
opt_for_validator = {
|
|
49
|
-
:code_type => options[:code_type],
|
|
50
|
-
:text => options[:text]
|
|
51
|
-
}
|
|
52
71
|
::Fdlint::Validator.new( nil, opt_for_validator ).validate do |file, source, results|
|
|
53
72
|
printer.print( file, source, results )
|
|
54
73
|
end
|
|
@@ -72,16 +91,23 @@ module Fdlint
|
|
|
72
91
|
|
|
73
92
|
def validate_directory( dir )
|
|
74
93
|
Find.find dir do |f|
|
|
75
|
-
|
|
94
|
+
unless File.directory? f
|
|
95
|
+
if need_check? f
|
|
96
|
+
validate_file f
|
|
97
|
+
end
|
|
98
|
+
end
|
|
76
99
|
end
|
|
77
100
|
end
|
|
78
101
|
|
|
79
102
|
def validate_file( path )
|
|
80
|
-
|
|
103
|
+
printer.pre_validate path
|
|
104
|
+
::Fdlint::Validator.new( path, opt_for_validator ).validate do |file, source, results|
|
|
81
105
|
printer.print( file, source, results )
|
|
82
106
|
end
|
|
107
|
+
printer.post_validate path
|
|
83
108
|
end
|
|
84
109
|
|
|
110
|
+
|
|
85
111
|
private
|
|
86
112
|
|
|
87
113
|
def printer
|
|
@@ -97,6 +123,32 @@ module Fdlint
|
|
|
97
123
|
mapping[format]
|
|
98
124
|
end
|
|
99
125
|
|
|
126
|
+
def need_check? path
|
|
127
|
+
if path =~ /([\.-_])min\.(css|js|html?)$/i && !@checkmin
|
|
128
|
+
info { "ignore minified file '#{path}'" }
|
|
129
|
+
return false
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
reg = case options[:syntax]
|
|
133
|
+
when :js, :css
|
|
134
|
+
/\.#{options[:syntax]}$/i
|
|
135
|
+
when :html
|
|
136
|
+
/\.html?$/i
|
|
137
|
+
else
|
|
138
|
+
/\.(js|css|html?)$/i
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
path =~ reg
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def opt_for_validator
|
|
145
|
+
{
|
|
146
|
+
:syntax => options[:syntax],
|
|
147
|
+
:text => options[:text],
|
|
148
|
+
:log_level => options[:log_level]
|
|
149
|
+
}
|
|
150
|
+
end
|
|
151
|
+
|
|
100
152
|
end
|
|
101
153
|
end
|
|
102
154
|
end
|
data/lib/fdlint/helper/logger.rb
CHANGED
data/lib/fdlint/log_entry.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
1
2
|
require 'colored'
|
|
2
3
|
|
|
3
4
|
module Fdlint
|
|
@@ -38,6 +39,19 @@ module Fdlint
|
|
|
38
39
|
validation && validation.long_desc
|
|
39
40
|
end
|
|
40
41
|
|
|
42
|
+
LEVEL_CONST = {
|
|
43
|
+
:warn => 1,
|
|
44
|
+
:error => 2,
|
|
45
|
+
:fatal => 3
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
def self.level_greater_or_equal?( a, b )
|
|
49
|
+
level_number(a) >= level_number(b)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def self.level_number( symb )
|
|
53
|
+
LEVEL_CONST[symb]
|
|
54
|
+
end
|
|
41
55
|
|
|
42
56
|
end
|
|
43
57
|
|
|
@@ -8,6 +8,7 @@ module Fdlint; module Parser; module HTML
|
|
|
8
8
|
class HtmlParser < ::Fdlint::Parser::BaseParser
|
|
9
9
|
|
|
10
10
|
include ::Fdlint::Parser::ParserVisitable
|
|
11
|
+
include ::Fdlint::Helper::Logger
|
|
11
12
|
|
|
12
13
|
def self.parse(src, &block)
|
|
13
14
|
parser = self.new(src)
|
|
@@ -33,13 +34,8 @@ module Fdlint; module Parser; module HTML
|
|
|
33
34
|
end
|
|
34
35
|
|
|
35
36
|
def parse_doc
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
when 0 then nil
|
|
39
|
-
when 1 then nodes[0]
|
|
40
|
-
else
|
|
41
|
-
::Fdlint::Parser::HTML::Document.new( nodes )
|
|
42
|
-
end
|
|
37
|
+
debug { "parse doc" }
|
|
38
|
+
::Fdlint::Parser::HTML::Document.new( batch(:parse_element) )
|
|
43
39
|
end
|
|
44
40
|
|
|
45
41
|
def parse_element
|
|
@@ -59,6 +55,7 @@ module Fdlint; module Parser; module HTML
|
|
|
59
55
|
end
|
|
60
56
|
|
|
61
57
|
def parse_dtd
|
|
58
|
+
debug { "parse dtd" }
|
|
62
59
|
node = scan(DTD)
|
|
63
60
|
DTDElement.new(@scanner[2], @scanner[1], node.position)
|
|
64
61
|
end
|
|
@@ -76,9 +73,10 @@ module Fdlint; module Parser; module HTML
|
|
|
76
73
|
text << "#{@scanner.scan(TEXT)}"
|
|
77
74
|
|
|
78
75
|
# TODO: make this detection a rule
|
|
79
|
-
parse_warn "'#{$~}' not escaped" if text =~ /<|>/
|
|
76
|
+
parse_warn "'#{$~}' not escaped" if text =~ /<|>/ && !@parsing_script
|
|
80
77
|
end
|
|
81
78
|
TextElement.new( text ).tap do |text|
|
|
79
|
+
text.scopes = scopes.dup
|
|
82
80
|
text.position = pos
|
|
83
81
|
end
|
|
84
82
|
end
|
|
@@ -165,9 +163,9 @@ module Fdlint; module Parser; module HTML
|
|
|
165
163
|
|
|
166
164
|
scopes.pop
|
|
167
165
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
166
|
+
Tag.new(tag, prop, children, close_type, ending).tap do |el|
|
|
167
|
+
el.scopes = scopes.dup
|
|
168
|
+
end
|
|
171
169
|
end
|
|
172
170
|
|
|
173
171
|
def scopes
|
|
@@ -183,7 +181,7 @@ module Fdlint; module Parser; module HTML
|
|
|
183
181
|
tag = scan(TAG_NAME)
|
|
184
182
|
prop = parse_properties
|
|
185
183
|
skip /\/>/
|
|
186
|
-
el =
|
|
184
|
+
el = Tag.new(tag, prop, [], :self)
|
|
187
185
|
el.scopes = scopes.dup
|
|
188
186
|
el
|
|
189
187
|
end
|
|
@@ -1,47 +1,37 @@
|
|
|
1
1
|
require 'strscan'
|
|
2
2
|
|
|
3
|
-
module
|
|
4
|
-
module HTML
|
|
3
|
+
module Fdlint; module Parser; module HTML
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
module Query
|
|
6
|
+
|
|
7
|
+
WORD = /[A-Za-z][-_\w]*/
|
|
8
|
+
CLASS = %r(\.#{WORD})
|
|
9
|
+
ID = %r(##{WORD})
|
|
10
|
+
PROP_PAIR = %r(\s*,?\s*#{WORD}(==[^\s,])?)
|
|
11
|
+
PROP = %r(\[#{WORD}.*?\])
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if v.nil?
|
|
34
|
-
return false unless has_prop? n
|
|
35
|
-
else
|
|
36
|
-
return false unless prop_value(n) == v
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
true
|
|
40
|
-
end
|
|
13
|
+
###
|
|
14
|
+
# This method implemented CSS selector for
|
|
15
|
+
# HTML (like Sizzle) very simply. It is not
|
|
16
|
+
# fully supported CSS selector.
|
|
17
|
+
#
|
|
18
|
+
# TODO: support full CSS3 selector
|
|
19
|
+
###
|
|
20
|
+
def match?(str)
|
|
21
|
+
query = query_obj(str)
|
|
22
|
+
tag_query = query[:tag]
|
|
23
|
+
class_query = query[:classes]
|
|
24
|
+
prop_query = query[:properties]
|
|
25
|
+
|
|
26
|
+
(tag_query.blank? || match_tag?( tag_query )) &&
|
|
27
|
+
(class_query.blank? || match_class?( class_query )) &&
|
|
28
|
+
(prop_query.blank? || match_prop?( prop_query ))
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
alias_method :===, :match?
|
|
41
32
|
|
|
42
|
-
|
|
33
|
+
private
|
|
43
34
|
|
|
44
|
-
private
|
|
45
35
|
def query_obj(str)
|
|
46
36
|
classes = []
|
|
47
37
|
props = {}
|
|
@@ -73,24 +63,48 @@ module XRay
|
|
|
73
63
|
{:tag => tag, :classes => classes, :properties => props }
|
|
74
64
|
end
|
|
75
65
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
66
|
+
def match_tag?( tag_query )
|
|
67
|
+
tag_name_equal? tag_query
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def match_class?( class_query )
|
|
71
|
+
classes = prop_value(:class)
|
|
72
|
+
if classes.blank?
|
|
73
|
+
false
|
|
74
|
+
else
|
|
75
|
+
class_query.all? do |c|
|
|
76
|
+
classes.include? c
|
|
77
|
+
end
|
|
82
78
|
end
|
|
79
|
+
end
|
|
83
80
|
|
|
84
|
-
|
|
85
|
-
|
|
81
|
+
def match_prop?( prop_query )
|
|
82
|
+
prop_query.all? do |n, v|
|
|
83
|
+
if v.nil?
|
|
84
|
+
has_prop? n
|
|
85
|
+
else
|
|
86
|
+
prop_value(n) == v
|
|
87
|
+
end
|
|
86
88
|
end
|
|
89
|
+
end
|
|
90
|
+
public
|
|
91
|
+
|
|
92
|
+
def query( selector, &block )
|
|
93
|
+
ret = []
|
|
94
|
+
if match?(selector)
|
|
95
|
+
ret << self
|
|
96
|
+
yield self if block_given?
|
|
97
|
+
end
|
|
87
98
|
|
|
88
|
-
|
|
99
|
+
children && children.each do |node|
|
|
100
|
+
ret += node.query(selector, &block)
|
|
89
101
|
end
|
|
90
|
-
|
|
91
|
-
alias_method :*, :query
|
|
92
102
|
|
|
103
|
+
ret
|
|
93
104
|
end
|
|
105
|
+
|
|
106
|
+
alias_method :*, :query
|
|
94
107
|
|
|
95
108
|
end
|
|
96
|
-
|
|
109
|
+
|
|
110
|
+
end; end; end
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
require 'fdlint/parser/html/query'
|
|
2
|
+
|
|
1
3
|
module Fdlint; module Parser
|
|
4
|
+
|
|
2
5
|
module HTML
|
|
3
6
|
|
|
4
7
|
Node = ::Fdlint::Parser::Node
|
|
@@ -12,9 +15,12 @@ module Fdlint; module Parser
|
|
|
12
15
|
input td ins time kbd var)
|
|
13
16
|
module Matchable
|
|
14
17
|
def =~ patten
|
|
18
|
+
name = respond_to?(:name) ? self.name :
|
|
19
|
+
respond_to?(:tag_name) ? tag_name :
|
|
20
|
+
nil
|
|
15
21
|
if name
|
|
16
22
|
case patten
|
|
17
|
-
when String
|
|
23
|
+
when String, Symbol
|
|
18
24
|
name =~ Regexp.new("^#{patten}$", Regexp::IGNORECASE)
|
|
19
25
|
when Regexp
|
|
20
26
|
name =~ patten
|
|
@@ -183,9 +189,12 @@ module Fdlint; module Parser
|
|
|
183
189
|
end
|
|
184
190
|
|
|
185
191
|
class Tag < Element
|
|
192
|
+
|
|
186
193
|
include Matchable
|
|
194
|
+
include ::Fdlint::Parser::HTML::Query
|
|
187
195
|
|
|
188
196
|
alias_method :name, :tag_name
|
|
197
|
+
alias_method :tag_name_equal?, :=~
|
|
189
198
|
end
|
|
190
199
|
|
|
191
200
|
class Document < Tag
|
|
@@ -215,6 +224,10 @@ module Fdlint; module Parser
|
|
|
215
224
|
|
|
216
225
|
alias_method :have_dtd?, :has_dtd?
|
|
217
226
|
|
|
227
|
+
def outer_html
|
|
228
|
+
children.map(&:outer_html).to_a.join
|
|
229
|
+
end
|
|
230
|
+
|
|
218
231
|
end
|
|
219
232
|
|
|
220
233
|
class TextElement < Tag
|
|
@@ -231,6 +244,10 @@ module Fdlint; module Parser
|
|
|
231
244
|
alias_method :inner_html, :text
|
|
232
245
|
alias_method :outer_html, :text
|
|
233
246
|
|
|
247
|
+
def match?( query )
|
|
248
|
+
false
|
|
249
|
+
end
|
|
250
|
+
|
|
234
251
|
def ==(other)
|
|
235
252
|
text == other.text
|
|
236
253
|
end
|
|
@@ -247,7 +264,7 @@ module Fdlint; module Parser
|
|
|
247
264
|
end
|
|
248
265
|
|
|
249
266
|
|
|
250
|
-
class CommentElement <
|
|
267
|
+
class CommentElement < Tag
|
|
251
268
|
def initialize(text)
|
|
252
269
|
super(nil)
|
|
253
270
|
@text = text.to_s
|
|
@@ -278,7 +295,7 @@ module Fdlint; module Parser
|
|
|
278
295
|
|
|
279
296
|
end
|
|
280
297
|
|
|
281
|
-
class DTDElement <
|
|
298
|
+
class DTDElement < Tag
|
|
282
299
|
|
|
283
300
|
attr_accessor :type
|
|
284
301
|
|
|
@@ -46,7 +46,7 @@ module Fdlint
|
|
|
46
46
|
alias_method old_method, method
|
|
47
47
|
|
|
48
48
|
define_method(method) do |*args, &block|
|
|
49
|
-
before name
|
|
49
|
+
before name
|
|
50
50
|
node = self.send(old_method, *args, &block)
|
|
51
51
|
node && visit(name, node)
|
|
52
52
|
node
|
|
@@ -74,8 +74,14 @@ module Fdlint
|
|
|
74
74
|
#
|
|
75
75
|
# Returns Parser's visitors
|
|
76
76
|
def add_visitors(visitors)
|
|
77
|
-
visitors.
|
|
78
|
-
|
|
77
|
+
if visitors.is_a? Array
|
|
78
|
+
visitors.each do |target, visitor|
|
|
79
|
+
add_visitor target, visitor
|
|
80
|
+
end
|
|
81
|
+
else
|
|
82
|
+
visitors.public_methods(false).grep(/^visit_/).map do |method|
|
|
83
|
+
add_visitor method.to_s.sub( /^visit_/, '' ), visitors.method( method )
|
|
84
|
+
end
|
|
79
85
|
end
|
|
80
86
|
self.visitors
|
|
81
87
|
end
|
|
@@ -110,13 +116,13 @@ module Fdlint
|
|
|
110
116
|
|
|
111
117
|
def visit(name, node)
|
|
112
118
|
walk(name, node) do |result|
|
|
113
|
-
results << result
|
|
119
|
+
results << result if result.present?
|
|
114
120
|
end
|
|
115
121
|
end
|
|
116
122
|
|
|
117
123
|
def before(name)
|
|
118
124
|
walk 'before_parse_' << name, nil do |result|
|
|
119
|
-
results << result
|
|
125
|
+
results << result if result.present?
|
|
120
126
|
end
|
|
121
127
|
end
|
|
122
128
|
|