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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d9d6d40f7557d99e016ca0dfe7949ff1fa69d856
|
4
|
+
data.tar.gz: 558d82918d7b4f6e1b4901fa69201e5e7539056d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 50b3ac1298038655d9fd0a89295f22d865780f79528f9b77ed65f47d967ee07d13aa1ecb2d156b53ffc82db4939c94660bdb1c02191232b024138ad4e27333e6
|
7
|
+
data.tar.gz: 3f44299dbd47fdca59e2dbe0c5b6769f287bd20d865338f40669d41540479e4c024f2cd5b39a48e9958040e3daee29f32b46f04e5df248e0efd8331e80f74051
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,15 +1,25 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
fdlint (0.2.0.pre)
|
5
|
+
colored (~> 1.2)
|
6
|
+
gli (~> 2.9.0)
|
7
|
+
string_utf8 (~> 0.1.1)
|
8
|
+
|
1
9
|
GEM
|
2
10
|
remote: https://rubygems.org/
|
3
11
|
specs:
|
4
|
-
|
12
|
+
colored (1.2)
|
13
|
+
gli (2.9.0)
|
5
14
|
rake (0.9.2.2)
|
15
|
+
string_utf8 (0.1.1)
|
6
16
|
test-unit (2.4.8)
|
7
17
|
|
8
18
|
PLATFORMS
|
9
19
|
ruby
|
10
20
|
|
11
21
|
DEPENDENCIES
|
12
|
-
|
13
|
-
|
22
|
+
bundler
|
23
|
+
fdlint!
|
24
|
+
rake (~> 0.9.2.2)
|
14
25
|
test-unit
|
15
|
-
win32console
|
data/Rakefile
CHANGED
@@ -1,92 +1,16 @@
|
|
1
|
-
|
1
|
+
require 'rake/clean'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rubygems/package_task'
|
2
4
|
|
3
|
-
|
4
|
-
task :test do
|
5
|
-
require_relative 'test/all_tests'
|
6
|
-
end
|
7
|
-
|
8
|
-
|
9
|
-
require "rubygems"
|
10
|
-
require "rubygems/package_task"
|
11
|
-
require "rdoc/task"
|
12
|
-
|
13
|
-
require "rake/testtask"
|
14
|
-
Rake::TestTask.new do |t|
|
15
|
-
t.libs << "test"
|
16
|
-
t.test_files = FileList["test/**/*_test.rb"]
|
17
|
-
t.verbose = true
|
18
|
-
end
|
19
|
-
|
20
|
-
|
21
|
-
task :default => ["test"]
|
22
|
-
|
23
|
-
# This builds the actual gem. For details of what all these options
|
24
|
-
# mean, and other ones you can add, check the documentation here:
|
25
|
-
#
|
26
|
-
# http://rubygems.org/read/chapter/20
|
27
|
-
#
|
28
|
-
spec = Gem::Specification.new do |s|
|
29
|
-
|
30
|
-
# Change these as appropriate
|
31
|
-
s.name = "fdlint"
|
32
|
-
s.version = "0.1.3"
|
33
|
-
s.summary = "Code reviewer for web developing. Check your HTML/JS/CSS codes against bad codes."
|
34
|
-
s.author = "qhwa,bencode"
|
35
|
-
s.email = "qhwa@163.com,bencode@163.com"
|
36
|
-
s.homepage = "https://github.com/qhwa/fdlint"
|
5
|
+
spec = eval(File.read('fdlint.gemspec'))
|
37
6
|
|
38
|
-
s.has_rdoc = false
|
39
|
-
s.extra_rdoc_files = %w(README.md)
|
40
|
-
s.rdoc_options = %w(--main README.md)
|
41
|
-
|
42
|
-
# Add any extra files to include in the gem
|
43
|
-
s.files = %w(README.md Rakefile Gemfile.lock Gemfile) +
|
44
|
-
Dir.glob("{bin,test,lib,rules.d}/**/*") -
|
45
|
-
Dir.glob("test/fixtures/html/{cms,tmp}/**/*")
|
46
|
-
s.executables = FileList["bin/**"].map { |f| File.basename(f) }
|
47
|
-
s.require_paths = ["lib"]
|
48
|
-
|
49
|
-
# If you want to depend on other gems, add them here, along with any
|
50
|
-
# relevant versions
|
51
|
-
#s.add_dependency("win32console")
|
52
|
-
|
53
|
-
# If your tests use any gems, include them here
|
54
|
-
s.add_development_dependency("rake")
|
55
|
-
s.add_development_dependency("test-unit")
|
56
|
-
end
|
57
|
-
|
58
|
-
# This task actually builds the gem. We also regenerate a static
|
59
|
-
# .gemspec file, which is useful if something (i.e. GitHub) will
|
60
|
-
# be automatically building a gem for this project. If you're not
|
61
|
-
# using GitHub, edit as appropriate.
|
62
|
-
#
|
63
|
-
# To publish your gem online, install the 'gemcutter' gem; Read more
|
64
|
-
# about that here: http://gemcutter.org/pages/gem_docs
|
65
7
|
Gem::PackageTask.new(spec) do |pkg|
|
66
|
-
pkg.gem_spec = spec
|
67
8
|
end
|
68
9
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
end
|
74
|
-
|
75
|
-
# If you don't want to generate the .gemspec file, just remove this line. Reasons
|
76
|
-
# why you might want to generate a gemspec:
|
77
|
-
# - using bundler with a git source
|
78
|
-
# - building the gem without rake (i.e. gem build blah.gemspec)
|
79
|
-
# - maybe others?
|
80
|
-
task :package => :gemspec
|
81
|
-
|
82
|
-
# Generate documentation
|
83
|
-
RDoc::Task.new do |rd|
|
84
|
-
rd.main = "README.md"
|
85
|
-
rd.rdoc_files.include("README.md", "lib/**/*.rb")
|
86
|
-
rd.rdoc_dir = "rdoc"
|
10
|
+
require 'rake/testtask'
|
11
|
+
Rake::TestTask.new do |t|
|
12
|
+
t.libs << "test"
|
13
|
+
t.test_files = FileList['test/*_test.rb']
|
87
14
|
end
|
88
15
|
|
89
|
-
|
90
|
-
task :clean => [:clobber_rdoc, :clobber_package] do
|
91
|
-
rm "#{spec.name}.gemspec"
|
92
|
-
end
|
16
|
+
task :default => [:test,:features]
|
data/bin/fdlint
CHANGED
@@ -1,14 +1,77 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
require 'gli'
|
3
|
+
begin # XXX: Remove this begin/rescue before distributing your app
|
4
|
+
require 'fdlint'
|
5
|
+
require 'fdlint/cli'
|
6
|
+
rescue LoadError
|
7
|
+
STDERR.puts "In development, you need to use `bundle exec bin/fdlint` to run your app"
|
8
|
+
STDERR.puts "At install-time, RubyGems will make sure lib, etc. are in the load path"
|
9
|
+
STDERR.puts "Feel free to remove this message from bin/fdlint now"
|
10
|
+
exit 64
|
11
|
+
end
|
12
|
+
|
13
|
+
include GLI::App
|
14
|
+
|
15
|
+
program_desc 'Code reviewer for web developing. Check your HTML/JS/CSS codes against bad smells.'
|
16
|
+
|
17
|
+
version Fdlint::VERSION
|
18
|
+
|
19
|
+
desc 'Print debug logs'
|
20
|
+
switch [:d, :debug], negatable: false
|
21
|
+
|
22
|
+
desc "review codes"
|
23
|
+
arg_name 'path'
|
24
|
+
command [:review, :check] do |c|
|
25
|
+
|
26
|
+
%w(css js html).each do |type|
|
27
|
+
c.desc "check #{type} files only"
|
28
|
+
c.switch type.intern, negatable: false
|
29
|
+
end
|
30
|
+
|
31
|
+
c.desc "output format. Can be 'vim', 'console' or 'nocolor'."
|
32
|
+
c.default_value :console
|
33
|
+
c.flag :format, must_match: %w[console nocolor vim]
|
2
34
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
35
|
+
c.desc "ignore minified files"
|
36
|
+
c.default_value false
|
37
|
+
c.switch [:m, :"ignore-min"], negatable: false
|
38
|
+
|
39
|
+
c.desc "shortcut for '--format=list'"
|
40
|
+
c.switch [:l, :list], negatable: false
|
41
|
+
|
42
|
+
c.desc "charset for reading files"
|
43
|
+
c.default_value 'utf-8'
|
44
|
+
c.flag [:c, :charset]
|
45
|
+
|
46
|
+
c.desc "the log level for filter results"
|
47
|
+
c.default_value 'warn'
|
48
|
+
c.flag [:loglevel], must_match: %s[warn error faltal]
|
49
|
+
|
50
|
+
c.action do |global, opt, args|
|
51
|
+
|
52
|
+
if args.empty?
|
53
|
+
if $stdin.tty?
|
54
|
+
help_now! 'files required'
|
55
|
+
else
|
56
|
+
source = ARGF.read
|
57
|
+
end
|
7
58
|
end
|
59
|
+
|
60
|
+
options = {
|
61
|
+
|
62
|
+
:log_level => opt[:loglevel],
|
63
|
+
:format => opt[:list] ? :nocolor : opt[:format],
|
64
|
+
:encoding => opt[:encoding],
|
65
|
+
:syntax => opt[:css] ? :css :
|
66
|
+
opt[:js] ? :js :
|
67
|
+
opt[:html] ? :html : nil,
|
68
|
+
:debug => global[:debug],
|
69
|
+
:files => args,
|
70
|
+
:text => source
|
71
|
+
}
|
72
|
+
|
73
|
+
Fdlint::CLI.run options
|
8
74
|
end
|
9
75
|
end
|
10
76
|
|
11
|
-
|
12
|
-
|
13
|
-
trap("SIGINT") { puts "\nGoodbye!"; exit! }
|
14
|
-
XRay::CMDRunner.run
|
77
|
+
exit run(ARGV)
|
data/lib/fdlint/cli.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
require 'find'
|
4
|
+
require 'logger'
|
5
|
+
require 'fdlint/printer'
|
6
|
+
require 'fdlint/printer/vim_printer'
|
7
|
+
require 'fdlint/printer/nocolor_printer'
|
8
|
+
require 'fdlint/printer/console_printer'
|
9
|
+
|
10
|
+
module Fdlint
|
11
|
+
|
12
|
+
module CLI
|
13
|
+
|
14
|
+
def self.run( options )
|
15
|
+
Runner.new( options ).run
|
16
|
+
end
|
17
|
+
|
18
|
+
class Runner
|
19
|
+
|
20
|
+
attr_reader :options, :files
|
21
|
+
|
22
|
+
def initialize( options={} )
|
23
|
+
@options = options
|
24
|
+
@files = options[:files]
|
25
|
+
end
|
26
|
+
|
27
|
+
def run
|
28
|
+
# Windows 下默认是ANSI编码
|
29
|
+
# 我们需要使用 UTF-8 编码输出
|
30
|
+
IO.popen "chcp 65001" if ENV['OS'] =~ /windows/i
|
31
|
+
|
32
|
+
$logger = Logger.new(STDOUT).tap do |l|
|
33
|
+
l.level = options[:debug] ? Logger::DEBUG : Logger::FATAL
|
34
|
+
end
|
35
|
+
|
36
|
+
trap("SIGINT") { puts "\nGoodbye!"; exit! }
|
37
|
+
|
38
|
+
if text = @options[:text]
|
39
|
+
validate_content
|
40
|
+
elsif !@files.empty?
|
41
|
+
validate_files
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
protected
|
46
|
+
|
47
|
+
def validate_content
|
48
|
+
opt_for_validator = {
|
49
|
+
:code_type => options[:code_type],
|
50
|
+
:text => options[:text]
|
51
|
+
}
|
52
|
+
::Fdlint::Validator.new( nil, opt_for_validator ).validate do |file, source, results|
|
53
|
+
printer.print( file, source, results )
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def validate_files
|
58
|
+
files.each do |file|
|
59
|
+
validate_path file do |file, source, results|
|
60
|
+
printer.print( file, source, results )
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def validate_path( path, &block )
|
66
|
+
if File.directory? path
|
67
|
+
validate_directory path
|
68
|
+
else
|
69
|
+
validate_file path
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def validate_directory( dir )
|
74
|
+
Find.find dir do |f|
|
75
|
+
validate_file f unless File.directory? f
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def validate_file( path )
|
80
|
+
::Fdlint::Validator.new( path ).validate do |file, source, results|
|
81
|
+
printer.print( file, source, results )
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def printer
|
88
|
+
@printer ||= printer_for( @options[:format] )
|
89
|
+
end
|
90
|
+
|
91
|
+
def printer_for format
|
92
|
+
mapping = {
|
93
|
+
:console => ::Fdlint::Printer::ConsolePrinter.new,
|
94
|
+
:nocolor => ::Fdlint::Printer::NoColorPrinter.new,
|
95
|
+
:vim => ::Fdlint::Printer::VimPrinter.new
|
96
|
+
}.tap {|hash| hash.default = hash[:console] }
|
97
|
+
mapping[format]
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
File without changes
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Fdlint
|
2
|
+
module Helper
|
3
|
+
|
4
|
+
class CodeType
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def guess(text, filename=nil)
|
9
|
+
if filename && !filename.empty?
|
10
|
+
guess_by_name filename
|
11
|
+
else
|
12
|
+
guess_by_content text
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def guess_by_name( filename )
|
17
|
+
case File.extname( filename )
|
18
|
+
when /\.css$/i
|
19
|
+
:css
|
20
|
+
when /\.js$/i
|
21
|
+
:js
|
22
|
+
else
|
23
|
+
:html #TODO: support more suffix
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def guess_by_content(text)
|
28
|
+
return :html if html? text
|
29
|
+
return :css if css? text
|
30
|
+
:js #TODO: support more code syntaxes
|
31
|
+
end
|
32
|
+
|
33
|
+
def style_file?(filename)
|
34
|
+
File.extname( filename ) =~ /(css|js|html?)$/i
|
35
|
+
end
|
36
|
+
|
37
|
+
def scope(filename)
|
38
|
+
filename =~ /[\\\/]lib[\\\/]/ ? 'lib' : 'page'
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def html?(text)
|
44
|
+
/^\s*</m =~ text
|
45
|
+
end
|
46
|
+
|
47
|
+
def css?(text)
|
48
|
+
/^\s*@/m =~ text or /^\s*([-\*:\.#_\w]+\s*)+\{/ =~ text
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'string/utf8'
|
2
|
+
|
3
|
+
module Fdlint
|
4
|
+
module Helper
|
5
|
+
module FileReader
|
6
|
+
extend self
|
7
|
+
|
8
|
+
# auto detect file encoding and read it.
|
9
|
+
# return with an array containing string
|
10
|
+
# and encoding
|
11
|
+
def readfile(path, opt={})
|
12
|
+
bin = File.read(path).utf8!
|
13
|
+
raise EncodingError.new unless bin.valid_encoding?
|
14
|
+
bin
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Fdlint; module Helper
|
4
|
+
|
5
|
+
# Public: Module Logger handles the in-application
|
6
|
+
# runtime logging. It helps user inspect
|
7
|
+
# details of application running.
|
8
|
+
module Logger
|
9
|
+
|
10
|
+
LEVELS = [:debug, :info, :warn, :error, :fatal]
|
11
|
+
|
12
|
+
# Public: log message with specificated log level
|
13
|
+
#
|
14
|
+
# msg - the message text to log
|
15
|
+
# level - debug / info / warn / error / fatal
|
16
|
+
#
|
17
|
+
# Returns nil
|
18
|
+
def log( msg, level = :info )
|
19
|
+
level = :info unless LEVELS.include?( level )
|
20
|
+
send level, msg
|
21
|
+
end
|
22
|
+
|
23
|
+
LEVELS.each do |method|
|
24
|
+
define_method method do |*args, &block|
|
25
|
+
logger.send method, *args, &block
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def logger
|
30
|
+
$logger ||= ::Logger.new(STDOUT)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end; end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'colored'
|
2
|
+
|
3
|
+
module Fdlint
|
4
|
+
|
5
|
+
class LogEntry < Struct.new(:message, :level, :row, :column)
|
6
|
+
|
7
|
+
attr_accessor :validation
|
8
|
+
|
9
|
+
def initialize(message, level, row = 0, colmn = 0)
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
"[#{level.to_s.upcase}] #{pos} #{message}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def pos
|
18
|
+
row.nil? ? "" : "[#{row},#{column}]"
|
19
|
+
end
|
20
|
+
|
21
|
+
def error?
|
22
|
+
level == :error
|
23
|
+
end
|
24
|
+
|
25
|
+
def warn?
|
26
|
+
level == :warn
|
27
|
+
end
|
28
|
+
|
29
|
+
def fatal?
|
30
|
+
level == :fatal
|
31
|
+
end
|
32
|
+
|
33
|
+
def info?
|
34
|
+
level == :info
|
35
|
+
end
|
36
|
+
|
37
|
+
def desc
|
38
|
+
validation && validation.long_desc
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
class InvalidFileEncoding < LogEntry
|
45
|
+
def initialize
|
46
|
+
super "文件编码错误,无法正常读取", :fatal
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'fdlint/parser/node'
|
2
|
+
require 'fdlint/parser/parse_error'
|
3
|
+
require 'fdlint/parser/position_info'
|
4
|
+
require 'strscan'
|
5
|
+
|
6
|
+
module Fdlint
|
7
|
+
|
8
|
+
module Parser
|
9
|
+
|
10
|
+
class BaseParser
|
11
|
+
|
12
|
+
include ::Fdlint::Helper::Logger
|
13
|
+
|
14
|
+
attr_reader :source
|
15
|
+
|
16
|
+
def initialize(text)
|
17
|
+
@source = text
|
18
|
+
text = filter_text(prepare_text(text))
|
19
|
+
@pos_info = PositionInfo.new text
|
20
|
+
@scanner = StringScanner.new text
|
21
|
+
@text_size = text.size
|
22
|
+
end
|
23
|
+
|
24
|
+
def skip_empty
|
25
|
+
@scanner.skip(/\s*/)
|
26
|
+
end
|
27
|
+
|
28
|
+
def skip(pattern, not_skip_empty = false)
|
29
|
+
not_skip_empty || skip_empty
|
30
|
+
pos = scanner_pos
|
31
|
+
unless @scanner.skip pattern
|
32
|
+
parse_error pattern
|
33
|
+
end
|
34
|
+
after_skip pattern
|
35
|
+
pos
|
36
|
+
end
|
37
|
+
|
38
|
+
def scanner_pos
|
39
|
+
pos = @text_size - @scanner.rest.size
|
40
|
+
@pos_info.locate pos
|
41
|
+
end
|
42
|
+
|
43
|
+
def check(pattern, not_skip_empty = false)
|
44
|
+
skip_empty = !not_skip_empty
|
45
|
+
if skip_empty && @scanner.check(/\s+/)
|
46
|
+
last_pos = @scanner.pos
|
47
|
+
@scanner.skip /\s+/
|
48
|
+
end
|
49
|
+
ret = @scanner.check pattern
|
50
|
+
@scanner.pos = last_pos if last_pos
|
51
|
+
ret
|
52
|
+
end
|
53
|
+
|
54
|
+
def scan(pattern, not_skip_empty = false)
|
55
|
+
node = raw_scan pattern, not_skip_empty
|
56
|
+
after_scan pattern
|
57
|
+
node
|
58
|
+
end
|
59
|
+
|
60
|
+
def raw_scan(pattern, not_skip_empty = false)
|
61
|
+
not_skip_empty || skip_empty
|
62
|
+
pos = scanner_pos
|
63
|
+
text = @scanner.scan pattern
|
64
|
+
text ? Node.new(text, pos) : parse_error(pattern)
|
65
|
+
end
|
66
|
+
|
67
|
+
def batch(name, stop = nil, skip_pattern = nil, not_skip_empty = false, &block)
|
68
|
+
first = true
|
69
|
+
result = []
|
70
|
+
while !@scanner.eos? &&
|
71
|
+
(stop ? batch_check(stop, skip_pattern, not_skip_empty, first) :
|
72
|
+
block ? block.call : true) &&
|
73
|
+
item = send(name)
|
74
|
+
result << item
|
75
|
+
first = false
|
76
|
+
end
|
77
|
+
result
|
78
|
+
end
|
79
|
+
|
80
|
+
def to_s
|
81
|
+
self.class.to_s
|
82
|
+
end
|
83
|
+
|
84
|
+
def reset
|
85
|
+
@scanner.reset
|
86
|
+
end
|
87
|
+
|
88
|
+
def eos?
|
89
|
+
@scanner.eos?
|
90
|
+
end
|
91
|
+
|
92
|
+
def scanned_source
|
93
|
+
pos = @text_size - @scanner.rest.size
|
94
|
+
source[0..(pos-1)]
|
95
|
+
end
|
96
|
+
|
97
|
+
def rest_source
|
98
|
+
@scanner.rest
|
99
|
+
end
|
100
|
+
|
101
|
+
protected
|
102
|
+
|
103
|
+
def filter_text(text)
|
104
|
+
text
|
105
|
+
end
|
106
|
+
|
107
|
+
def after_skip(pattern)
|
108
|
+
end
|
109
|
+
|
110
|
+
def after_scan(pattern)
|
111
|
+
end
|
112
|
+
|
113
|
+
def parse_warn(message)
|
114
|
+
pos = scanner_pos
|
115
|
+
log "#{message}#{pos}", :warn
|
116
|
+
end
|
117
|
+
|
118
|
+
def parse_error(pattern)
|
119
|
+
if pattern.respond_to?(:source)
|
120
|
+
message = "should be #{pattern.source} here"
|
121
|
+
else
|
122
|
+
message = pattern.to_s
|
123
|
+
end
|
124
|
+
pos = scanner_pos
|
125
|
+
log "#{message} #{pos}", :error
|
126
|
+
raise ParseError.new(message, pos)
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
def prepare_text(text)
|
132
|
+
if text.respond_to? :encode!
|
133
|
+
text.encode! 'utf-8', :invalid => :replace, :universal_newline => true
|
134
|
+
else
|
135
|
+
text.gsub(/\r\n/, "\n").gsub(/\r/, "\n")
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def batch_check(stop, skip_pattern, not_skip_empty, first)
|
140
|
+
if check stop, not_skip_empty
|
141
|
+
false
|
142
|
+
else
|
143
|
+
!first && skip_pattern && skip(skip_pattern)
|
144
|
+
true
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
end
|