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.
Files changed (136) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +31 -9
  3. data/.serena/.gitignore +1 -0
  4. data/.serena/memories/project_overview.md +25 -0
  5. data/.serena/memories/style_and_conventions.md +7 -0
  6. data/.serena/memories/suggested_commands.md +17 -0
  7. data/.serena/memories/task_completion.md +5 -0
  8. data/.serena/project.yml +89 -0
  9. data/CHANGELOG.md +6 -2
  10. data/Gemfile +9 -7
  11. data/LICENSE.txt +1 -1
  12. data/README.md +155 -17
  13. data/Rakefile +10 -3
  14. data/docs/Yamlint/Cli.html +403 -0
  15. data/docs/Yamlint/Config.html +1034 -0
  16. data/docs/Yamlint/Formatter.html +433 -0
  17. data/docs/Yamlint/Linter.html +423 -0
  18. data/docs/Yamlint/Models/LintContext.html +993 -0
  19. data/docs/Yamlint/Models/Problem.html +951 -0
  20. data/docs/Yamlint/Models/Token.html +713 -0
  21. data/docs/Yamlint/Models.html +117 -0
  22. data/docs/Yamlint/Output/Base.html +290 -0
  23. data/docs/Yamlint/Output/Colored.html +293 -0
  24. data/docs/Yamlint/Output/Github.html +260 -0
  25. data/docs/Yamlint/Output/Parsable.html +258 -0
  26. data/docs/Yamlint/Output/Standard.html +270 -0
  27. data/docs/Yamlint/Output.html +208 -0
  28. data/docs/Yamlint/Parser/Comment.html +795 -0
  29. data/docs/Yamlint/Parser/CommentExtractor.html +287 -0
  30. data/docs/Yamlint/Parser/LineParser.html +423 -0
  31. data/docs/Yamlint/Parser/TokenParser/Handler.html +910 -0
  32. data/docs/Yamlint/Parser/TokenParser.html +291 -0
  33. data/docs/Yamlint/Parser.html +117 -0
  34. data/docs/Yamlint/Presets.html +266 -0
  35. data/docs/Yamlint/Rules/Anchors/AnchorHandler.html +678 -0
  36. data/docs/Yamlint/Rules/Anchors.html +314 -0
  37. data/docs/Yamlint/Rules/Base.html +968 -0
  38. data/docs/Yamlint/Rules/Braces.html +335 -0
  39. data/docs/Yamlint/Rules/Brackets.html +335 -0
  40. data/docs/Yamlint/Rules/Colons.html +313 -0
  41. data/docs/Yamlint/Rules/Commas.html +313 -0
  42. data/docs/Yamlint/Rules/CommentRule.html +298 -0
  43. data/docs/Yamlint/Rules/Comments.html +317 -0
  44. data/docs/Yamlint/Rules/CommentsIndentation.html +328 -0
  45. data/docs/Yamlint/Rules/DocumentEnd.html +332 -0
  46. data/docs/Yamlint/Rules/DocumentStart.html +332 -0
  47. data/docs/Yamlint/Rules/EmptyLines.html +300 -0
  48. data/docs/Yamlint/Rules/EmptyValues.html +273 -0
  49. data/docs/Yamlint/Rules/FloatValues.html +383 -0
  50. data/docs/Yamlint/Rules/Hyphens.html +337 -0
  51. data/docs/Yamlint/Rules/Indentation.html +329 -0
  52. data/docs/Yamlint/Rules/KeyDuplicates/DuplicateKeyHandler.html +716 -0
  53. data/docs/Yamlint/Rules/KeyDuplicates.html +258 -0
  54. data/docs/Yamlint/Rules/KeyOrdering/KeyOrderHandler.html +694 -0
  55. data/docs/Yamlint/Rules/KeyOrdering.html +258 -0
  56. data/docs/Yamlint/Rules/LineLength.html +251 -0
  57. data/docs/Yamlint/Rules/LineRule.html +304 -0
  58. data/docs/Yamlint/Rules/NewLineAtEndOfFile.html +308 -0
  59. data/docs/Yamlint/Rules/NewLines.html +310 -0
  60. data/docs/Yamlint/Rules/OctalValues.html +270 -0
  61. data/docs/Yamlint/Rules/QuotedStrings.html +381 -0
  62. data/docs/Yamlint/Rules/Registry.html +492 -0
  63. data/docs/Yamlint/Rules/TokenRule.html +298 -0
  64. data/docs/Yamlint/Rules/TrailingSpaces.html +321 -0
  65. data/docs/Yamlint/Rules/Truthy.html +288 -0
  66. data/docs/Yamlint/Rules.html +190 -0
  67. data/docs/Yamlint/Runner.html +551 -0
  68. data/docs/Yamlint.html +135 -0
  69. data/docs/_index.html +643 -0
  70. data/docs/class_list.html +54 -0
  71. data/docs/css/common.css +1 -0
  72. data/docs/css/full_list.css +58 -0
  73. data/docs/css/style.css +490 -0
  74. data/docs/file.README.html +276 -0
  75. data/docs/file_list.html +59 -0
  76. data/docs/frames.html +22 -0
  77. data/docs/index.html +276 -0
  78. data/docs/js/app.js +395 -0
  79. data/docs/js/full_list.js +244 -0
  80. data/docs/js/jquery.js +4 -0
  81. data/docs/method_list.html +1582 -0
  82. data/docs/top-level-namespace.html +110 -0
  83. data/exe/yamlint +7 -0
  84. data/lib/yamlint/cli.rb +162 -0
  85. data/lib/yamlint/config.rb +113 -0
  86. data/lib/yamlint/formatter.rb +140 -0
  87. data/lib/yamlint/linter.rb +130 -0
  88. data/lib/yamlint/models/lint_context.rb +43 -0
  89. data/lib/yamlint/models/problem.rb +44 -0
  90. data/lib/yamlint/models/token.rb +22 -0
  91. data/lib/yamlint/models.rb +9 -0
  92. data/lib/yamlint/output/base.rb +15 -0
  93. data/lib/yamlint/output/colored.rb +54 -0
  94. data/lib/yamlint/output/github.rb +20 -0
  95. data/lib/yamlint/output/parsable.rb +19 -0
  96. data/lib/yamlint/output/standard.rb +25 -0
  97. data/lib/yamlint/output.rb +26 -0
  98. data/lib/yamlint/parser/comment_extractor.rb +78 -0
  99. data/lib/yamlint/parser/line_parser.rb +30 -0
  100. data/lib/yamlint/parser/token_parser.rb +92 -0
  101. data/lib/yamlint/parser.rb +10 -0
  102. data/lib/yamlint/presets/default.rb +35 -0
  103. data/lib/yamlint/presets/relaxed.rb +34 -0
  104. data/lib/yamlint/presets.rb +19 -0
  105. data/lib/yamlint/rules/anchors.rb +133 -0
  106. data/lib/yamlint/rules/base.rb +102 -0
  107. data/lib/yamlint/rules/braces.rb +105 -0
  108. data/lib/yamlint/rules/brackets.rb +105 -0
  109. data/lib/yamlint/rules/colons.rb +73 -0
  110. data/lib/yamlint/rules/commas.rb +85 -0
  111. data/lib/yamlint/rules/comments.rb +77 -0
  112. data/lib/yamlint/rules/comments_indentation.rb +66 -0
  113. data/lib/yamlint/rules/document_end.rb +45 -0
  114. data/lib/yamlint/rules/document_start.rb +45 -0
  115. data/lib/yamlint/rules/empty_lines.rb +107 -0
  116. data/lib/yamlint/rules/empty_values.rb +43 -0
  117. data/lib/yamlint/rules/float_values.rb +67 -0
  118. data/lib/yamlint/rules/hyphens.rb +42 -0
  119. data/lib/yamlint/rules/indentation.rb +39 -0
  120. data/lib/yamlint/rules/key_duplicates.rb +127 -0
  121. data/lib/yamlint/rules/key_ordering.rb +126 -0
  122. data/lib/yamlint/rules/line_length.rb +57 -0
  123. data/lib/yamlint/rules/new_line_at_end_of_file.rb +31 -0
  124. data/lib/yamlint/rules/new_lines.rb +59 -0
  125. data/lib/yamlint/rules/octal_values.rb +62 -0
  126. data/lib/yamlint/rules/quoted_strings.rb +73 -0
  127. data/lib/yamlint/rules/registry.rb +48 -0
  128. data/lib/yamlint/rules/trailing_spaces.rb +31 -0
  129. data/lib/yamlint/rules/truthy.rb +48 -0
  130. data/lib/yamlint/rules.rb +41 -0
  131. data/lib/yamlint/runner.rb +80 -0
  132. data/lib/yamlint/version.rb +1 -1
  133. data/lib/yamlint.rb +11 -3
  134. metadata +131 -11
  135. data/CODE_OF_CONDUCT.md +0 -84
  136. data/sig/yamlint.rbs +0 -4
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yamlint
4
+ module Rules
5
+ class EmptyLines < Base
6
+ rule_id 'empty-lines'
7
+ desc 'Limit the number of consecutive blank lines.'
8
+ defaults({
9
+ max: 2,
10
+ 'max-start': 0,
11
+ 'max-end': 0
12
+ })
13
+
14
+ def check(context)
15
+ return [] if context.empty?
16
+
17
+ problems = []
18
+ problems.concat(check_start_empty_lines(context))
19
+ problems.concat(check_end_empty_lines(context))
20
+ problems.concat(check_consecutive_empty_lines(context))
21
+ problems
22
+ end
23
+
24
+ def fixable?
25
+ true
26
+ end
27
+
28
+ private
29
+
30
+ def check_start_empty_lines(context)
31
+ max_start = @config[:'max-start']
32
+ count = 0
33
+
34
+ context.lines.each do |line|
35
+ break unless blank_line?(line)
36
+
37
+ count += 1
38
+ end
39
+
40
+ return [] if count <= max_start
41
+
42
+ [problem(
43
+ line: 1,
44
+ column: 1,
45
+ message: "too many blank lines at the beginning of file (#{count} > #{max_start})",
46
+ fixable: true
47
+ )]
48
+ end
49
+
50
+ def check_end_empty_lines(context)
51
+ max_end = @config[:'max-end']
52
+ count = 0
53
+ lines = context.lines
54
+
55
+ lines.reverse_each do |line|
56
+ break unless blank_line?(line)
57
+
58
+ count += 1
59
+ end
60
+
61
+ return [] if count <= max_end
62
+
63
+ [problem(
64
+ line: context.line_count - count + 1,
65
+ column: 1,
66
+ message: "too many blank lines at the end of file (#{count} > #{max_end})",
67
+ fixable: true
68
+ )]
69
+ end
70
+
71
+ def check_consecutive_empty_lines(context)
72
+ max = @config[:max]
73
+ problems = []
74
+ consecutive_count = 0
75
+ first_blank_line = nil
76
+
77
+ context.lines.each_with_index do |line, index|
78
+ line_number = index + 1
79
+
80
+ if blank_line?(line)
81
+ first_blank_line ||= line_number
82
+ consecutive_count += 1
83
+ else
84
+ if consecutive_count > max
85
+ problems << problem(
86
+ line: first_blank_line,
87
+ column: 1,
88
+ message: "too many blank lines (#{consecutive_count} > #{max})",
89
+ fixable: true
90
+ )
91
+ end
92
+ consecutive_count = 0
93
+ first_blank_line = nil
94
+ end
95
+ end
96
+
97
+ problems
98
+ end
99
+
100
+ def blank_line?(line)
101
+ line.strip.empty?
102
+ end
103
+ end
104
+
105
+ Registry.register(EmptyLines)
106
+ end
107
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yamlint
4
+ module Rules
5
+ class EmptyValues < LineRule
6
+ rule_id 'empty-values'
7
+ desc 'Forbid empty values in mappings.'
8
+ defaults({
9
+ 'forbid-in-block-mappings': true,
10
+ 'forbid-in-flow-mappings': true
11
+ })
12
+
13
+ def check_line(line, line_number, _context)
14
+ return if line.strip.empty?
15
+ return if line.strip.start_with?('#')
16
+
17
+ problems = []
18
+
19
+ if @config[:'forbid-in-block-mappings'] && line.match?(/:\s*$/) && !line.match?(/[|>]/)
20
+ problems << problem(
21
+ line: line_number,
22
+ column: line.index(':') + 1,
23
+ message: 'empty value in block mapping',
24
+ fixable: false
25
+ )
26
+ end
27
+
28
+ if @config[:'forbid-in-flow-mappings'] && line.match?(/:\s*[,}]/)
29
+ problems << problem(
30
+ line: line_number,
31
+ column: line.index(':') + 1,
32
+ message: 'empty value in flow mapping',
33
+ fixable: false
34
+ )
35
+ end
36
+
37
+ problems
38
+ end
39
+ end
40
+
41
+ Registry.register(EmptyValues)
42
+ end
43
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yamlint
4
+ module Rules
5
+ class FloatValues < LineRule
6
+ rule_id 'float-values'
7
+ desc 'Check float value formatting.'
8
+ defaults({
9
+ 'forbid-scientific-notation': false,
10
+ 'forbid-nan': false,
11
+ 'forbid-inf': false,
12
+ 'require-numeral-before-decimal': false
13
+ })
14
+
15
+ def check_line(line, line_number, _context)
16
+ return if line.strip.empty?
17
+ return if line.strip.start_with?('#')
18
+
19
+ problems = []
20
+
21
+ if @config[:'forbid-scientific-notation'] && line.match?(/:\s*[\d.]+[eE][+-]?\d+/)
22
+ problems << problem(
23
+ line: line_number,
24
+ column: line.index(':') + 1,
25
+ message: 'scientific notation forbidden',
26
+ fixable: false
27
+ )
28
+ end
29
+
30
+ if @config[:'forbid-nan'] && line.match?(/:\s*\.nan\s*(?:#.*)?$/i)
31
+ problems << problem(
32
+ line: line_number,
33
+ column: line.index(':') + 1,
34
+ message: '.nan value forbidden',
35
+ fixable: false
36
+ )
37
+ end
38
+
39
+ if @config[:'forbid-inf'] && line.match?(/:\s*[+-]?\.inf\s*(?:#.*)?$/i)
40
+ problems << problem(
41
+ line: line_number,
42
+ column: line.index(':') + 1,
43
+ message: '.inf value forbidden',
44
+ fixable: false
45
+ )
46
+ end
47
+
48
+ if @config[:'require-numeral-before-decimal'] && line.match?(/:\s*\.\d+/)
49
+ problems << problem(
50
+ line: line_number,
51
+ column: line.index(':') + 1,
52
+ message: 'numeral required before decimal point',
53
+ fixable: true
54
+ )
55
+ end
56
+
57
+ problems
58
+ end
59
+
60
+ def fixable?
61
+ @config[:'require-numeral-before-decimal']
62
+ end
63
+ end
64
+
65
+ Registry.register(FloatValues)
66
+ end
67
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'English'
4
+ module Yamlint
5
+ module Rules
6
+ class Hyphens < LineRule
7
+ rule_id 'hyphens'
8
+ desc 'Check space after hyphens.'
9
+ defaults({
10
+ 'max-spaces-after': 1
11
+ })
12
+
13
+ def check_line(line, line_number, _context)
14
+ return if line.strip.empty?
15
+ return if line.strip.start_with?('#')
16
+
17
+ problems = []
18
+ max_after = @config[:'max-spaces-after']
19
+
20
+ line.scan(/^(\s*)-(\s+)/) do |_indent, spaces|
21
+ next if spaces.length <= max_after
22
+
23
+ pos = $LAST_MATCH_INFO.begin(2)
24
+ problems << problem(
25
+ line: line_number,
26
+ column: pos + 1,
27
+ message: "too many spaces after hyphen (#{spaces.length} > #{max_after})",
28
+ fixable: true
29
+ )
30
+ end
31
+
32
+ problems
33
+ end
34
+
35
+ def fixable?
36
+ true
37
+ end
38
+ end
39
+
40
+ Registry.register(Hyphens)
41
+ end
42
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yamlint
4
+ module Rules
5
+ class Indentation < LineRule
6
+ rule_id 'indentation'
7
+ desc 'Enforce consistent indentation.'
8
+ defaults({
9
+ spaces: 2,
10
+ 'indent-sequences': true,
11
+ 'check-multi-line-strings': false
12
+ })
13
+
14
+ def check_line(line, line_number, _context)
15
+ return if line.strip.empty?
16
+ return if line.start_with?('#')
17
+
18
+ expected_spaces = @config[:spaces]
19
+ leading_spaces = line[/\A */].length
20
+
21
+ return if leading_spaces.zero?
22
+ return if (leading_spaces % expected_spaces).zero?
23
+
24
+ problem(
25
+ line: line_number,
26
+ column: 1,
27
+ message: "wrong indentation: expected #{expected_spaces}n spaces",
28
+ fixable: true
29
+ )
30
+ end
31
+
32
+ def fixable?
33
+ true
34
+ end
35
+ end
36
+
37
+ Registry.register(Indentation)
38
+ end
39
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+
5
+ module Yamlint
6
+ module Rules
7
+ class KeyDuplicates < Base
8
+ rule_id 'key-duplicates'
9
+ desc 'Forbid duplicated keys in mappings.'
10
+ defaults({})
11
+
12
+ def check(context)
13
+ handler = DuplicateKeyHandler.new
14
+ parser = Psych::Parser.new(handler)
15
+ handler.parser = parser
16
+
17
+ begin
18
+ parser.parse(context.content)
19
+ rescue Psych::SyntaxError
20
+ return []
21
+ end
22
+
23
+ handler.problems.map do |prob|
24
+ problem(
25
+ line: prob[:line],
26
+ column: prob[:column],
27
+ message: "duplicate key \"#{prob[:key]}\"",
28
+ fixable: false
29
+ )
30
+ end
31
+ end
32
+
33
+ class DuplicateKeyHandler < Psych::Handler
34
+ attr_reader :problems
35
+
36
+ def initialize
37
+ super
38
+ @stack = []
39
+ @problems = []
40
+ @parser = nil
41
+ end
42
+
43
+ attr_writer :parser
44
+
45
+ def start_mapping(*)
46
+ parent = current_mapping_frame
47
+ @stack << {
48
+ type: :mapping,
49
+ keys: {},
50
+ expecting_key: true,
51
+ close_parent: capture_close_parent(parent)
52
+ }
53
+ end
54
+
55
+ def end_mapping
56
+ frame = @stack.pop
57
+ close_parent_value(frame)
58
+ end
59
+
60
+ def start_sequence(*)
61
+ parent = current_mapping_frame
62
+ @stack << {
63
+ type: :sequence,
64
+ close_parent: capture_close_parent(parent)
65
+ }
66
+ end
67
+
68
+ def end_sequence
69
+ frame = @stack.pop
70
+ close_parent_value(frame)
71
+ end
72
+
73
+ def scalar(value, _anchor, _tag, _plain, _quoted, _style)
74
+ frame = @stack.last
75
+ return unless frame && frame[:type] == :mapping
76
+
77
+ if frame[:expecting_key]
78
+ current_keys = frame[:keys]
79
+ mark = @parser&.mark
80
+
81
+ if current_keys.key?(value)
82
+ @problems << {
83
+ key: value,
84
+ line: mark ? mark.line + 1 : 1,
85
+ column: mark ? mark.column + 1 : 1
86
+ }
87
+ else
88
+ current_keys[value] = true
89
+ end
90
+
91
+ frame[:expecting_key] = false
92
+ else
93
+ frame[:expecting_key] = true
94
+ end
95
+ end
96
+
97
+ private
98
+
99
+ def current_mapping_frame
100
+ frame = @stack.last
101
+ return frame if frame && frame[:type] == :mapping
102
+
103
+ nil
104
+ end
105
+
106
+ def capture_close_parent(parent)
107
+ return nil unless parent
108
+
109
+ if parent[:expecting_key]
110
+ { parent:, expecting_key: false }
111
+ else
112
+ { parent:, expecting_key: true }
113
+ end
114
+ end
115
+
116
+ def close_parent_value(frame)
117
+ close = frame[:close_parent]
118
+ return unless close
119
+
120
+ close[:parent][:expecting_key] = close[:expecting_key]
121
+ end
122
+ end
123
+ end
124
+
125
+ Registry.register(KeyDuplicates)
126
+ end
127
+ end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+
5
+ module Yamlint
6
+ module Rules
7
+ class KeyOrdering < Base
8
+ rule_id 'key-ordering'
9
+ desc 'Enforce alphabetical ordering of keys.'
10
+ defaults({})
11
+
12
+ def check(context)
13
+ handler = KeyOrderHandler.new
14
+ parser = Psych::Parser.new(handler)
15
+ handler.parser = parser
16
+
17
+ begin
18
+ parser.parse(context.content)
19
+ rescue Psych::SyntaxError
20
+ return []
21
+ end
22
+
23
+ handler.problems.map do |prob|
24
+ problem(
25
+ line: prob[:line],
26
+ column: prob[:column],
27
+ message: "wrong ordering of key \"#{prob[:key]}\" (should be before \"#{prob[:prev_key]}\")",
28
+ fixable: false
29
+ )
30
+ end
31
+ end
32
+
33
+ class KeyOrderHandler < Psych::Handler
34
+ attr_reader :problems
35
+ attr_accessor :parser
36
+
37
+ def initialize
38
+ super
39
+ @stack = []
40
+ @problems = []
41
+ @parser = nil
42
+ end
43
+
44
+ def start_mapping(*)
45
+ parent = current_mapping_frame
46
+ @stack << {
47
+ type: :mapping,
48
+ keys: [],
49
+ expecting_key: true,
50
+ close_parent: capture_close_parent(parent)
51
+ }
52
+ end
53
+
54
+ def end_mapping
55
+ frame = @stack.pop
56
+ close_parent_value(frame)
57
+ end
58
+
59
+ def start_sequence(*)
60
+ parent = current_mapping_frame
61
+ @stack << {
62
+ type: :sequence,
63
+ close_parent: capture_close_parent(parent)
64
+ }
65
+ end
66
+
67
+ def end_sequence
68
+ frame = @stack.pop
69
+ close_parent_value(frame)
70
+ end
71
+
72
+ def scalar(value, _anchor, _tag, _plain, _quoted, _style)
73
+ frame = @stack.last
74
+ return unless frame && frame[:type] == :mapping
75
+
76
+ if frame[:expecting_key]
77
+ current_keys = frame[:keys]
78
+ mark = @parser&.mark
79
+
80
+ if current_keys.any? && value < current_keys.last
81
+ @problems << {
82
+ key: value,
83
+ prev_key: current_keys.last,
84
+ line: mark ? mark.line + 1 : 1,
85
+ column: mark ? mark.column + 1 : 1
86
+ }
87
+ end
88
+
89
+ current_keys << value
90
+ frame[:expecting_key] = false
91
+ else
92
+ frame[:expecting_key] = true
93
+ end
94
+ end
95
+
96
+ private
97
+
98
+ def current_mapping_frame
99
+ frame = @stack.last
100
+ return frame if frame && frame[:type] == :mapping
101
+
102
+ nil
103
+ end
104
+
105
+ def capture_close_parent(parent)
106
+ return nil unless parent
107
+
108
+ if parent[:expecting_key]
109
+ { parent:, expecting_key: false }
110
+ else
111
+ { parent:, expecting_key: true }
112
+ end
113
+ end
114
+
115
+ def close_parent_value(frame)
116
+ close = frame[:close_parent]
117
+ return unless close
118
+
119
+ close[:parent][:expecting_key] = close[:expecting_key]
120
+ end
121
+ end
122
+ end
123
+
124
+ Registry.register(KeyOrdering)
125
+ end
126
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yamlint
4
+ module Rules
5
+ class LineLength < LineRule
6
+ rule_id 'line-length'
7
+ desc 'Limit the line length.'
8
+ defaults({
9
+ max: 80,
10
+ 'allow-non-breakable-words': true,
11
+ 'allow-non-breakable-inline-mappings': true
12
+ })
13
+
14
+ def check_line(line, line_number, _context)
15
+ max_length = @config[:max]
16
+ actual_length = line.chomp.length
17
+
18
+ return if actual_length <= max_length
19
+ return if allow_non_breakable_words? && non_breakable_word?(line)
20
+ return if allow_non_breakable_inline_mappings? && inline_mapping?(line)
21
+
22
+ problem(
23
+ line: line_number,
24
+ column: max_length + 1,
25
+ message: "line too long (#{actual_length} > #{max_length} characters)",
26
+ fixable: false
27
+ )
28
+ end
29
+
30
+ private
31
+
32
+ def allow_non_breakable_words?
33
+ @config[:'allow-non-breakable-words']
34
+ end
35
+
36
+ def allow_non_breakable_inline_mappings?
37
+ @config[:'allow-non-breakable-inline-mappings']
38
+ end
39
+
40
+ def non_breakable_word?(line)
41
+ stripped = line.strip
42
+ return false if stripped.empty?
43
+
44
+ # Check if the line contains a URL or a very long word
45
+ stripped.match?(%r{https?://\S+}) ||
46
+ stripped.split.any? { |word| word.length > @config[:max] }
47
+ end
48
+
49
+ def inline_mapping?(line)
50
+ stripped = line.strip
51
+ stripped.match?(/^\{.*\}$/)
52
+ end
53
+ end
54
+
55
+ Registry.register(LineLength)
56
+ end
57
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yamlint
4
+ module Rules
5
+ class NewLineAtEndOfFile < Base
6
+ rule_id 'new-line-at-end-of-file'
7
+ desc 'Require a new line character at the end of files.'
8
+ defaults({})
9
+
10
+ def check(context)
11
+ return [] if context.empty?
12
+
13
+ last_char = context.content[-1]
14
+ return [] if last_char == "\n"
15
+
16
+ [problem(
17
+ line: context.line_count,
18
+ column: (context.lines.last&.length || 0) + 1,
19
+ message: 'no new line character at the end of file',
20
+ fixable: true
21
+ )]
22
+ end
23
+
24
+ def fixable?
25
+ true
26
+ end
27
+ end
28
+
29
+ Registry.register(NewLineAtEndOfFile)
30
+ end
31
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Yamlint
4
+ module Rules
5
+ class NewLines < Base
6
+ rule_id 'new-lines'
7
+ desc 'Use consistent line endings throughout the file.'
8
+ defaults({ type: 'unix' })
9
+
10
+ def check(context)
11
+ return [] if context.empty?
12
+
13
+ expected_type = @config[:type]
14
+ problems = []
15
+
16
+ context.lines.each_with_index do |line, index|
17
+ line_number = index + 1
18
+ problem = check_line_ending(line, line_number, expected_type)
19
+ problems << problem if problem
20
+ end
21
+
22
+ problems
23
+ end
24
+
25
+ def fixable?
26
+ true
27
+ end
28
+
29
+ private
30
+
31
+ def check_line_ending(line, line_number, expected_type)
32
+ case expected_type
33
+ when 'unix'
34
+ if line.end_with?("\r\n")
35
+ problem(
36
+ line: line_number,
37
+ column: line.length - 1,
38
+ message: 'wrong new line character: expected unix',
39
+ fixable: true
40
+ )
41
+ end
42
+ when 'dos'
43
+ if line.end_with?("\n") && !line.end_with?("\r\n")
44
+ problem(
45
+ line: line_number,
46
+ column: line.length,
47
+ message: 'wrong new line character: expected dos',
48
+ fixable: true
49
+ )
50
+ end
51
+ when 'platform'
52
+ nil
53
+ end
54
+ end
55
+ end
56
+
57
+ Registry.register(NewLines)
58
+ end
59
+ end