yamlint 0.1.0 → 1.0.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/.rubocop.yml +31 -9
- data/.serena/.gitignore +1 -0
- data/.serena/memories/project_overview.md +25 -0
- data/.serena/memories/style_and_conventions.md +7 -0
- data/.serena/memories/suggested_commands.md +17 -0
- data/.serena/memories/task_completion.md +5 -0
- data/.serena/project.yml +89 -0
- data/CHANGELOG.md +6 -2
- data/Gemfile +9 -7
- data/LICENSE.txt +1 -1
- data/README.md +155 -17
- data/Rakefile +10 -3
- data/docs/Yamlint/Cli.html +403 -0
- data/docs/Yamlint/Config.html +1034 -0
- data/docs/Yamlint/Formatter.html +433 -0
- data/docs/Yamlint/Linter.html +423 -0
- data/docs/Yamlint/Models/LintContext.html +993 -0
- data/docs/Yamlint/Models/Problem.html +951 -0
- data/docs/Yamlint/Models/Token.html +713 -0
- data/docs/Yamlint/Models.html +117 -0
- data/docs/Yamlint/Output/Base.html +290 -0
- data/docs/Yamlint/Output/Colored.html +293 -0
- data/docs/Yamlint/Output/Github.html +260 -0
- data/docs/Yamlint/Output/Parsable.html +258 -0
- data/docs/Yamlint/Output/Standard.html +270 -0
- data/docs/Yamlint/Output.html +208 -0
- data/docs/Yamlint/Parser/Comment.html +795 -0
- data/docs/Yamlint/Parser/CommentExtractor.html +287 -0
- data/docs/Yamlint/Parser/LineParser.html +423 -0
- data/docs/Yamlint/Parser/TokenParser/Handler.html +910 -0
- data/docs/Yamlint/Parser/TokenParser.html +291 -0
- data/docs/Yamlint/Parser.html +117 -0
- data/docs/Yamlint/Presets.html +266 -0
- data/docs/Yamlint/Rules/Anchors/AnchorHandler.html +678 -0
- data/docs/Yamlint/Rules/Anchors.html +314 -0
- data/docs/Yamlint/Rules/Base.html +968 -0
- data/docs/Yamlint/Rules/Braces.html +335 -0
- data/docs/Yamlint/Rules/Brackets.html +335 -0
- data/docs/Yamlint/Rules/Colons.html +313 -0
- data/docs/Yamlint/Rules/Commas.html +313 -0
- data/docs/Yamlint/Rules/CommentRule.html +298 -0
- data/docs/Yamlint/Rules/Comments.html +317 -0
- data/docs/Yamlint/Rules/CommentsIndentation.html +328 -0
- data/docs/Yamlint/Rules/DocumentEnd.html +332 -0
- data/docs/Yamlint/Rules/DocumentStart.html +332 -0
- data/docs/Yamlint/Rules/EmptyLines.html +300 -0
- data/docs/Yamlint/Rules/EmptyValues.html +273 -0
- data/docs/Yamlint/Rules/FloatValues.html +383 -0
- data/docs/Yamlint/Rules/Hyphens.html +337 -0
- data/docs/Yamlint/Rules/Indentation.html +329 -0
- data/docs/Yamlint/Rules/KeyDuplicates/DuplicateKeyHandler.html +716 -0
- data/docs/Yamlint/Rules/KeyDuplicates.html +258 -0
- data/docs/Yamlint/Rules/KeyOrdering/KeyOrderHandler.html +694 -0
- data/docs/Yamlint/Rules/KeyOrdering.html +258 -0
- data/docs/Yamlint/Rules/LineLength.html +251 -0
- data/docs/Yamlint/Rules/LineRule.html +304 -0
- data/docs/Yamlint/Rules/NewLineAtEndOfFile.html +308 -0
- data/docs/Yamlint/Rules/NewLines.html +310 -0
- data/docs/Yamlint/Rules/OctalValues.html +270 -0
- data/docs/Yamlint/Rules/QuotedStrings.html +381 -0
- data/docs/Yamlint/Rules/Registry.html +492 -0
- data/docs/Yamlint/Rules/TokenRule.html +298 -0
- data/docs/Yamlint/Rules/TrailingSpaces.html +321 -0
- data/docs/Yamlint/Rules/Truthy.html +288 -0
- data/docs/Yamlint/Rules.html +190 -0
- data/docs/Yamlint/Runner.html +551 -0
- data/docs/Yamlint.html +135 -0
- data/docs/_index.html +643 -0
- data/docs/class_list.html +54 -0
- data/docs/css/common.css +1 -0
- data/docs/css/full_list.css +58 -0
- data/docs/css/style.css +490 -0
- data/docs/file.README.html +276 -0
- data/docs/file_list.html +59 -0
- data/docs/frames.html +22 -0
- data/docs/index.html +276 -0
- data/docs/js/app.js +395 -0
- data/docs/js/full_list.js +244 -0
- data/docs/js/jquery.js +4 -0
- data/docs/method_list.html +1582 -0
- data/docs/top-level-namespace.html +110 -0
- data/exe/yamlint +7 -0
- data/lib/yamlint/cli.rb +162 -0
- data/lib/yamlint/config.rb +113 -0
- data/lib/yamlint/formatter.rb +140 -0
- data/lib/yamlint/linter.rb +130 -0
- data/lib/yamlint/models/lint_context.rb +43 -0
- data/lib/yamlint/models/problem.rb +44 -0
- data/lib/yamlint/models/token.rb +22 -0
- data/lib/yamlint/models.rb +9 -0
- data/lib/yamlint/output/base.rb +15 -0
- data/lib/yamlint/output/colored.rb +54 -0
- data/lib/yamlint/output/github.rb +20 -0
- data/lib/yamlint/output/parsable.rb +19 -0
- data/lib/yamlint/output/standard.rb +25 -0
- data/lib/yamlint/output.rb +26 -0
- data/lib/yamlint/parser/comment_extractor.rb +78 -0
- data/lib/yamlint/parser/line_parser.rb +30 -0
- data/lib/yamlint/parser/token_parser.rb +92 -0
- data/lib/yamlint/parser.rb +10 -0
- data/lib/yamlint/presets/default.rb +35 -0
- data/lib/yamlint/presets/relaxed.rb +34 -0
- data/lib/yamlint/presets.rb +19 -0
- data/lib/yamlint/rules/anchors.rb +133 -0
- data/lib/yamlint/rules/base.rb +102 -0
- data/lib/yamlint/rules/braces.rb +105 -0
- data/lib/yamlint/rules/brackets.rb +105 -0
- data/lib/yamlint/rules/colons.rb +73 -0
- data/lib/yamlint/rules/commas.rb +85 -0
- data/lib/yamlint/rules/comments.rb +77 -0
- data/lib/yamlint/rules/comments_indentation.rb +66 -0
- data/lib/yamlint/rules/document_end.rb +45 -0
- data/lib/yamlint/rules/document_start.rb +45 -0
- data/lib/yamlint/rules/empty_lines.rb +107 -0
- data/lib/yamlint/rules/empty_values.rb +43 -0
- data/lib/yamlint/rules/float_values.rb +67 -0
- data/lib/yamlint/rules/hyphens.rb +42 -0
- data/lib/yamlint/rules/indentation.rb +39 -0
- data/lib/yamlint/rules/key_duplicates.rb +127 -0
- data/lib/yamlint/rules/key_ordering.rb +126 -0
- data/lib/yamlint/rules/line_length.rb +57 -0
- data/lib/yamlint/rules/new_line_at_end_of_file.rb +31 -0
- data/lib/yamlint/rules/new_lines.rb +59 -0
- data/lib/yamlint/rules/octal_values.rb +62 -0
- data/lib/yamlint/rules/quoted_strings.rb +73 -0
- data/lib/yamlint/rules/registry.rb +48 -0
- data/lib/yamlint/rules/trailing_spaces.rb +31 -0
- data/lib/yamlint/rules/truthy.rb +48 -0
- data/lib/yamlint/rules.rb +41 -0
- data/lib/yamlint/runner.rb +80 -0
- data/lib/yamlint/version.rb +1 -1
- data/lib/yamlint.rb +11 -3
- metadata +131 -11
- data/CODE_OF_CONDUCT.md +0 -84
- data/sig/yamlint.rbs +0 -4
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yamlint
|
|
4
|
+
module Models
|
|
5
|
+
class Problem
|
|
6
|
+
attr_reader :line, :column, :rule, :level, :message, :fixable
|
|
7
|
+
|
|
8
|
+
LEVELS = %i[error warning info].freeze
|
|
9
|
+
|
|
10
|
+
def initialize(line:, column:, rule:, level:, message:, fixable: false)
|
|
11
|
+
@line = line
|
|
12
|
+
@column = column
|
|
13
|
+
@rule = rule
|
|
14
|
+
@level = validate_level(level)
|
|
15
|
+
@message = message
|
|
16
|
+
@fixable = fixable
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def error?
|
|
20
|
+
@level == :error
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def warning?
|
|
24
|
+
@level == :warning
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def fixable?
|
|
28
|
+
@fixable
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def to_s
|
|
32
|
+
"#{line}:#{column} [#{level}] #{message} (#{rule})"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def validate_level(level)
|
|
38
|
+
return level if LEVELS.include?(level)
|
|
39
|
+
|
|
40
|
+
raise ArgumentError, "Invalid level: #{level}. Must be one of #{LEVELS.join(', ')}"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yamlint
|
|
4
|
+
module Models
|
|
5
|
+
class Token
|
|
6
|
+
attr_reader :type, :value, :start_line, :start_column, :end_line, :end_column
|
|
7
|
+
|
|
8
|
+
def initialize(type:, start_line:, start_column:, value: nil, end_line: nil, end_column: nil)
|
|
9
|
+
@type = type
|
|
10
|
+
@value = value
|
|
11
|
+
@start_line = start_line
|
|
12
|
+
@start_column = start_column
|
|
13
|
+
@end_line = end_line || start_line
|
|
14
|
+
@end_column = end_column || start_column
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def to_s
|
|
18
|
+
"#{type}(#{start_line}:#{start_column})"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yamlint
|
|
4
|
+
module Output
|
|
5
|
+
class Base
|
|
6
|
+
def format(filepath, problems)
|
|
7
|
+
raise NotImplementedError, "#{self.class}#format must be implemented"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def format_summary(total_files, total_problems)
|
|
11
|
+
raise NotImplementedError, "#{self.class}#format_summary must be implemented"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yamlint
|
|
4
|
+
module Output
|
|
5
|
+
class Colored < Base
|
|
6
|
+
COLORS = {
|
|
7
|
+
reset: "\e[0m",
|
|
8
|
+
bold: "\e[1m",
|
|
9
|
+
red: "\e[31m",
|
|
10
|
+
yellow: "\e[33m",
|
|
11
|
+
cyan: "\e[36m",
|
|
12
|
+
dim: "\e[2m"
|
|
13
|
+
}.freeze
|
|
14
|
+
|
|
15
|
+
def format(filepath, problems)
|
|
16
|
+
return '' if problems.empty?
|
|
17
|
+
|
|
18
|
+
lines = ["#{COLORS[:bold]}#{filepath}#{COLORS[:reset]}"]
|
|
19
|
+
problems.each do |problem|
|
|
20
|
+
lines << format_problem(problem)
|
|
21
|
+
end
|
|
22
|
+
lines.join("\n")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def format_summary(total_files, total_problems)
|
|
26
|
+
if total_problems.zero?
|
|
27
|
+
format_success_summary(total_files)
|
|
28
|
+
else
|
|
29
|
+
format_failure_summary(total_files, total_problems)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def format_problem(problem)
|
|
36
|
+
color = problem.error? ? COLORS[:red] : COLORS[:yellow]
|
|
37
|
+
pos = "#{COLORS[:dim]}#{problem.line}:#{problem.column}#{COLORS[:reset]}"
|
|
38
|
+
level = "#{color}#{problem.level}#{COLORS[:reset]}"
|
|
39
|
+
rule = "#{COLORS[:cyan]}(#{problem.rule})#{COLORS[:reset]}"
|
|
40
|
+
" #{pos} #{level} #{problem.message} #{rule}"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def format_success_summary(total_files)
|
|
44
|
+
"#{COLORS[:bold]}#{total_files}#{COLORS[:reset]} file(s) checked, " \
|
|
45
|
+
"#{COLORS[:bold]}no problems found#{COLORS[:reset]}"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def format_failure_summary(total_files, total_problems)
|
|
49
|
+
"#{COLORS[:bold]}#{total_files}#{COLORS[:reset]} file(s) checked, " \
|
|
50
|
+
"#{COLORS[:red]}#{total_problems} problem(s) found#{COLORS[:reset]}"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yamlint
|
|
4
|
+
module Output
|
|
5
|
+
class Github < Base
|
|
6
|
+
def format(filepath, problems)
|
|
7
|
+
return '' if problems.empty?
|
|
8
|
+
|
|
9
|
+
problems.map do |problem|
|
|
10
|
+
type = problem.error? ? 'error' : 'warning'
|
|
11
|
+
"::#{type} file=#{filepath},line=#{problem.line},col=#{problem.column}::#{problem.message} (#{problem.rule})"
|
|
12
|
+
end.join("\n")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def format_summary(_total_files, _total_problems)
|
|
16
|
+
''
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yamlint
|
|
4
|
+
module Output
|
|
5
|
+
class Parsable < Base
|
|
6
|
+
def format(filepath, problems)
|
|
7
|
+
return '' if problems.empty?
|
|
8
|
+
|
|
9
|
+
problems.map do |problem|
|
|
10
|
+
"#{filepath}:#{problem.line}:#{problem.column}: [#{problem.level}] #{problem.message} (#{problem.rule})"
|
|
11
|
+
end.join("\n")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def format_summary(_total_files, _total_problems)
|
|
15
|
+
''
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yamlint
|
|
4
|
+
module Output
|
|
5
|
+
class Standard < Base
|
|
6
|
+
def format(filepath, problems)
|
|
7
|
+
return '' if problems.empty?
|
|
8
|
+
|
|
9
|
+
lines = [filepath]
|
|
10
|
+
problems.each do |problem|
|
|
11
|
+
lines << " #{problem.line}:#{problem.column} #{problem.level} #{problem.message} (#{problem.rule})"
|
|
12
|
+
end
|
|
13
|
+
lines.join("\n")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def format_summary(total_files, total_problems)
|
|
17
|
+
if total_problems.zero?
|
|
18
|
+
"#{total_files} file(s) checked, no problems found"
|
|
19
|
+
else
|
|
20
|
+
"#{total_files} file(s) checked, #{total_problems} problem(s) found"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yamlint
|
|
4
|
+
module Output
|
|
5
|
+
autoload :Base, 'yamlint/output/base'
|
|
6
|
+
autoload :Standard, 'yamlint/output/standard'
|
|
7
|
+
autoload :Parsable, 'yamlint/output/parsable'
|
|
8
|
+
autoload :Colored, 'yamlint/output/colored'
|
|
9
|
+
autoload :Github, 'yamlint/output/github'
|
|
10
|
+
|
|
11
|
+
def self.get(format)
|
|
12
|
+
case format.to_s
|
|
13
|
+
when 'standard'
|
|
14
|
+
Standard.new
|
|
15
|
+
when 'parsable'
|
|
16
|
+
Parsable.new
|
|
17
|
+
when 'colored', 'auto'
|
|
18
|
+
Colored.new
|
|
19
|
+
when 'github'
|
|
20
|
+
Github.new
|
|
21
|
+
else
|
|
22
|
+
raise ArgumentError, "Unknown output format: #{format}"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yamlint
|
|
4
|
+
module Parser
|
|
5
|
+
class Comment
|
|
6
|
+
attr_reader :line_number, :column, :text, :inline
|
|
7
|
+
|
|
8
|
+
def initialize(line_number:, column:, text:, inline: false)
|
|
9
|
+
@line_number = line_number
|
|
10
|
+
@column = column
|
|
11
|
+
@text = text
|
|
12
|
+
@inline = inline
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def inline?
|
|
16
|
+
@inline
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def disable_directive?
|
|
20
|
+
@text.match?(/yamllint\s+disable(-line)?/)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def enable_directive?
|
|
24
|
+
@text.match?(/yamllint\s+enable/)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def disabled_rules
|
|
28
|
+
if (match = @text.match(/yamllint\s+disable(-line)?\s+(.+)/))
|
|
29
|
+
match[2].split(/[,\s]+/).map(&:strip).reject(&:empty?)
|
|
30
|
+
else
|
|
31
|
+
[]
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class CommentExtractor
|
|
37
|
+
COMMENT_PATTERN = /#(.*)$/
|
|
38
|
+
|
|
39
|
+
def initialize(content)
|
|
40
|
+
@content = content
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def extract
|
|
44
|
+
comments = []
|
|
45
|
+
@content.lines.each_with_index do |line, index|
|
|
46
|
+
line_number = index + 1
|
|
47
|
+
extract_comments_from_line(line, line_number, comments)
|
|
48
|
+
end
|
|
49
|
+
comments
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def extract_comments_from_line(line, line_number, comments)
|
|
55
|
+
return if in_string?(line)
|
|
56
|
+
|
|
57
|
+
if (match = line.match(COMMENT_PATTERN))
|
|
58
|
+
column = match.begin(0) + 1
|
|
59
|
+
text = match[1].strip
|
|
60
|
+
inline = column > 1 && !line[0...(column - 1)].strip.empty?
|
|
61
|
+
|
|
62
|
+
comments << Comment.new(
|
|
63
|
+
line_number:,
|
|
64
|
+
column:,
|
|
65
|
+
text:,
|
|
66
|
+
inline:
|
|
67
|
+
)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def in_string?(_line)
|
|
72
|
+
# Simple heuristic: skip lines that start with quotes
|
|
73
|
+
# A more complete implementation would track string state
|
|
74
|
+
false
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yamlint
|
|
4
|
+
module Parser
|
|
5
|
+
class LineParser
|
|
6
|
+
def initialize(content)
|
|
7
|
+
@content = content
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def parse
|
|
11
|
+
@content.lines
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def line_at(line_number)
|
|
15
|
+
lines = parse
|
|
16
|
+
lines[line_number - 1]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def line_count
|
|
20
|
+
parse.length
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def each_line_with_number(&)
|
|
24
|
+
parse.each_with_index do |line, index|
|
|
25
|
+
yield(line, index + 1)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'yaml'
|
|
4
|
+
|
|
5
|
+
module Yamlint
|
|
6
|
+
module Parser
|
|
7
|
+
class TokenParser
|
|
8
|
+
class Handler < Psych::Handler
|
|
9
|
+
attr_reader :tokens
|
|
10
|
+
|
|
11
|
+
def initialize
|
|
12
|
+
super
|
|
13
|
+
@tokens = []
|
|
14
|
+
@parser = nil
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
attr_writer :parser
|
|
18
|
+
|
|
19
|
+
def start_stream(encoding)
|
|
20
|
+
add_token(:stream_start, encoding:)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def end_stream
|
|
24
|
+
add_token(:stream_end)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def start_document(version, tag_directives, implicit)
|
|
28
|
+
add_token(:document_start, version:, tag_directives:, implicit:)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def end_document(implicit)
|
|
32
|
+
add_token(:document_end, implicit:)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def start_mapping(anchor, tag, implicit, style)
|
|
36
|
+
add_token(:mapping_start, anchor:, tag:, implicit:, style:)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def end_mapping
|
|
40
|
+
add_token(:mapping_end)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def start_sequence(anchor, tag, implicit, style)
|
|
44
|
+
add_token(:sequence_start, anchor:, tag:, implicit:, style:)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def end_sequence
|
|
48
|
+
add_token(:sequence_end)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def scalar(value, anchor, tag, plain, quoted, style)
|
|
52
|
+
add_token(:scalar, value:, anchor:, tag:, plain:, quoted:, style:)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def alias(anchor)
|
|
56
|
+
add_token(:alias, anchor:)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def add_token(type, **attrs)
|
|
62
|
+
mark = @parser&.mark
|
|
63
|
+
token = Models::Token.new(
|
|
64
|
+
type:,
|
|
65
|
+
value: attrs[:value],
|
|
66
|
+
start_line: mark ? mark.line + 1 : 1,
|
|
67
|
+
start_column: mark ? mark.column + 1 : 1
|
|
68
|
+
)
|
|
69
|
+
@tokens << token
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def initialize(content)
|
|
74
|
+
@content = content
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def parse
|
|
78
|
+
handler = Handler.new
|
|
79
|
+
parser = Psych::Parser.new(handler)
|
|
80
|
+
handler.parser = parser
|
|
81
|
+
|
|
82
|
+
begin
|
|
83
|
+
parser.parse(@content)
|
|
84
|
+
rescue Psych::SyntaxError
|
|
85
|
+
# Syntax errors will be handled separately
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
handler.tokens
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yamlint
|
|
4
|
+
module Parser
|
|
5
|
+
autoload :LineParser, 'yamlint/parser/line_parser'
|
|
6
|
+
autoload :TokenParser, 'yamlint/parser/token_parser'
|
|
7
|
+
autoload :CommentExtractor, 'yamlint/parser/comment_extractor'
|
|
8
|
+
autoload :Comment, 'yamlint/parser/comment_extractor'
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yamlint
|
|
4
|
+
module Presets
|
|
5
|
+
DEFAULT = {
|
|
6
|
+
rules: {
|
|
7
|
+
'anchors' => { 'forbid-undeclared-aliases' => true, 'forbid-duplicated-anchors' => true,
|
|
8
|
+
'forbid-unused-anchors' => true },
|
|
9
|
+
'braces' => { 'forbid' => false, 'min-spaces-inside' => 0, 'max-spaces-inside' => 0 },
|
|
10
|
+
'brackets' => { 'forbid' => false, 'min-spaces-inside' => 0, 'max-spaces-inside' => 0 },
|
|
11
|
+
'colons' => { 'max-spaces-before' => 0, 'max-spaces-after' => 1 },
|
|
12
|
+
'commas' => { 'max-spaces-before' => 0, 'min-spaces-after' => 1, 'max-spaces-after' => 1 },
|
|
13
|
+
'comments' => { 'require-starting-space' => true, 'ignore-shebangs' => true, 'min-spaces-from-content' => 2 },
|
|
14
|
+
'comments-indentation' => {},
|
|
15
|
+
'document-end' => 'disable',
|
|
16
|
+
'document-start' => 'disable',
|
|
17
|
+
'empty-lines' => { 'max' => 2, 'max-start' => 0, 'max-end' => 0 },
|
|
18
|
+
'empty-values' => { 'forbid-in-block-mappings' => true, 'forbid-in-flow-mappings' => true },
|
|
19
|
+
'float-values' => 'disable',
|
|
20
|
+
'hyphens' => { 'max-spaces-after' => 1 },
|
|
21
|
+
'indentation' => { 'spaces' => 2, 'indent-sequences' => true },
|
|
22
|
+
'key-duplicates' => {},
|
|
23
|
+
'key-ordering' => 'disable',
|
|
24
|
+
'line-length' => { 'max' => 80, 'allow-non-breakable-words' => true,
|
|
25
|
+
'allow-non-breakable-inline-mappings' => true },
|
|
26
|
+
'new-line-at-end-of-file' => {},
|
|
27
|
+
'new-lines' => { 'type' => 'unix' },
|
|
28
|
+
'octal-values' => { 'forbid-implicit-octal' => true, 'forbid-explicit-octal' => false },
|
|
29
|
+
'quoted-strings' => 'disable',
|
|
30
|
+
'trailing-spaces' => {},
|
|
31
|
+
'truthy' => { 'allowed-values' => %w[true false], 'check-keys' => true }
|
|
32
|
+
}
|
|
33
|
+
}.freeze
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Yamlint
|
|
4
|
+
module Presets
|
|
5
|
+
RELAXED = {
|
|
6
|
+
rules: {
|
|
7
|
+
'anchors' => 'disable',
|
|
8
|
+
'braces' => { 'forbid' => false, 'min-spaces-inside' => 0, 'max-spaces-inside' => 1 },
|
|
9
|
+
'brackets' => { 'forbid' => false, 'min-spaces-inside' => 0, 'max-spaces-inside' => 1 },
|
|
10
|
+
'colons' => { 'max-spaces-before' => 1, 'max-spaces-after' => 1 },
|
|
11
|
+
'commas' => { 'max-spaces-before' => 1, 'min-spaces-after' => 1, 'max-spaces-after' => 1 },
|
|
12
|
+
'comments' => 'disable',
|
|
13
|
+
'comments-indentation' => 'disable',
|
|
14
|
+
'document-end' => 'disable',
|
|
15
|
+
'document-start' => 'disable',
|
|
16
|
+
'empty-lines' => 'disable',
|
|
17
|
+
'empty-values' => 'disable',
|
|
18
|
+
'float-values' => 'disable',
|
|
19
|
+
'hyphens' => 'disable',
|
|
20
|
+
'indentation' => 'disable',
|
|
21
|
+
'key-duplicates' => {},
|
|
22
|
+
'key-ordering' => 'disable',
|
|
23
|
+
'line-length' => { 'max' => 120, 'allow-non-breakable-words' => true,
|
|
24
|
+
'allow-non-breakable-inline-mappings' => true },
|
|
25
|
+
'new-line-at-end-of-file' => 'disable',
|
|
26
|
+
'new-lines' => { 'type' => 'unix' },
|
|
27
|
+
'octal-values' => 'disable',
|
|
28
|
+
'quoted-strings' => 'disable',
|
|
29
|
+
'trailing-spaces' => 'disable',
|
|
30
|
+
'truthy' => 'disable'
|
|
31
|
+
}
|
|
32
|
+
}.freeze
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'presets/default'
|
|
4
|
+
require_relative 'presets/relaxed'
|
|
5
|
+
|
|
6
|
+
module Yamlint
|
|
7
|
+
module Presets
|
|
8
|
+
def self.get(name)
|
|
9
|
+
case name.to_s
|
|
10
|
+
when 'default'
|
|
11
|
+
DEFAULT
|
|
12
|
+
when 'relaxed'
|
|
13
|
+
RELAXED
|
|
14
|
+
else
|
|
15
|
+
raise ArgumentError, "Unknown preset: #{name}"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'yaml'
|
|
4
|
+
|
|
5
|
+
module Yamlint
|
|
6
|
+
module Rules
|
|
7
|
+
class Anchors < Base
|
|
8
|
+
rule_id 'anchors'
|
|
9
|
+
desc 'Check anchors are defined before use and are not duplicated.'
|
|
10
|
+
defaults({
|
|
11
|
+
'forbid-undeclared-aliases': true,
|
|
12
|
+
'forbid-duplicated-anchors': true,
|
|
13
|
+
'forbid-unused-anchors': true
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
def check(context)
|
|
17
|
+
handler = AnchorHandler.new
|
|
18
|
+
parser = Psych::Parser.new(handler)
|
|
19
|
+
handler.parser = parser
|
|
20
|
+
|
|
21
|
+
begin
|
|
22
|
+
parser.parse(context.content)
|
|
23
|
+
rescue Psych::SyntaxError
|
|
24
|
+
return []
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
problems = []
|
|
28
|
+
|
|
29
|
+
if @config[:'forbid-undeclared-aliases']
|
|
30
|
+
handler.undeclared_aliases.each do |alias_info|
|
|
31
|
+
problems << problem(
|
|
32
|
+
line: alias_info[:line],
|
|
33
|
+
column: alias_info[:column],
|
|
34
|
+
message: "found undefined alias \"#{alias_info[:name]}\"",
|
|
35
|
+
fixable: false
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
if @config[:'forbid-duplicated-anchors']
|
|
41
|
+
handler.duplicated_anchors.each do |anchor_info|
|
|
42
|
+
problems << problem(
|
|
43
|
+
line: anchor_info[:line],
|
|
44
|
+
column: anchor_info[:column],
|
|
45
|
+
message: "found duplicate anchor \"#{anchor_info[:name]}\"",
|
|
46
|
+
fixable: false
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
if @config[:'forbid-unused-anchors']
|
|
52
|
+
handler.unused_anchors.each do |anchor_info|
|
|
53
|
+
problems << problem(
|
|
54
|
+
line: anchor_info[:line],
|
|
55
|
+
column: anchor_info[:column],
|
|
56
|
+
message: "found undefined anchor \"#{anchor_info[:name]}\"",
|
|
57
|
+
fixable: false
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
problems
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
class AnchorHandler < Psych::Handler
|
|
66
|
+
attr_accessor :parser
|
|
67
|
+
|
|
68
|
+
def initialize
|
|
69
|
+
super
|
|
70
|
+
@anchors = {}
|
|
71
|
+
@aliases = []
|
|
72
|
+
@parser = nil
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def scalar(_value, anchor, _tag, _plain, _quoted, _style)
|
|
76
|
+
record_anchor(anchor) if anchor
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def start_mapping(anchor, _tag, _implicit, _style)
|
|
80
|
+
record_anchor(anchor) if anchor
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def start_sequence(anchor, _tag, _implicit, _style)
|
|
84
|
+
record_anchor(anchor) if anchor
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def alias(anchor)
|
|
88
|
+
mark = @parser&.mark
|
|
89
|
+
@aliases << {
|
|
90
|
+
name: anchor,
|
|
91
|
+
line: mark ? mark.line + 1 : 1,
|
|
92
|
+
column: mark ? mark.column + 1 : 1
|
|
93
|
+
}
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def undeclared_aliases
|
|
97
|
+
@aliases.reject { |a| @anchors.key?(a[:name]) }
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def duplicated_anchors
|
|
101
|
+
@anchors.values.select { |v| v.is_a?(Array) && v.length > 1 }.flatten
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def unused_anchors
|
|
105
|
+
used_names = @aliases.map { |a| a[:name] }
|
|
106
|
+
@anchors.except(*used_names).map do |_, info|
|
|
107
|
+
info.is_a?(Array) ? info.first : info
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
private
|
|
112
|
+
|
|
113
|
+
def record_anchor(anchor)
|
|
114
|
+
mark = @parser&.mark
|
|
115
|
+
info = {
|
|
116
|
+
name: anchor,
|
|
117
|
+
line: mark ? mark.line + 1 : 1,
|
|
118
|
+
column: mark ? mark.column + 1 : 1
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if @anchors.key?(anchor)
|
|
122
|
+
existing = @anchors[anchor]
|
|
123
|
+
@anchors[anchor] = existing.is_a?(Array) ? existing + [info] : [existing, info]
|
|
124
|
+
else
|
|
125
|
+
@anchors[anchor] = info
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
Registry.register(Anchors)
|
|
132
|
+
end
|
|
133
|
+
end
|