fdlint 0.1.3 → 0.2.0.pre
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 +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
|