fdlint 0.1.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.
Files changed (218) hide show
  1. data/Gemfile +8 -0
  2. data/Gemfile.lock +14 -0
  3. data/README.md +68 -0
  4. data/Rakefile +92 -0
  5. data/bin/fdlint +17 -0
  6. data/lib/base_parser.rb +143 -0
  7. data/lib/cmd_runner.rb +145 -0
  8. data/lib/context.rb +31 -0
  9. data/lib/css/parser.rb +186 -0
  10. data/lib/css/reader.rb +30 -0
  11. data/lib/css/rule/check_compression_rule.rb +48 -0
  12. data/lib/css/rule/checklist.rb +45 -0
  13. data/lib/css/struct.rb +111 -0
  14. data/lib/encoding_error.rb +6 -0
  15. data/lib/file_validator.rb +38 -0
  16. data/lib/helper/code_type.rb +50 -0
  17. data/lib/helper/color_string.rb +44 -0
  18. data/lib/helper/file_reader.rb +22 -0
  19. data/lib/helper/strenc.rb +65 -0
  20. data/lib/html/parser.rb +212 -0
  21. data/lib/html/query.rb +96 -0
  22. data/lib/html/rule/check_tag_rule.rb +80 -0
  23. data/lib/html/struct.rb +291 -0
  24. data/lib/js/expr/expr.rb +66 -0
  25. data/lib/js/expr/left_hand.rb +63 -0
  26. data/lib/js/expr/operate.rb +92 -0
  27. data/lib/js/expr/primary.rb +166 -0
  28. data/lib/js/parser.rb +116 -0
  29. data/lib/js/rule/all.rb +35 -0
  30. data/lib/js/rule/checklist.rb +41 -0
  31. data/lib/js/rule/file_checker.rb +42 -0
  32. data/lib/js/rule/helper.rb +96 -0
  33. data/lib/js/rule/no_global.rb +87 -0
  34. data/lib/js/stat/if.rb +25 -0
  35. data/lib/js/stat/iter.rb +85 -0
  36. data/lib/js/stat/stat.rb +117 -0
  37. data/lib/js/stat/switch.rb +65 -0
  38. data/lib/js/stat/try.rb +28 -0
  39. data/lib/js/stat/var.rb +40 -0
  40. data/lib/js/struct.rb +248 -0
  41. data/lib/log_entry.rb +49 -0
  42. data/lib/node.rb +28 -0
  43. data/lib/parse_error.rb +13 -0
  44. data/lib/parser_visitable.rb +138 -0
  45. data/lib/position_info.rb +46 -0
  46. data/lib/printer/base_printer.rb +24 -0
  47. data/lib/printer/console_printer.rb +66 -0
  48. data/lib/printer/nocolor_printer.rb +27 -0
  49. data/lib/printer/vim_printer.rb +19 -0
  50. data/lib/rule.rb +241 -0
  51. data/lib/rule_helper.rb +14 -0
  52. data/lib/runner.rb +225 -0
  53. data/rules.d/css.rule +127 -0
  54. data/rules.d/html.dtd.rule +22 -0
  55. data/rules.d/html.prop.rule +51 -0
  56. data/rules.d/html.tag.rule +136 -0
  57. data/rules.d/js.file.rule +13 -0
  58. data/rules.d/js.jquery.rule +56 -0
  59. data/rules.d/js.mergefile.rule +71 -0
  60. data/rules.d/js.rule +84 -0
  61. data/test/all_tests.rb +84 -0
  62. data/test/cli/cli_test.rb +70 -0
  63. data/test/cli/log_level_test.rb +51 -0
  64. data/test/cli/output_format_test.rb +47 -0
  65. data/test/cli/type_test.rb +77 -0
  66. data/test/css/mac_line_end_support_test.rb +38 -0
  67. data/test/css/parser_test.rb +276 -0
  68. data/test/css/rule/check_encoding_test.rb +66 -0
  69. data/test/css/rule/check_list_rule_test.rb +167 -0
  70. data/test/css/rule/compression_test.rb +53 -0
  71. data/test/css/rule/file_name_test.rb +76 -0
  72. data/test/fixtures/css/broken.css +4 -0
  73. data/test/fixtures/css/cbu/36.css +52 -0
  74. data/test/fixtures/css/cbu/china_top.css +324 -0
  75. data/test/fixtures/css/cbu/default-merge.css +3 -0
  76. data/test/fixtures/css/cbu/default.css +13 -0
  77. data/test/fixtures/css/cbu/diy-merge.css +25 -0
  78. data/test/fixtures/css/cbu/fns-v1.css +27 -0
  79. data/test/fixtures/css/cbu/index_v0.1.css +12 -0
  80. data/test/fixtures/css/cbu/merge.css +11 -0
  81. data/test/fixtures/css/cbu/min.css +2 -0
  82. data/test/fixtures/css/cbu/my_home_admin.css +126 -0
  83. data/test/fixtures/css/cbu/nav.css +95 -0
  84. data/test/fixtures/css/cbu/pic_list.css +386 -0
  85. data/test/fixtures/css/cbu/quote-edit.css +18 -0
  86. data/test/fixtures/css/cbu/selloffer.shopwindow.css +1 -0
  87. data/test/fixtures/css/cbu/v1.css +9 -0
  88. data/test/fixtures/css/css3.css +30 -0
  89. data/test/fixtures/css/empty-min.css +0 -0
  90. data/test/fixtures/css/empty.css +0 -0
  91. data/test/fixtures/css/font-family.css +4 -0
  92. data/test/fixtures/css/gb-good.css +14 -0
  93. data/test/fixtures/css/gb_using_star.css +4 -0
  94. data/test/fixtures/css/import.css +18 -0
  95. data/test/fixtures/css/mac-line-sep-err-min.css +1 -0
  96. data/test/fixtures/css/mac-line-sep-err.css +1 -0
  97. data/test/fixtures/css/mac-line-sep-good-min.css +1 -0
  98. data/test/fixtures/css/mac-line-sep-good.css +1 -0
  99. data/test/fixtures/css/multi-encoding-in-a-file.css +0 -0
  100. data/test/fixtures/css/simple.css +1 -0
  101. data/test/fixtures/css/using_expr.css +8 -0
  102. data/test/fixtures/css/using_hack.css +21 -0
  103. data/test/fixtures/css/using_id.css +1 -0
  104. data/test/fixtures/css/using_star.css +4 -0
  105. data/test/fixtures/css/utf8_good.css +6 -0
  106. data/test/fixtures/css/utf8_good_declaring_charset.css +7 -0
  107. data/test/fixtures/css/utf8_using_star.css +5 -0
  108. data/test/fixtures/html/1-1.html +120 -0
  109. data/test/fixtures/html/1-2.html +120 -0
  110. data/test/fixtures/html/cms.html +373 -0
  111. data/test/fixtures/html/css_out_of_head.html +9 -0
  112. data/test/fixtures/html/fdev-template.html +22 -0
  113. data/test/fixtures/html/google.com.html +33 -0
  114. data/test/fixtures/html/mixed_log_levels.html +4 -0
  115. data/test/fixtures/html/mixed_types.html +13 -0
  116. data/test/fixtures/html/no_dtd.html +6 -0
  117. data/test/fixtures/html/readme.html +94 -0
  118. data/test/fixtures/html/review.board.html +163 -0
  119. data/test/fixtures/html/syntax_err.html +3 -0
  120. data/test/fixtures/html/train/detail/345/233/276/346/226/207/347/273/223/345/220/210.html +208 -0
  121. data/test/fixtures/html/train/detail/347/232/204Flash.html +212 -0
  122. data/test/fixtures/html/train/detail/347/232/204Vedio.html +212 -0
  123. data/test/fixtures/html/train/index.html +37 -0
  124. data/test/fixtures/html/train/test.html +1 -0
  125. data/test/fixtures/html/train//344/277/256/346/224/271/344/270/200/347/272/247/345/210/206/347/261/273.html +112 -0
  126. data/test/fixtures/html/train//344/277/256/346/224/271/345/255/220/345/210/206/347/261/273.html +108 -0
  127. data/test/fixtures/html/train//344/277/256/346/224/271/350/257/276/347/250/213.html +195 -0
  128. data/test/fixtures/html/train//345/215/232/345/256/242/350/256/276/347/275/256.html +142 -0
  129. data/test/fixtures/html/train//346/265/217/350/247/210/350/256/260/345/275/225.html +191 -0
  130. data/test/fixtures/html/train//346/267/273/345/212/240/344/270/200/347/272/247/345/210/206/347/261/273.html +113 -0
  131. data/test/fixtures/html/train//346/267/273/345/212/240/345/255/220/345/210/206/347/261/273.html +112 -0
  132. data/test/fixtures/html/train//346/267/273/345/212/240/350/257/276/347/250/213.html +195 -0
  133. data/test/fixtures/html/train//347/231/273/345/275/225.html +20 -0
  134. data/test/fixtures/html/train//347/256/241/347/220/206/345/210/206/347/261/273.html +210 -0
  135. data/test/fixtures/html/train//347/256/241/347/220/206/345/217/215/351/246/210.html +222 -0
  136. data/test/fixtures/html/train//347/256/241/347/220/206/350/257/276/347/250/213.html +284 -0
  137. data/test/fixtures/html/train//347/256/241/347/220/206/350/264/246/346/210/267.html +107 -0
  138. data/test/fixtures/html/train//347/275/221/344/270/212/345/237/271/350/256/255home/351/241/265.html +354 -0
  139. data/test/fixtures/html/train//347/275/221/345/225/206/345/237/271/350/256/255list/351/241/265.html +255 -0
  140. data/test/fixtures/html/train//350/256/276/347/275/256/351/246/226/351/241/265/346/216/250/350/215/220.html +168 -0
  141. data/test/fixtures/html/train//350/257/264/346/230/216.txt +3 -0
  142. data/test/fixtures/html/train//351/246/226/351/241/265/345/271/277/345/221/212/350/256/276/347/275/256.html +297 -0
  143. data/test/fixtures/html/unescaped.html +2 -0
  144. data/test/fixtures/html/view.vm +916 -0
  145. data/test/fixtures/js/jquery-1.7.js +9300 -0
  146. data/test/fixtures/js/scope-test.js +22 -0
  147. data/test/helper.rb +41 -0
  148. data/test/html/mixed_type_test.rb +35 -0
  149. data/test/html/parser/parse_comment_test.rb +47 -0
  150. data/test/html/parser/parse_dtd_test.rb +46 -0
  151. data/test/html/parser/parse_script_tag_test.rb +55 -0
  152. data/test/html/parser/parse_with_auto_close_tag_test.rb +41 -0
  153. data/test/html/parser/parse_with_diff_case_test.rb +38 -0
  154. data/test/html/parser/parse_with_emtpy_test.rb +22 -0
  155. data/test/html/parser/parse_with_multi_children_test.rb +27 -0
  156. data/test/html/parser/parse_with_multi_line_test.rb +41 -0
  157. data/test/html/parser/parse_with_prop_test.rb +88 -0
  158. data/test/html/parser/parse_with_script_tag_test.rb +26 -0
  159. data/test/html/parser/parse_with_selfclosing_test.rb +39 -0
  160. data/test/html/parser/parse_with_simple_tag_test.rb +44 -0
  161. data/test/html/parser/parse_with_simple_tree_test.rb +40 -0
  162. data/test/html/parser/parse_with_style_tag_test.rb +22 -0
  163. data/test/html/parser/parse_with_text_test.rb +45 -0
  164. data/test/html/parser_test.rb +52 -0
  165. data/test/html/query_test.rb +52 -0
  166. data/test/html/rule/check_block_level_element_test.rb +52 -0
  167. data/test/html/rule/check_button_test.rb +45 -0
  168. data/test/html/rule/check_class_count_test.rb +36 -0
  169. data/test/html/rule/check_css_in_head_test.rb +53 -0
  170. data/test/html/rule/check_dtd_test.rb +46 -0
  171. data/test/html/rule/check_form_element_name_test.rb +49 -0
  172. data/test/html/rule/check_head_contain_meta_and_title_test.rb +52 -0
  173. data/test/html/rule/check_html_template_test.rb +103 -0
  174. data/test/html/rule/check_hyperlink_with_target_test.rb +40 -0
  175. data/test/html/rule/check_hyperlink_with_title_test.rb +43 -0
  176. data/test/html/rule/check_id_n_class_downcase_test.rb +40 -0
  177. data/test/html/rule/check_img_with_alt_prop_test.rb +33 -0
  178. data/test/html/rule/check_no_import_css_test.rb +36 -0
  179. data/test/html/rule/check_prop_have_value_test.rb +32 -0
  180. data/test/html/rule/check_prop_seperator_test.rb +32 -0
  181. data/test/html/rule/check_style_prop_test.rb +30 -0
  182. data/test/html/rule/check_tag_closed_test.rb +59 -0
  183. data/test/html/rule/check_tag_downcase_test.rb +51 -0
  184. data/test/html/rule/check_unescape_char_test.rb +35 -0
  185. data/test/html/rule/check_unique_import_test.rb +56 -0
  186. data/test/html/rule_test.rb +62 -0
  187. data/test/js/expr/expr.rb +57 -0
  188. data/test/js/expr/left_hand.rb +25 -0
  189. data/test/js/expr/operate.rb +145 -0
  190. data/test/js/expr/primary.rb +89 -0
  191. data/test/js/parser_test.rb +98 -0
  192. data/test/js/rule/alert_check_test.rb +37 -0
  193. data/test/js/rule/all_test.rb +23 -0
  194. data/test/js/rule/base_test.rb +34 -0
  195. data/test/js/rule/file_checker_test.rb +131 -0
  196. data/test/js/rule/jq_check_test.rb +90 -0
  197. data/test/js/rule/nest_try_catch_test.rb +71 -0
  198. data/test/js/rule/new_object_and_new_array_test.rb +38 -0
  199. data/test/js/rule/no_eval_test.rb +34 -0
  200. data/test/js/rule/no_global_test.rb +88 -0
  201. data/test/js/rule/private_method_check_test.rb +58 -0
  202. data/test/js/rule/semicolon_test.rb +63 -0
  203. data/test/js/rule/stat_if_with_brace_test.rb +68 -0
  204. data/test/js/rule/stat_if_with_muti_else_test.rb +68 -0
  205. data/test/js/rule/use_strict_equal_test.rb +44 -0
  206. data/test/js/rule_test.rb +47 -0
  207. data/test/js/stat/if.rb +26 -0
  208. data/test/js/stat/iter.rb +115 -0
  209. data/test/js/stat/stat.rb +91 -0
  210. data/test/js/stat/switch.rb +37 -0
  211. data/test/js/stat/try.rb +32 -0
  212. data/test/js/stat/var.rb +38 -0
  213. data/test/parser_visitable_test.rb +102 -0
  214. data/test/position_info_test.rb +66 -0
  215. data/test/rule_dsl/dsl_basic_test.rb +91 -0
  216. data/test/rule_dsl/importing_test.rb +48 -0
  217. data/test/runner/log_level_test.rb +58 -0
  218. metadata +317 -0
@@ -0,0 +1,166 @@
1
+ module XRay
2
+ module JS
3
+ module Expr
4
+
5
+ module Primary
6
+
7
+ R_IDENTIFY = /[a-zA-Z_$][\w$]*/
8
+
9
+ RESERVED_WORDS = %w(
10
+ break case catch continue debugger default delete do else
11
+ finally for function if in instanceof new return switch this
12
+ throw try typeof var void while with
13
+ class const enum export extends import super
14
+ implements interface let package private protected public static yield
15
+ null true false
16
+ )
17
+
18
+ R_THIS_NULL_BOOLEAN = /(?:this|null|true|false)\b/
19
+ R_HEX = /0[xX]/
20
+ R_NUMBERIC = /[+-]?(?:\d|(?:[.]\d))/
21
+ R_STRING = /['"]/
22
+ R_REGEXP = /\/[^\/]/
23
+
24
+ def parse_expr_primary
25
+ log "parse expr primary"
26
+ if check /\(/
27
+ parse_expr_parentheses
28
+
29
+ elsif check /\[/
30
+ parse_expr_array
31
+
32
+ elsif check /\{/
33
+ parse_expr_object
34
+
35
+ # literal
36
+ elsif check R_THIS_NULL_BOOLEAN
37
+ parse_expr_literal_this_null_boolean
38
+
39
+ elsif check R_HEX
40
+ parse_expr_literal_hex
41
+
42
+ elsif check R_NUMBERIC
43
+ parse_expr_literal_number
44
+
45
+ elsif check R_STRING
46
+ parse_expr_literal_string
47
+
48
+ elsif check R_REGEXP
49
+ parse_expr_literal_regexp
50
+ #~
51
+
52
+ else
53
+ parse_expr_identifier
54
+ end
55
+ end
56
+
57
+ def parse_expr_parentheses
58
+ log 'parse expr parentheses'
59
+
60
+ pos = skip /\(/
61
+ expr = parse_expression
62
+ skip /\)/
63
+
64
+ create_expression 'parentheses', expr, pos
65
+ end
66
+
67
+ def parse_expr_array
68
+ log 'parse expr array'
69
+
70
+ pos = skip /\[/
71
+ elms = batch(:parse_expr_assignment, /\]/, /,/)
72
+ skip /\]/
73
+
74
+ create_expression 'array', Elements.new(elms), pos
75
+ end
76
+
77
+ def parse_expr_object
78
+ log 'parse expr object'
79
+
80
+ pos = skip /\{/
81
+ elms = batch(:parse_expr_object_item, /\}/, /,/)
82
+ skip /\}/
83
+
84
+ create_expression 'object', Elements.new(elms), pos
85
+ end
86
+
87
+ def parse_expr_object_item
88
+ log 'parse expr object item'
89
+
90
+ name = if check R_STRING
91
+ parse_expr_literal_string
92
+ elsif check R_NUMBERIC
93
+ parse_expr_literal_number
94
+ else
95
+ parse_expr_identifier
96
+ end
97
+
98
+ skip /:/
99
+ value = parse_expr_assignment
100
+
101
+ Expression.new ':', name, value
102
+ end
103
+
104
+ def parse_expr_identifier
105
+ log 'parse expr identifier'
106
+
107
+ id = scan(R_IDENTIFY)
108
+ RESERVED_WORDS.include?(id.text) ?
109
+ parse_error("identifier can not be reserved word: #{id}") : id
110
+
111
+ create_expression 'id', id
112
+ end
113
+
114
+ def parse_expr_literal_this_null_boolean
115
+ log 'parse expr literal this null boolean'
116
+ expr = scan /this|null|true|false/
117
+ type = expr.text.gsub(/true|false/, 'boolean')
118
+
119
+ create_expression type, expr
120
+ end
121
+
122
+ def parse_expr_literal_string
123
+ log 'parse expr literal string'
124
+
125
+ expr = if check /'/
126
+ scan /'(?:(?:\\')|(?:\\\n)|[^'\n])*'/
127
+ elsif check /"/
128
+ scan /"(?:(?:\\")|(?:\\\n)|[^"\n])*"/
129
+ else
130
+ raise 'assert false'
131
+ end
132
+
133
+ create_expression 'string', expr
134
+ end
135
+
136
+ def parse_expr_literal_hex
137
+ log 'parse expr literal hex'
138
+ expr = scan /0[xX][0-9a-fA-F]+/
139
+ create_expression 'number', expr
140
+ end
141
+
142
+ def parse_expr_literal_number
143
+ log 'parse expr literal number'
144
+ expr = scan /[+-]?(?:(?:\d*[.]\d+)|(?:\d+))(?:[eE][+-]?\d+)?/
145
+ create_expression 'number', expr
146
+ end
147
+
148
+ def parse_expr_literal_regexp
149
+ log 'parse expr literal regexp'
150
+ expr = scan %r{/(?:(?:\\.)|(?:\[(?:\\.|[^\[\]])+\])|[^/\\])+/[a-z]*}
151
+ create_expression 'regexp', expr
152
+ end
153
+
154
+ private
155
+
156
+ def create_expression(*args)
157
+ expr = PrimaryExpression.new *args
158
+ log " #{expr}"
159
+ expr
160
+ end
161
+
162
+ end
163
+
164
+ end
165
+ end
166
+ end
data/lib/js/parser.rb ADDED
@@ -0,0 +1,116 @@
1
+ require_relative '../base_parser'
2
+ require_relative 'struct'
3
+
4
+ require_relative 'expr/expr'
5
+ require_relative 'stat/stat'
6
+
7
+
8
+ module XRay
9
+ module JS
10
+
11
+ class Parser < XRay::BaseParser
12
+
13
+ include Expr::Expr
14
+ include Stat::Stat
15
+
16
+ attr_reader :singleline_comments, :mutiline_comments
17
+
18
+ def initialize(js, logger)
19
+ super js, logger
20
+ @singleline_comments, @mutiline_comments = [], []
21
+ end
22
+
23
+ def parse_program
24
+ log 'parse program'
25
+ parse_comments
26
+ Program.new parse_source_elements
27
+ end
28
+
29
+ alias_method :parse, :parse_program
30
+
31
+ def parse_source_element
32
+ log 'parse source_element'
33
+
34
+ check(/function\b/) ? parse_function_declaration : parse_statement
35
+ end
36
+
37
+ def parse_function_declaration(skip_name = false)
38
+ log 'parse function declaration'
39
+
40
+ pos = skip /function/
41
+
42
+ name = (skip_name && check(/\(/)) ? nil : parse_function_name
43
+ skip /\(/
44
+ params = parse_function_parameters
45
+ skip /\)\s*\{/
46
+ body = parse_source_elements true
47
+ skip /\}/
48
+
49
+ FunctionDeclaraion.new name, params, body, pos
50
+ end
51
+
52
+ def parse_function_name
53
+ parse_expr_identifier
54
+ end
55
+
56
+ def parse_function_parameters
57
+ Elements.new batch(:parse_expr_identifier, /\)/, /,/)
58
+ end
59
+
60
+ def parse_singleline_comment
61
+ log 'parse singleline comment'
62
+ comment = raw_scan /\/\/.*/
63
+ log " #{comment}"
64
+ comment
65
+ end
66
+
67
+ def parse_mutiline_comment
68
+ log 'parse mutiline comment'
69
+ comment = raw_scan /\/\*[^*]*\*+([^\/*][^*]*\*+)*\//
70
+ log " #{comment}"
71
+ comment
72
+ end
73
+
74
+ protected
75
+
76
+ def create_element(klass, *args)
77
+ elm = klass.new *args
78
+ log " #{elm.text} #{elm.position}"
79
+ elm
80
+ end
81
+
82
+ #override
83
+ def after_scan(pattern)
84
+ parse_comments
85
+ end
86
+
87
+ def after_skip(pattern)
88
+ parse_comments
89
+ end
90
+
91
+ private
92
+
93
+ def parse_source_elements(inner = false)
94
+ elms = batch(:parse_source_element) do
95
+ skip_empty
96
+ inner ? !check(/\}/) : !eos?
97
+ end
98
+ Elements.new elms
99
+ end
100
+
101
+ def parse_comments
102
+ while true
103
+ if check /\/\//
104
+ @singleline_comments << parse_singleline_comment
105
+ elsif check /\/\*/
106
+ @mutiline_comments << parse_mutiline_comment
107
+ else
108
+ break
109
+ end
110
+ end
111
+ end
112
+
113
+ end
114
+
115
+ end
116
+ end
@@ -0,0 +1,35 @@
1
+ require 'delegate'
2
+
3
+ module XRay
4
+ module JS
5
+ module Rule
6
+
7
+ class All < SimpleDelegator
8
+
9
+ attr_reader :rules
10
+
11
+ def initialize(options = {})
12
+ @rules = load_sub_rules.collect do |name|
13
+ klass = Rule.const_get name
14
+ klass.method(:initialize).arity >= 1 ? klass.new(options) :
15
+ klass.new
16
+ end
17
+
18
+ super @rules
19
+ end
20
+
21
+ def load_sub_rules
22
+ Dir.glob File.expand_path( '*.rb', File.dirname(__FILE__) ) do |file|
23
+ require file
24
+ end
25
+ XRay::JS::Rule.constants.select { |c| c.to_s.end_with? 'Rule' }
26
+ end
27
+
28
+
29
+ end
30
+
31
+ end
32
+ end
33
+ end
34
+
35
+
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+ require_relative 'helper'
3
+ require_relative '../../rule'
4
+
5
+ module XRay
6
+ module JS
7
+ module Rule
8
+
9
+ class ChecklistRule
10
+
11
+ include XRay::JS::Rule::Helper, XRay::Rule
12
+
13
+ def visit_statement(stat)
14
+ check_js_statement stat
15
+ end
16
+
17
+ def visit_stat_if(stat)
18
+ check_js_stat_if stat
19
+ end
20
+
21
+ def visit_expr_member(expr)
22
+ check_js_expr_member expr
23
+ end
24
+
25
+ def visit_expr_new(expr)
26
+ check_js_expr_new expr
27
+ end
28
+
29
+ def visit_expr_equal(expr)
30
+ check_js_expr_equal expr
31
+ end
32
+
33
+ def visit_stat_try(stat)
34
+ check_js_stat_try stat
35
+ end
36
+
37
+ end
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,42 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative '../../helper/file_reader'
4
+ require_relative 'helper'
5
+ require_relative '../../rule'
6
+
7
+
8
+ module XRay
9
+ module JS
10
+ module Rule
11
+
12
+ class FileChecker
13
+
14
+ include Helper, XRay::Rule
15
+
16
+ def check_file(path)
17
+ src = readfile(path)
18
+ ret = results_to_logs check_js_file( path, src )
19
+
20
+ if merge_file? path
21
+ pathes = grep_import_js_path( src )
22
+ ret.concat results_to_logs( check_js_merge_file( path, src, pathes ) )
23
+ ret.concat results_to_logs( check_merge_imports( pathes, path ) )
24
+ end
25
+ ret
26
+ end
27
+
28
+ def check_merge_imports( pathes, path )
29
+ ret = []
30
+ pathes.each do |import|
31
+ r = check_js_merge_importing import, pathes, path
32
+ ret.concat r
33
+ end
34
+ ret
35
+ end
36
+
37
+
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,96 @@
1
+ module XRay
2
+ module JS
3
+ module Rule
4
+
5
+ module Helper
6
+ def find_expr_member(expr)
7
+ while expr.is_a?(Expression) && !yield(expr)
8
+ expr = expr.left
9
+ end
10
+ expr && expr.is_a?(Expression) && yield(expr) ? expr : nil
11
+ end
12
+
13
+ def has_doc_comment?(body)
14
+ body =~ /^\s*\/\*\*[^*]*\*+([^\/*][^*]*\*+)*\//
15
+ end
16
+
17
+ def readfile(path)
18
+ text, encoding = XRay::Helper::FileReader.readfile path
19
+ text
20
+ end
21
+
22
+ def merge_file?(path)
23
+ return path =~ /\w+-merge([-_]?\d+)?\.js$/
24
+ end
25
+
26
+ def min_file?(path)
27
+ return path =~ /\w+-min\.js$/
28
+ end
29
+
30
+ def func_file?(path)
31
+ !merge_file?(path) and !min_file?(path)
32
+ end
33
+
34
+ def grep_import_js_path(body)
35
+ lines = body.split /\n/
36
+ pattern = /(ImportJavscript\s*\.\s*url\s*\(\s*['"]?([^'"]+)['"]?\s*\)\s*;?)/
37
+
38
+ pathes = []
39
+ lines.each_with_index do |line, index|
40
+ line.scan(pattern) do |text, url|
41
+ pathes << {
42
+ :text => text,
43
+ :url => url,
44
+ :row => index + 1,
45
+ :col => Regexp.last_match.begin(0) + 1
46
+ }
47
+ end
48
+ end
49
+ pathes
50
+ end
51
+
52
+
53
+ def scope(path)
54
+ parts = path.split(/\\\//)
55
+ if parts.include? 'global'
56
+ :global
57
+ elsif parts.include? 'page'
58
+ :page
59
+ elsif parts.include? 'lib' or parts.include? 'sys'
60
+ :lib
61
+ end
62
+ end
63
+
64
+ def global_scope?( path )
65
+ scope(path) == :global
66
+ end
67
+
68
+ def page_scope?( path )
69
+ scope(path) == :page
70
+ end
71
+
72
+ def lib_scope?( path )
73
+ scope(path) == :lib
74
+ end
75
+
76
+ def relative?( path )
77
+ path !~ %r(^https?://)
78
+ end
79
+
80
+ def app( path )
81
+ sep = /(?:\\|\/)/
82
+ path[/#{sep}app#{sep}(.*?)#{sep}(?:.+#{sep})*(global|page|module)(?:\\|\/)/, 1]
83
+ end
84
+
85
+ def results_to_logs( results )
86
+ results.map do |r|
87
+ msg, level, row, column = *r
88
+ LogEntry.new(msg, level, row || 0, column || 0)
89
+ end
90
+ end
91
+ end
92
+
93
+ end
94
+ end
95
+ end
96
+
@@ -0,0 +1,87 @@
1
+ # encoding: utf-8
2
+
3
+ module XRay
4
+ module JS
5
+ module Rule
6
+
7
+ class NoGlobalRule
8
+
9
+ def visit_stat_var(stat)
10
+ unless @scope_index > 0
11
+ ['不允许使用全局变量', :error]
12
+ end
13
+ end
14
+
15
+ def visit_stat_var_declaration(dec)
16
+ scope = current_scope
17
+ scope << dec.left.text
18
+ nil
19
+ end
20
+
21
+ def visit_function_name(name)
22
+ current_scope << name.text
23
+ ['不允许申明全局函数', :error] if @scope_index == 0
24
+ end
25
+
26
+ def visit_function_parameters(params)
27
+ @scope_index = (@scope_index || 0) + 1
28
+ scope = current_scope(true)
29
+ params.each do |param|
30
+ scope << param.text
31
+ end
32
+ nil
33
+ end
34
+
35
+ def visit_stat_for(stat)
36
+ first = stat.condition.first
37
+ nil
38
+ end
39
+
40
+ def visit_function_declaration(fun)
41
+ @scope_index -= 1
42
+ nil
43
+ end
44
+
45
+ def visit_expr_assignment(expr)
46
+ if expr.type == '='
47
+ id = find_assignment_id(expr.left)
48
+
49
+ if id && use_id_global?(id.text)
50
+ ['禁止使用未定义的变量(或全局变量)', :error]
51
+ end
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def current_scope(empty = false)
58
+ @scopes ||= []
59
+ @scope_index ||= 0
60
+ @scopes[@scope_index] = [] if empty
61
+ @scopes[@scope_index] ||= []
62
+ end
63
+
64
+ def find_assignment_id(expr)
65
+ expr.type == 'id' ? expr :
66
+ expr.type == '.' && expr.left.text == 'window' &&
67
+ expr.right.type == 'id' ? expr.right : nil
68
+ end
69
+
70
+ def use_id_global?(id)
71
+ white_list = %w(ImportJavscript)
72
+
73
+ return false if white_list.include? id
74
+ return true unless @scopes && @scope_index
75
+
76
+ @scope_index.downto(0) do |index|
77
+ scope = @scopes[index]
78
+ return false if scope && scope.find { |name| name == id}
79
+ end
80
+ true
81
+ end
82
+
83
+ end
84
+
85
+ end
86
+ end
87
+ end
data/lib/js/stat/if.rb ADDED
@@ -0,0 +1,25 @@
1
+ module XRay
2
+ module JS
3
+ module Stat
4
+
5
+ module If
6
+ def parse_stat_if
7
+ log 'parse stat if'
8
+
9
+ pos = skip /if\s*\(/
10
+ condition = parse_expression
11
+ skip /\)/
12
+
13
+ true_part = parse_statement
14
+ false_part = if check /else\b/
15
+ skip /else/
16
+ parse_statement
17
+ end
18
+
19
+ create_element IfStatement, condition, true_part, false_part, pos
20
+ end
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,85 @@
1
+ module XRay
2
+ module JS
3
+ module Stat
4
+
5
+ module Iter
6
+
7
+ def parse_stat_dowhile
8
+ log 'parse stat dowhile'
9
+
10
+ pos = skip /do/
11
+ body = parse_statement
12
+
13
+ skip /while\s*\(/
14
+ condition = parse_expression
15
+ skip /\)/
16
+
17
+ create_element DowhileStatement, body, condition, pos
18
+ end
19
+
20
+ def parse_stat_while
21
+ log 'parse stat while'
22
+
23
+ pos = skip /while\s*\(/
24
+ condition = parse_expression
25
+ skip /\)/
26
+ body = parse_statement
27
+
28
+ create_element WhileStatement, condition, body, pos
29
+ end
30
+
31
+ def parse_stat_for
32
+ log 'parse stat for'
33
+
34
+ pos = skip /for/
35
+
36
+ con_pos = skip /\(/
37
+ first, is_var = parse_stat_for_con_first
38
+ type, second, third = parse_stat_for_con_other(first, is_var)
39
+ skip /\)/
40
+
41
+ condition = create_element ForConditionElement, type, first, second, third, con_pos
42
+ body = parse_statement
43
+ create_element ForStatement, condition, body, pos
44
+ end
45
+
46
+ private
47
+
48
+ def parse_stat_for_con_first
49
+ self.expr_operate_not_in = true
50
+ first = if check /var\b/
51
+ skip /var/
52
+ is_var = true
53
+ parse_stat_var_declarationlist
54
+ elsif !check(/;/)
55
+ parse_expression
56
+ end
57
+ self.expr_operate_not_in = false
58
+ [first, is_var]
59
+ end
60
+
61
+ def parse_stat_for_con_other(first, is_var)
62
+ if check /in\b/
63
+ if is_var && first.length != 1 || !is_var && !first.left_hand?
64
+ parse_error('first expression of for-condtion error')
65
+ end
66
+
67
+ skip /in/
68
+ type = is_var ? 'forvarin' : 'forin'
69
+ second = parse_expression
70
+ else
71
+ skip /;/
72
+ type = is_var ? 'forvar' : 'fordefault'
73
+ second = check(/;/) ? nil : parse_expression
74
+ skip /;/
75
+
76
+ third = check(/\)/) ? nil : parse_expression
77
+ end
78
+ [type, second, third]
79
+ end
80
+
81
+ end
82
+
83
+ end
84
+ end
85
+ end