a11y-lint 0.6.0 → 0.7.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '041558922708cbcbc98072a22a57ee9c01292eabefc08d7c8ad2e289b89f159c'
4
- data.tar.gz: b6de899716228d66c4a56a33e26e6dc2e55aa216e6a261ae82cef3f7c010b5a0
3
+ metadata.gz: 6fe6daf54c27923c7bb8d7c200baab018d5643ae6d17f1da3116b90b8b9a9b1a
4
+ data.tar.gz: 866c2a9cdbeddc1d8b4c726e89a104b4b193070fb52ec1ae45c6552fee41afe1
5
5
  SHA512:
6
- metadata.gz: d7792835cc5123bc0832ca308ab88e28e51662f6ea1fc597458a5fcd96145e7135d9ad01c486f6efe6436b8f7453f44c8ef4f086bf76d6de7b8fdba271c122d4
7
- data.tar.gz: 2d22327769cc721c03056845c6f13e46ef35a62b265b67114d5dc85eb6f8c656b1bcc3cf3d5d4e7a52fcde4fb7a2de25972ce822006fda0d78f558ade625aa68
6
+ metadata.gz: 1d07bed9bdc71ef0d08f6aa097c5c2550988c11899106e0ceeaaaf54a2c5243449842dd20390b321fdbbcf54811bc53a1487cbb502ac75698224dec99e13599c
7
+ data.tar.gz: a7ef305af11a87604e4f95ca3cfd62afa7c142601d9c081ec2448747414fef7ae32a11020134cebaddb4954c788eec5688251d18332d7079d8b531f98015ab6f
data/.rubocop.yml CHANGED
@@ -7,6 +7,15 @@ Style/StringLiterals:
7
7
  Style/StringLiteralsInInterpolation:
8
8
  EnforcedStyle: double_quotes
9
9
 
10
+ Layout/LineLength:
11
+ Max: 80
12
+ Exclude:
13
+ - "a11y-lint.gemspec"
14
+
10
15
  Metrics/ClassLength:
11
16
  Exclude:
12
17
  - "test/**/*"
18
+
19
+ Metrics/MethodLength:
20
+ Exclude:
21
+ - "test/**/*"
data/CHANGELOG.md CHANGED
@@ -7,6 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.7.1] - 2026-04-13
11
+
12
+ ### Fixed
13
+
14
+ - Slim runner: correct line numbers in templates with multiline backslash continuations
15
+
16
+ ## [0.7.0] - 2026-04-13
17
+
18
+ ### Added
19
+
20
+ - `ListInvalidChildren` rule: detects invalid direct children of `<ul>` and `<ol>` elements (WCAG 1.3.1)
21
+ - `MissingAccessibleName` rule: consolidates `LinkMissingAccessibleName` into a single rule covering `link_to`, `external_link_to`, and `button_tag`
22
+ - Per-rule configuration via `.a11y-lint.yml` file: enable or disable individual rules
23
+ - Place `.a11y-lint.yml` in the project root for automatic detection
24
+ - Use `--config PATH` to specify a custom configuration file path
25
+
26
+ ### Removed
27
+
28
+ - `LinkMissingAccessibleName` rule: replaced by `MissingAccessibleName`
29
+
10
30
  ## [0.6.0] - 2026-03-31
11
31
 
12
32
  ### Added
data/CLAUDE.md CHANGED
@@ -23,10 +23,12 @@ a11y-lint is a Ruby gem (v0.1.0) for accessibility linting. It uses the `A11y::L
23
23
  - **Entry point:** `lib/a11y/lint.rb` — defines the `A11y::Lint` module and `A11y::Lint::Error` exception
24
24
  - **Slim pipeline:** `SlimRunner` parses Slim templates via `Slim::Parser`; `Node` wraps Slim S-expressions
25
25
  - **ERB pipeline:** `ErbRunner` parses ERB templates via Nokogiri; `ErbNode` wraps Nokogiri nodes and extracted `<%= %>` Ruby code
26
- - **Rules:** `lib/a11y/lint/rules/`rules implement `check(node)` against the shared node interface (`tag_name`, `attribute?`, `attributes`, `ruby_code`, `line`)
26
+ - **Configuration:** `lib/a11y/lint/configuration.rb`loads `.a11y-lint.yml` to enable/disable individual rules; searches upward from the target path
27
+ - **Rules:** `lib/a11y/lint/rules/` — organized by WCAG principle (`perceivable/`, `operable/`, `understandable/`, `robust/`); rules implement `check(node)` against the shared node interface (`tag_name`, `attribute?`, `attributes`, `ruby_code`, `line`)
27
28
  - **Version:** `lib/a11y/lint/version.rb`
28
29
  - **Type signatures (RBS):** `sig/a11y/lint.rbs`
29
30
  - **Tests:** `test/` directory using Minitest; test helper at `test/test_helper.rb`
31
+ - **Dummy app:** `test/fixtures/dummy_app/` — a fixture app with Slim/ERB templates for end-to-end smoke testing before releases (`bundle exec a11y-lint test/fixtures/dummy_app`)
30
32
 
31
33
  ## Code Style
32
34
 
data/README.md CHANGED
@@ -39,6 +39,26 @@ With no arguments, it scans the current directory recursively for `.slim` and `.
39
39
  a11y-lint
40
40
  ```
41
41
 
42
+ ### Configuration
43
+
44
+ Create a `.a11y-lint.yml` file in your project root to enable or disable individual rules:
45
+
46
+ ```yaml
47
+ ImgMissingAlt:
48
+ Enabled: false
49
+
50
+ ImageTagMissingAlt:
51
+ Enabled: true
52
+ ```
53
+
54
+ Rules not listed in the file are enabled by default. The linter searches for `.a11y-lint.yml` starting from the target directory and walking up to the filesystem root.
55
+
56
+ To specify a config file explicitly:
57
+
58
+ ```bash
59
+ a11y-lint --config path/to/.a11y-lint.yml app/views/
60
+ ```
61
+
42
62
  ### Ruby API
43
63
 
44
64
  ```ruby
data/lib/a11y/lint/cli.rb CHANGED
@@ -4,12 +4,14 @@ require "optparse"
4
4
 
5
5
  module A11y
6
6
  module Lint
7
- # Command-line interface for running accessibility linting on Slim templates.
7
+ # Command-line interface for running accessibility
8
+ # linting on Slim templates.
8
9
  class CLI
9
10
  def initialize(argv, stdout: $stdout, stderr: $stderr)
10
11
  @argv = argv
11
12
  @stdout = stdout
12
13
  @stderr = stderr
14
+ @config_path = nil
13
15
  end
14
16
 
15
17
  def run
@@ -42,6 +44,10 @@ module A11y
42
44
  exit 0
43
45
  end
44
46
 
47
+ opts.on("-c", "--config PATH", "Path to configuration file") do |path|
48
+ @config_path = path
49
+ end
50
+
45
51
  opts.on("-h", "--help", "Show help") do
46
52
  @stdout.puts(opts)
47
53
  exit 0
@@ -78,9 +84,16 @@ module A11y
78
84
  end
79
85
 
80
86
  def all_rules
87
+ configuration = Configuration.load(
88
+ @config_path,
89
+ search_path: @argv.first || "."
90
+ )
91
+
81
92
  Rules.constants.filter_map do |name|
82
93
  klass = Rules.const_get(name)
83
- klass.new if klass.is_a?(Class) && klass < Rule
94
+ next unless klass.is_a?(Class) && klass < Rule
95
+
96
+ klass if configuration.enabled?(klass.rule_name)
84
97
  end
85
98
  end
86
99
 
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+
5
+ module A11y
6
+ module Lint
7
+ # Loads and stores rule configuration from a YAML file.
8
+ class Configuration
9
+ DEFAULT_FILE = ".a11y-lint.yml"
10
+
11
+ def initialize(config_hash = {})
12
+ @config = config_hash
13
+ end
14
+
15
+ def self.load(path = nil, search_path: Dir.pwd)
16
+ path ||= find_config_file(search_path)
17
+ return new unless path && File.exist?(path)
18
+
19
+ config_hash = YAML.safe_load_file(path) || {}
20
+ new(config_hash)
21
+ end
22
+
23
+ def self.find_config_file(start_dir)
24
+ dir = File.expand_path(start_dir)
25
+ dir = File.dirname(dir) unless File.directory?(dir)
26
+
27
+ loop do
28
+ candidate = File.join(dir, DEFAULT_FILE)
29
+ return candidate if File.exist?(candidate)
30
+
31
+ parent = File.dirname(dir)
32
+ return nil if parent == dir
33
+
34
+ dir = parent
35
+ end
36
+ end
37
+ private_class_method :find_config_file
38
+
39
+ def enabled?(rule_name)
40
+ return true unless @config.key?(rule_name)
41
+
42
+ @config.dig(rule_name, "Enabled") != false
43
+ end
44
+ end
45
+ end
46
+ end
@@ -2,7 +2,8 @@
2
2
 
3
3
  module A11y
4
4
  module Lint
5
- # Wraps a Nokogiri node or extracted ERB output tag as a queryable node for lint rules.
5
+ # Wraps a Nokogiri node or extracted ERB output tag
6
+ # as a queryable node for lint rules.
6
7
  class ErbNode
7
8
  attr_reader :line
8
9
 
@@ -28,13 +29,24 @@ module A11y
28
29
  @ruby_code_string
29
30
  end
30
31
 
32
+ # Returns direct element children wrapped as ErbNode objects.
33
+ def children
34
+ return [] unless @nokogiri_node
35
+
36
+ @nokogiri_node.element_children.map do |child|
37
+ ErbNode.new(nokogiri_node: child, line: child.line)
38
+ end
39
+ end
40
+
31
41
  private
32
42
 
33
43
  def extract_attributes
34
44
  return {} unless @nokogiri_node
35
45
 
36
- @nokogiri_node.attributes.each_with_object({}) do |(name, _attr), result|
37
- result[name] = true
46
+ @nokogiri_node
47
+ .attributes
48
+ .each_with_object({}) do |(name, _attr), result|
49
+ result[name] = true
38
50
  end
39
51
  end
40
52
  end
@@ -34,7 +34,10 @@ module A11y
34
34
  doc.traverse do |nokogiri_node|
35
35
  next unless nokogiri_node.element?
36
36
 
37
- node = ErbNode.new(nokogiri_node: nokogiri_node, line: nokogiri_node.line)
37
+ node = ErbNode.new(
38
+ nokogiri_node: nokogiri_node,
39
+ line: nokogiri_node.line
40
+ )
38
41
  check_node(node)
39
42
  end
40
43
  end
@@ -50,12 +53,12 @@ module A11y
50
53
  end
51
54
 
52
55
  def check_node(node)
53
- rules.each do |rule|
54
- message = rule.check(node)
56
+ rules.each do |rule_class|
57
+ message = rule_class.check(node)
55
58
  next unless message
56
59
 
57
60
  @offenses << Offense.new(
58
- rule: rule.name,
61
+ rule: rule_class.rule_name,
59
62
  filename: @filename,
60
63
  line: node.line,
61
64
  message: message
@@ -29,8 +29,40 @@ module A11y
29
29
  @attributes ||= extract_attributes
30
30
  end
31
31
 
32
+ # Returns direct HTML element children as Node objects.
33
+ # Walks through [:multi] and [:slim, :control] wrappers so that tags
34
+ # nested inside control flow are still treated as direct children.
35
+ # Opaque [:slim, :output] blocks are skipped.
36
+ def children
37
+ return [] unless html_tag?
38
+
39
+ body = @sexp[4]
40
+ collect_children(body)
41
+ end
42
+
32
43
  private
33
44
 
45
+ def html_tag?
46
+ @sexp[0] == :html && @sexp[1] == :tag
47
+ end
48
+
49
+ def collect_children(sexp)
50
+ return [] unless sexp.is_a?(Array)
51
+ return [Node.new(sexp, line: @line)] if html_tag_sexp?(sexp)
52
+ return collect_children(sexp[3]) if slim_control_sexp?(sexp)
53
+ return [] unless sexp[0] == :multi
54
+
55
+ sexp[1..].flat_map { |c| collect_children(c) }
56
+ end
57
+
58
+ def html_tag_sexp?(sexp)
59
+ sexp[0] == :html && sexp[1] == :tag
60
+ end
61
+
62
+ def slim_control_sexp?(sexp)
63
+ sexp[0] == :slim && sexp[1] == :control
64
+ end
65
+
34
66
  def extract_attributes
35
67
  return {} unless html_attributes?
36
68
 
@@ -4,11 +4,19 @@ module A11y
4
4
  module Lint
5
5
  # Base class for accessibility lint rules.
6
6
  class Rule
7
- def name
8
- self.class.name.split("::").last
7
+ def self.check(node)
8
+ new(node).check
9
9
  end
10
10
 
11
- def check(node)
11
+ def self.rule_name
12
+ name.split("::").last
13
+ end
14
+
15
+ def initialize(node)
16
+ @node = node
17
+ end
18
+
19
+ def check
12
20
  raise NotImplementedError
13
21
  end
14
22
  end
@@ -7,16 +7,16 @@ module A11y
7
7
  module Rules
8
8
  # Checks that image_tag calls include an alt option (WCAG 1.1.1).
9
9
  class ImageTagMissingAlt < Rule
10
- def check(node)
11
- return unless an_image_tag_without_an_alt_attribute?(node)
10
+ def check
11
+ return unless an_image_tag_without_an_alt_attribute?
12
12
 
13
13
  "image_tag is missing an alt option (WCAG 1.1.1)"
14
14
  end
15
15
 
16
16
  private
17
17
 
18
- def an_image_tag_without_an_alt_attribute?(node)
19
- code = node.ruby_code
18
+ def an_image_tag_without_an_alt_attribute?
19
+ code = @node.ruby_code
20
20
  return false unless code
21
21
 
22
22
  sexp = Ripper.sexp(code)
@@ -26,6 +26,8 @@ module A11y
26
26
  call && !alt_key_within?(call)
27
27
  end
28
28
 
29
+ # Walks the Ripper S-expression tree to find
30
+ # the image_tag call node, if present.
29
31
  def extract_image_tag_call(sexp)
30
32
  return unless sexp.is_a?(Array)
31
33
  return sexp if image_tag_call?(sexp)
@@ -38,6 +40,9 @@ module A11y
38
40
  nil
39
41
  end
40
42
 
43
+ # Matches both calling styles:
44
+ # image_tag "photo.jpg" => :command
45
+ # image_tag("photo.jpg") => :method_add_arg
41
46
  def image_tag_call?(sexp)
42
47
  case sexp
43
48
  in [:command, [:@ident, "image_tag", *], *] then true
@@ -46,6 +51,8 @@ module A11y
46
51
  end
47
52
  end
48
53
 
54
+ # Recursively searches the sexp for an
55
+ # :assoc_new node whose key is "alt".
49
56
  def alt_key_within?(sexp)
50
57
  return true if alt_key?(sexp)
51
58
  return false unless sexp.is_a?(Array)
@@ -53,12 +60,29 @@ module A11y
53
60
  sexp.any? { |child| alt_key_within?(child) }
54
61
  end
55
62
 
63
+ # Checks if a sexp is a hash pair (assoc_new)
64
+ # with "alt" as the key.
56
65
  def alt_key?(sexp)
57
66
  return false unless sexp.is_a?(Array) && sexp[0] == :assoc_new
58
67
 
59
- key = sexp[1]
60
- (key in [:@label, "alt:", *]) ||
61
- (key in [:string_literal, [:string_content, [:@tstring_content, "alt", *]]])
68
+ alt_key_value?(sexp[1])
69
+ end
70
+
71
+ def alt_key_value?(key)
72
+ alt_symbol_key?(key) || alt_string_key?(key)
73
+ end
74
+
75
+ # Matches symbol-style key: `alt: "..."`
76
+ def alt_symbol_key?(key)
77
+ key in [:@label, "alt:", *]
78
+ end
79
+
80
+ # Matches string-style key: `"alt" => "..."`
81
+ def alt_string_key?(key)
82
+ key in [
83
+ :string_literal,
84
+ [:string_content, [:@tstring_content, "alt", *]]
85
+ ]
62
86
  end
63
87
  end
64
88
  end
@@ -5,16 +5,16 @@ module A11y
5
5
  module Rules
6
6
  # Checks that img tags include an alt attribute (WCAG 1.1.1).
7
7
  class ImgMissingAlt < Rule
8
- def check(node)
9
- return unless an_image_without_an_alt_attribute?(node)
8
+ def check
9
+ return unless an_image_without_an_alt_attribute?
10
10
 
11
11
  "img tag is missing an alt attribute (WCAG 1.1.1)"
12
12
  end
13
13
 
14
14
  private
15
15
 
16
- def an_image_without_an_alt_attribute?(node)
17
- node.tag_name == "img" && !node.attribute?("alt")
16
+ def an_image_without_an_alt_attribute?
17
+ @node.tag_name == "img" && !@node.attribute?("alt")
18
18
  end
19
19
  end
20
20
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module A11y
4
+ module Lint
5
+ module Rules
6
+ # Checks that <ul> and <ol> only directly contain <li>, <script>,
7
+ # or <template> elements (WCAG 1.3.1).
8
+ class ListInvalidChildren < Rule
9
+ LIST_TAGS = %w[ul ol].freeze
10
+ ALLOWED_CHILDREN = %w[li script template].freeze
11
+
12
+ def check
13
+ return unless list_with_invalid_children?
14
+
15
+ offense_message(@node.tag_name, invalid_children.first.tag_name)
16
+ end
17
+
18
+ private
19
+
20
+ def list_with_invalid_children?
21
+ LIST_TAGS.include?(@node.tag_name) && invalid_children.any?
22
+ end
23
+
24
+ def invalid_children
25
+ @invalid_children ||= @node.children.reject do |child|
26
+ ALLOWED_CHILDREN.include?(child.tag_name)
27
+ end
28
+ end
29
+
30
+ def offense_message(parent, child)
31
+ "<#{parent}> must only directly contain <li>, <script>, " \
32
+ "or <template> elements, found <#{child}> (WCAG 1.3.1)"
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -5,54 +5,72 @@ require "ripper"
5
5
  module A11y
6
6
  module Lint
7
7
  module Rules
8
- # Checks that link_to / external_link_to calls with empty text
9
- # or block content include an aria-label (WCAG 4.1.2).
10
- class LinkMissingAccessibleName < Rule
11
- LINK_METHODS = %w[link_to external_link_to].freeze
8
+ # Checks that link_to, external_link_to, and button_tag calls with
9
+ # empty text or block content include an aria-label (WCAG 4.1.2).
10
+ class MissingAccessibleName < Rule
11
+ METHODS = %w[link_to external_link_to button_tag].freeze
12
12
 
13
- def check(node)
14
- code = node.ruby_code
15
- return unless code
13
+ def check
14
+ return unless (code = @node.ruby_code)
16
15
 
17
16
  clean_code = code.sub(/\s+do\s*\z/, "")
18
17
  is_block = clean_code != code
19
- call = parse_link_call(clean_code)
18
+ call = parse_call(clean_code)
20
19
  return unless call
21
20
  return if aria_label_within?(call)
22
21
  return unless first_arg_empty_string?(call) || is_block
23
22
 
24
- "link missing an accessible name requires an aria-label (WCAG 4.1.2)"
23
+ offense_message(extract_method_name(call))
25
24
  end
26
25
 
27
26
  private
28
27
 
29
- def parse_link_call(code)
28
+ def offense_message(method_name)
29
+ <<~MSG.strip
30
+ #{method_name} missing an accessible name \
31
+ requires an aria-label (WCAG 4.1.2)
32
+ MSG
33
+ end
34
+
35
+ def parse_call(code)
30
36
  sexp = Ripper.sexp(code)
31
37
  return unless sexp
32
38
 
33
- extract_link_call(sexp)
39
+ extract_matching_call(sexp)
34
40
  end
35
41
 
36
- def extract_link_call(sexp)
42
+ def extract_matching_call(sexp)
37
43
  return unless sexp.is_a?(Array)
38
- return sexp if link_call?(sexp)
44
+ return sexp if matching_call?(sexp)
39
45
 
40
46
  sexp.each do |child|
41
- result = extract_link_call(child)
47
+ result = extract_matching_call(child)
42
48
  return result if result
43
49
  end
44
50
 
45
51
  nil
46
52
  end
47
53
 
48
- def link_call?(sexp)
54
+ def matching_call?(sexp)
55
+ name = call_method_name(sexp)
56
+ name ? METHODS.include?(name) : false
57
+ end
58
+
59
+ def call_method_name(sexp)
49
60
  case sexp
50
- in [:command, [:@ident, name, *], *] if LINK_METHODS.include?(name) then true
51
- in [:method_add_arg, [:fcall, [:@ident, name, *]], *] if LINK_METHODS.include?(name) then true
52
- else false
61
+ in [:command, [:@ident, name, *], *]
62
+ name
63
+ in [:method_add_arg,
64
+ [:fcall, [:@ident, name, *]], *]
65
+ name
66
+ else nil
53
67
  end
54
68
  end
55
69
 
70
+ def extract_method_name(call)
71
+ call_method_name(call)
72
+ end
73
+
56
74
  def first_arg_empty_string?(call)
57
75
  args = extract_args(call)
58
76
  return false unless args&.first
@@ -63,7 +81,9 @@ module A11y
63
81
  def extract_args(call)
64
82
  case call
65
83
  in [:command, _, [:args_add_block, args, *]] then args
66
- in [:method_add_arg, _, [:arg_paren, [:args_add_block, args, *]]] then args
84
+ in [:method_add_arg, _,
85
+ [:arg_paren, [:args_add_block, args, *]]]
86
+ then args
67
87
  in [:method_add_arg, _, [:arg_paren, Array => args]] then args
68
88
  else nil
69
89
  end
@@ -94,13 +114,17 @@ module A11y
94
114
  end
95
115
 
96
116
  def label_key?(sexp)
97
- sexp.is_a?(Array) && sexp[0] == :assoc_new && (sexp[1] in [:@label, "label:", *])
117
+ sexp.is_a?(Array) &&
118
+ sexp[0] == :assoc_new &&
119
+ (sexp[1] in [:@label, "label:", *])
98
120
  end
99
121
 
100
122
  def aria_label_string_key?(sexp)
101
123
  return false unless sexp.is_a?(Array) && sexp[0] == :assoc_new
102
124
 
103
- sexp[1] in [:string_literal, [:string_content, [:@tstring_content, "aria-label", *]]]
125
+ sexp[1] in [:string_literal,
126
+ [:string_content,
127
+ [:@tstring_content, "aria-label", *]]]
104
128
  end
105
129
  end
106
130
  end
@@ -27,6 +27,7 @@ module A11y
27
27
  @line += 1 if sexp[0] == :newline
28
28
  new_node = Node.new(sexp, line: @line)
29
29
  check_node(new_node) if html_tag?(sexp) || slim_output?(sexp)
30
+ @line += continuation_newlines(sexp)
30
31
  sexp.each { |child| walk(child) }
31
32
  end
32
33
 
@@ -38,17 +39,30 @@ module A11y
38
39
  sexp[0] == :slim && sexp[1] == :output
39
40
  end
40
41
 
42
+ # Counts extra source lines consumed by backslash-continued
43
+ # multiline expressions in :output and :control nodes.
44
+ # Slim collapses these into one AST node whose ruby_code
45
+ # string retains the original newlines.
46
+ def continuation_newlines(sexp)
47
+ code = case sexp
48
+ in [:slim, :output, _, String => c, *] then c
49
+ in [:slim, :control, String => c, *] then c
50
+ else return 0
51
+ end
52
+ code.count("\n")
53
+ end
54
+
41
55
  def node?(sexp)
42
56
  sexp.is_a?(Array) && !sexp.empty? && sexp[0].is_a?(Symbol)
43
57
  end
44
58
 
45
59
  def check_node(node)
46
- rules.each do |rule|
47
- message = rule.check(node)
60
+ rules.each do |rule_class|
61
+ message = rule_class.check(node)
48
62
  next unless message
49
63
 
50
64
  @offenses << Offense.new(
51
- rule: rule.name,
65
+ rule: rule_class.rule_name,
52
66
  filename: @filename,
53
67
  line: node.line,
54
68
  message: message
@@ -2,6 +2,6 @@
2
2
 
3
3
  module A11y
4
4
  module Lint
5
- VERSION = "0.6.0"
5
+ VERSION = "0.7.1"
6
6
  end
7
7
  end
data/lib/a11y/lint.rb CHANGED
@@ -6,10 +6,12 @@ require_relative "lint/version"
6
6
  require_relative "lint/offense"
7
7
  require_relative "lint/node"
8
8
  require_relative "lint/erb_node"
9
+ require_relative "lint/configuration"
9
10
  require_relative "lint/rule"
10
- require_relative "lint/rules/image_tag_missing_alt"
11
- require_relative "lint/rules/img_missing_alt"
12
- require_relative "lint/rules/link_missing_accessible_name"
11
+ require_relative "lint/rules/perceivable/image_tag_missing_alt"
12
+ require_relative "lint/rules/perceivable/img_missing_alt"
13
+ require_relative "lint/rules/perceivable/list_invalid_children"
14
+ require_relative "lint/rules/robust/missing_accessible_name"
13
15
  require_relative "lint/slim_runner"
14
16
  require_relative "lint/erb_runner"
15
17
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: a11y-lint
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Abdullah Hashim
@@ -56,14 +56,16 @@ files:
56
56
  - exe/a11y-lint
57
57
  - lib/a11y/lint.rb
58
58
  - lib/a11y/lint/cli.rb
59
+ - lib/a11y/lint/configuration.rb
59
60
  - lib/a11y/lint/erb_node.rb
60
61
  - lib/a11y/lint/erb_runner.rb
61
62
  - lib/a11y/lint/node.rb
62
63
  - lib/a11y/lint/offense.rb
63
64
  - lib/a11y/lint/rule.rb
64
- - lib/a11y/lint/rules/image_tag_missing_alt.rb
65
- - lib/a11y/lint/rules/img_missing_alt.rb
66
- - lib/a11y/lint/rules/link_missing_accessible_name.rb
65
+ - lib/a11y/lint/rules/perceivable/image_tag_missing_alt.rb
66
+ - lib/a11y/lint/rules/perceivable/img_missing_alt.rb
67
+ - lib/a11y/lint/rules/perceivable/list_invalid_children.rb
68
+ - lib/a11y/lint/rules/robust/missing_accessible_name.rb
67
69
  - lib/a11y/lint/slim_runner.rb
68
70
  - lib/a11y/lint/version.rb
69
71
  - sig/a11y/lint.rbs