@herb-tools/linter 0.6.1 → 0.7.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 (93) hide show
  1. package/README.md +60 -16
  2. package/dist/herb-lint.js +364 -181
  3. package/dist/herb-lint.js.map +1 -1
  4. package/dist/index.cjs +321 -100
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.js +270 -89
  7. package/dist/index.js.map +1 -1
  8. package/dist/package.json +11 -5
  9. package/dist/src/cli/argument-parser.js +11 -6
  10. package/dist/src/cli/argument-parser.js.map +1 -1
  11. package/dist/src/cli/file-processor.js +5 -6
  12. package/dist/src/cli/file-processor.js.map +1 -1
  13. package/dist/src/cli/formatters/detailed-formatter.js +3 -5
  14. package/dist/src/cli/formatters/detailed-formatter.js.map +1 -1
  15. package/dist/src/cli/formatters/github-actions-formatter.js +55 -11
  16. package/dist/src/cli/formatters/github-actions-formatter.js.map +1 -1
  17. package/dist/src/cli/index.js +1 -0
  18. package/dist/src/cli/index.js.map +1 -1
  19. package/dist/src/cli/output-manager.js +23 -5
  20. package/dist/src/cli/output-manager.js.map +1 -1
  21. package/dist/src/cli/summary-reporter.js +2 -11
  22. package/dist/src/cli/summary-reporter.js.map +1 -1
  23. package/dist/src/cli.js +88 -4
  24. package/dist/src/cli.js.map +1 -1
  25. package/dist/src/default-rules.js +8 -4
  26. package/dist/src/default-rules.js.map +1 -1
  27. package/dist/src/linter.js.map +1 -1
  28. package/dist/src/rules/erb-prefer-image-tag-helper.js +1 -1
  29. package/dist/src/rules/erb-prefer-image-tag-helper.js.map +1 -1
  30. package/dist/src/rules/html-boolean-attributes-no-value.js +8 -8
  31. package/dist/src/rules/html-boolean-attributes-no-value.js.map +1 -1
  32. package/dist/src/rules/html-no-empty-attributes.js +56 -0
  33. package/dist/src/rules/html-no-empty-attributes.js.map +1 -0
  34. package/dist/src/rules/html-no-positive-tab-index.js +1 -1
  35. package/dist/src/rules/html-no-positive-tab-index.js.map +1 -1
  36. package/dist/src/rules/html-no-underscores-in-attribute-names.js +36 -0
  37. package/dist/src/rules/html-no-underscores-in-attribute-names.js.map +1 -0
  38. package/dist/src/rules/index.js +3 -0
  39. package/dist/src/rules/index.js.map +1 -1
  40. package/dist/src/rules/rule-utils.js +11 -7
  41. package/dist/src/rules/rule-utils.js.map +1 -1
  42. package/dist/src/rules/svg-tag-name-capitalization.js +2 -2
  43. package/dist/src/rules/svg-tag-name-capitalization.js.map +1 -1
  44. package/dist/tsconfig.tsbuildinfo +1 -1
  45. package/dist/types/cli/argument-parser.d.ts +2 -1
  46. package/dist/types/cli/file-processor.d.ts +6 -1
  47. package/dist/types/cli/formatters/github-actions-formatter.d.ts +6 -1
  48. package/dist/types/cli/index.d.ts +1 -0
  49. package/dist/types/cli/output-manager.d.ts +1 -0
  50. package/dist/types/cli.d.ts +20 -5
  51. package/dist/types/linter.d.ts +7 -7
  52. package/dist/types/rules/html-no-empty-attributes.d.ts +7 -0
  53. package/dist/types/rules/html-no-underscores-in-attribute-names.d.ts +7 -0
  54. package/dist/types/rules/index.d.ts +3 -0
  55. package/dist/types/rules/rule-utils.d.ts +7 -5
  56. package/dist/types/src/cli/argument-parser.d.ts +2 -1
  57. package/dist/types/src/cli/file-processor.d.ts +6 -1
  58. package/dist/types/src/cli/formatters/github-actions-formatter.d.ts +6 -1
  59. package/dist/types/src/cli/index.d.ts +1 -0
  60. package/dist/types/src/cli/output-manager.d.ts +1 -0
  61. package/dist/types/src/cli.d.ts +20 -5
  62. package/dist/types/src/linter.d.ts +7 -7
  63. package/dist/types/src/rules/html-no-empty-attributes.d.ts +7 -0
  64. package/dist/types/src/rules/html-no-underscores-in-attribute-names.d.ts +7 -0
  65. package/dist/types/src/rules/index.d.ts +3 -0
  66. package/dist/types/src/rules/rule-utils.d.ts +7 -5
  67. package/docs/rules/README.md +2 -0
  68. package/docs/rules/html-img-require-alt.md +0 -2
  69. package/docs/rules/html-no-empty-attributes.md +77 -0
  70. package/docs/rules/html-no-underscores-in-attribute-names.md +45 -0
  71. package/package.json +11 -5
  72. package/src/cli/argument-parser.ts +15 -7
  73. package/src/cli/file-processor.ts +11 -7
  74. package/src/cli/formatters/detailed-formatter.ts +5 -7
  75. package/src/cli/formatters/github-actions-formatter.ts +64 -11
  76. package/src/cli/index.ts +2 -0
  77. package/src/cli/output-manager.ts +27 -5
  78. package/src/cli/summary-reporter.ts +3 -11
  79. package/src/cli.ts +125 -20
  80. package/src/default-rules.ts +8 -4
  81. package/src/linter.ts +6 -6
  82. package/src/rules/erb-no-silent-tag-in-attribute-name.ts +1 -1
  83. package/src/rules/erb-prefer-image-tag-helper.ts +2 -2
  84. package/src/rules/erb-require-whitespace-inside-tags.ts +2 -2
  85. package/src/rules/html-attribute-double-quotes.ts +1 -1
  86. package/src/rules/html-boolean-attributes-no-value.ts +9 -11
  87. package/src/rules/html-no-empty-attributes.ts +75 -0
  88. package/src/rules/html-no-positive-tab-index.ts +1 -1
  89. package/src/rules/html-no-underscores-in-attribute-names.ts +58 -0
  90. package/src/rules/html-tag-name-lowercase.ts +1 -1
  91. package/src/rules/index.ts +3 -0
  92. package/src/rules/rule-utils.ts +15 -11
  93. package/src/rules/svg-tag-name-capitalization.ts +2 -2
@@ -58,7 +58,7 @@ class RequireWhitespaceInsideTags extends BaseRuleVisitor {
58
58
  }
59
59
 
60
60
  private checkOpenTagWhitespace(openTag: Token, content:string):void {
61
- if (content.startsWith(" ") || content.startsWith("\n")) {
61
+ if (content.startsWith(" ") || content.startsWith("\n")) {
62
62
  return
63
63
  }
64
64
 
@@ -70,7 +70,7 @@ class RequireWhitespaceInsideTags extends BaseRuleVisitor {
70
70
  }
71
71
 
72
72
  private checkCloseTagWhitespace(closeTag: Token, content:string):void {
73
- if (content.endsWith(" ") || content.endsWith("\n")) {
73
+ if (content.endsWith(" ") || content.endsWith("\n")) {
74
74
  return
75
75
  }
76
76
 
@@ -1,6 +1,6 @@
1
1
  import { ParserRule } from "../types.js"
2
2
  import { AttributeVisitorMixin, StaticAttributeStaticValueParams, StaticAttributeDynamicValueParams, getAttributeValueQuoteType, hasAttributeValue } from "./rule-utils.js"
3
- import { filterLiteralNodes } from "@herb-tools/core"
3
+ import { filterLiteralNodes } from "@herb-tools/core"
4
4
 
5
5
  import type { LintOffense, LintContext } from "../types.js"
6
6
  import type { ParseResult } from "@herb-tools/core"
@@ -1,27 +1,25 @@
1
1
  import { ParserRule } from "../types.js"
2
2
  import { AttributeVisitorMixin, StaticAttributeStaticValueParams, StaticAttributeDynamicValueParams, isBooleanAttribute, hasAttributeValue } from "./rule-utils.js"
3
+ import { IdentityPrinter } from "@herb-tools/printer"
3
4
 
4
5
  import type { LintOffense, LintContext } from "../types.js"
5
- import type { ParseResult } from "@herb-tools/core"
6
+ import type { ParseResult, HTMLAttributeNode } from "@herb-tools/core"
6
7
 
7
8
  class BooleanAttributesNoValueVisitor extends AttributeVisitorMixin {
8
- protected checkStaticAttributeStaticValue({ attributeName, attributeNode }: StaticAttributeStaticValueParams) {
9
- if (!isBooleanAttribute(attributeName)) return
10
- if (!hasAttributeValue(attributeNode)) return
9
+ protected checkStaticAttributeStaticValue({ originalAttributeName, attributeNode }: StaticAttributeStaticValueParams) {
10
+ this.checkAttribute(originalAttributeName, attributeNode)
11
+ }
11
12
 
12
- this.addOffense(
13
- `Boolean attribute \`${attributeName}\` should not have a value. Use \`${attributeName}\` instead of \`${attributeName}="${attributeName}"\`.`,
14
- attributeNode.value!.location,
15
- "error"
16
- )
13
+ protected checkStaticAttributeDynamicValue({ originalAttributeName, attributeNode }: StaticAttributeDynamicValueParams) {
14
+ this.checkAttribute(originalAttributeName, attributeNode)
17
15
  }
18
16
 
19
- protected checkStaticAttributeDynamicValue({ attributeName, attributeNode, combinedValue }: StaticAttributeDynamicValueParams) {
17
+ private checkAttribute(attributeName: string, attributeNode: HTMLAttributeNode) {
20
18
  if (!isBooleanAttribute(attributeName)) return
21
19
  if (!hasAttributeValue(attributeNode)) return
22
20
 
23
21
  this.addOffense(
24
- `Boolean attribute \`${attributeName}\` should not have a value. Use \`${attributeName}\` instead of \`${attributeName}="${combinedValue}"\`.`,
22
+ `Boolean attribute \`${IdentityPrinter.print(attributeNode.name)}\` should not have a value. Use \`${attributeName.toLowerCase()}\` instead of \`${IdentityPrinter.print(attributeNode)}\`.`,
25
23
  attributeNode.value!.location,
26
24
  "error"
27
25
  )
@@ -0,0 +1,75 @@
1
+ import { ParserRule } from "../types.js"
2
+ import { AttributeVisitorMixin, StaticAttributeStaticValueParams, DynamicAttributeStaticValueParams } from "./rule-utils.js"
3
+
4
+ import type { LintOffense, LintContext } from "../types.js"
5
+ import type { ParseResult } from "@herb-tools/core"
6
+
7
+ // Attributes that must not have empty values
8
+ const RESTRICTED_ATTRIBUTES = new Set([
9
+ 'id',
10
+ 'class',
11
+ 'name',
12
+ 'for',
13
+ 'src',
14
+ 'href',
15
+ 'title',
16
+ 'data',
17
+ 'role'
18
+ ])
19
+
20
+ // Check if attribute name matches any restricted patterns
21
+ function isRestrictedAttribute(attributeName: string): boolean {
22
+ // Check direct matches
23
+ if (RESTRICTED_ATTRIBUTES.has(attributeName)) {
24
+ return true
25
+ }
26
+
27
+ // Check for data-* attributes
28
+ if (attributeName.startsWith('data-')) {
29
+ return true
30
+ }
31
+
32
+ // Check for aria-* attributes
33
+ if (attributeName.startsWith('aria-')) {
34
+ return true
35
+ }
36
+
37
+ return false
38
+ }
39
+
40
+ class NoEmptyAttributesVisitor extends AttributeVisitorMixin {
41
+ protected checkStaticAttributeStaticValue({ attributeName, attributeValue, attributeNode }: StaticAttributeStaticValueParams): void {
42
+ if (!isRestrictedAttribute(attributeName)) return
43
+ if (attributeValue.trim() !== "") return
44
+
45
+ this.addOffense(
46
+ `Attribute \`${attributeName}\` must not be empty. Either provide a meaningful value or remove the attribute entirely.`,
47
+ attributeNode.name!.location,
48
+ "warning"
49
+ )
50
+ }
51
+
52
+ protected checkDynamicAttributeStaticValue({ combinedName, attributeValue, attributeNode }: DynamicAttributeStaticValueParams): void {
53
+ const name = (combinedName || "").toLowerCase()
54
+ if (!isRestrictedAttribute(name)) return
55
+ if (attributeValue.trim() !== "") return
56
+
57
+ this.addOffense(
58
+ `Attribute \`${combinedName}\` must not be empty. Either provide a meaningful value or remove the attribute entirely.`,
59
+ attributeNode.name!.location,
60
+ "warning"
61
+ )
62
+ }
63
+ }
64
+
65
+ export class HTMLNoEmptyAttributesRule extends ParserRule {
66
+ name = "html-no-empty-attributes"
67
+
68
+ check(result: ParseResult, context?: Partial<LintContext>): LintOffense[] {
69
+ const visitor = new NoEmptyAttributesVisitor(this.name, context)
70
+
71
+ visitor.visit(result.value)
72
+
73
+ return visitor.offenses
74
+ }
75
+ }
@@ -12,7 +12,7 @@ class NoPositiveTabIndexVisitor extends AttributeVisitorMixin {
12
12
 
13
13
  if (!isNaN(tabIndexValue) && tabIndexValue > 0) {
14
14
  this.addOffense(
15
- `Do not use positive \`tabindex\` values as they are error prone and can severely disrupt navigation experience for keyboard users. Use \`tabindex="0"\` to make an element focusable or \`tabindex=\"-1\"\` to remove it from the tab sequence.`,
15
+ `Do not use positive \`tabindex\` values as they are error prone and can severely disrupt navigation experience for keyboard users. Use \`tabindex="0"\` to make an element focusable or \`tabindex="-1"\` to remove it from the tab sequence.`,
16
16
  attributeNode.location,
17
17
  "error"
18
18
  )
@@ -0,0 +1,58 @@
1
+ import { ParserRule } from "../types.js"
2
+ import {
3
+ AttributeVisitorMixin,
4
+ StaticAttributeStaticValueParams,
5
+ StaticAttributeDynamicValueParams,
6
+ DynamicAttributeStaticValueParams,
7
+ DynamicAttributeDynamicValueParams
8
+ } from "./rule-utils.js"
9
+ import { getStaticContentFromNodes } from "@herb-tools/core"
10
+ import { IdentityPrinter } from "@herb-tools/printer"
11
+ import type { LintContext, LintOffense } from "../types.js"
12
+ import type { ParseResult, HTMLAttributeNode } from "@herb-tools/core"
13
+
14
+ class HTMLNoUnderscoresInAttributeNamesVisitor extends AttributeVisitorMixin {
15
+ protected checkStaticAttributeStaticValue({ attributeName, attributeNode }: StaticAttributeStaticValueParams): void {
16
+ this.check(attributeName, attributeNode)
17
+ }
18
+
19
+ protected checkStaticAttributeDynamicValue({ attributeName, attributeNode }: StaticAttributeDynamicValueParams): void {
20
+ this.check(attributeName, attributeNode)
21
+ }
22
+
23
+ protected checkDynamicAttributeStaticValue({ nameNodes, attributeNode }: DynamicAttributeStaticValueParams) {
24
+ const attributeName = getStaticContentFromNodes(nameNodes)
25
+
26
+ this.check(attributeName, attributeNode)
27
+ }
28
+
29
+ protected checkDynamicAttributeDynamicValue({ nameNodes, attributeNode }: DynamicAttributeDynamicValueParams) {
30
+ const attributeName = getStaticContentFromNodes(nameNodes)
31
+
32
+ this.check(attributeName, attributeNode)
33
+ }
34
+
35
+ private check(attributeName: string | null, attributeNode: HTMLAttributeNode): void {
36
+ if (!attributeName) return
37
+
38
+ if (attributeName.includes("_")) {
39
+ this.addOffense(
40
+ `Attribute \`${IdentityPrinter.print(attributeNode.name)}\` should not contain underscores. Use hyphens (-) instead.`,
41
+ attributeNode.value!.location,
42
+ "warning"
43
+ )
44
+ }
45
+ }
46
+ }
47
+
48
+ export class HTMLNoUnderscoresInAttributeNamesRule extends ParserRule {
49
+ name = "html-no-underscores-in-attribute-names"
50
+
51
+ check(result: ParseResult, context?: Partial<LintContext>): LintOffense[] {
52
+ const visitor = new HTMLNoUnderscoresInAttributeNamesVisitor(this.name, context)
53
+
54
+ visitor.visit(result.value)
55
+
56
+ return visitor.offenses
57
+ }
58
+ }
@@ -36,7 +36,7 @@ class TagNameLowercaseVisitor extends BaseRuleVisitor {
36
36
  this.checkTagName(node)
37
37
  }
38
38
 
39
- private checkTagName(node: HTMLOpenTagNode | HTMLCloseTagNode | null): void {
39
+ private checkTagName(node: HTMLOpenTagNode | HTMLCloseTagNode | null): void {
40
40
  if (!node) return
41
41
 
42
42
  const tagName = getTagName(node)
@@ -1,3 +1,4 @@
1
+ export * from "./rule-utils.js"
1
2
  export * from "./erb-no-empty-tags.js"
2
3
  export * from "./erb-no-output-control-flow.js"
3
4
  export * from "./erb-no-silent-tag-in-attribute-name.js"
@@ -20,6 +21,7 @@ export * from "./html-no-aria-hidden-on-focusable.js"
20
21
  export * from "./html-no-block-inside-inline.js"
21
22
  export * from "./html-no-duplicate-attributes.js"
22
23
  export * from "./html-no-duplicate-ids.js"
24
+ export * from "./html-no-empty-attributes.js"
23
25
  export * from "./html-no-empty-headings.js"
24
26
  export * from "./html-no-nested-links.js"
25
27
  export * from "./html-no-positive-tab-index.js"
@@ -27,3 +29,4 @@ export * from "./html-no-self-closing.js"
27
29
  export * from "./html-no-title-attribute.js"
28
30
  export * from "./html-tag-name-lowercase.js"
29
31
  export * from "./svg-tag-name-capitalization.js"
32
+ export * from "./html-no-underscores-in-attribute-names.js"
@@ -24,8 +24,6 @@ import type {
24
24
  Node
25
25
  } from "@herb-tools/core"
26
26
 
27
- import { IdentityPrinter } from "@herb-tools/printer"
28
-
29
27
  import { DEFAULT_LINT_CONTEXT } from "../types.js"
30
28
 
31
29
  import type * as Nodes from "@herb-tools/core"
@@ -180,11 +178,13 @@ export function getTagName(node: HTMLOpenTagNode): string | null {
180
178
  * Gets the attribute name from an HTMLAttributeNode (lowercased)
181
179
  * Returns null if the attribute name contains dynamic content (ERB)
182
180
  */
183
- export function getAttributeName(attributeNode: HTMLAttributeNode): string | null {
181
+ export function getAttributeName(attributeNode: HTMLAttributeNode, lowercase = true): string | null {
184
182
  if (attributeNode.name?.type === "AST_HTML_ATTRIBUTE_NAME_NODE") {
185
183
  const nameNode = attributeNode.name as HTMLAttributeNameNode
186
184
  const staticName = getStaticAttributeName(nameNode)
187
185
 
186
+ if (!lowercase) return staticName
187
+
188
188
  return staticName ? staticName.toLowerCase() : null
189
189
  }
190
190
 
@@ -287,7 +287,7 @@ export function getStaticAttributeValueContent(attributeNode: HTMLAttributeNode)
287
287
  * Gets the attribute value content from an HTMLAttributeValueNode
288
288
  */
289
289
  export function getAttributeValue(attributeNode: HTMLAttributeNode): string | null {
290
- const valueNode: HTMLAttributeValueNode | null = attributeNode.value as HTMLAttributeValueNode
290
+ const valueNode: HTMLAttributeValueNode | null = attributeNode.value as HTMLAttributeValueNode
291
291
 
292
292
  if (valueNode === null) return null
293
293
 
@@ -381,7 +381,7 @@ export function hasAttribute(node: HTMLOpenTagNode, attributeName: string): bool
381
381
  /**
382
382
  * Checks if a tag has a specific attribute
383
383
  */
384
- export function getAttribute(node: HTMLOpenTagNode, attributeName: string): HTMLAttributeNode | null {
384
+ export function getAttribute(node: HTMLOpenTagNode, attributeName: string): HTMLAttributeNode | null {
385
385
  const attributes = getAttributes(node)
386
386
 
387
387
  return findAttributeByName(attributes, attributeName)
@@ -486,6 +486,7 @@ export interface StaticAttributeStaticValueParams {
486
486
  attributeName: string
487
487
  attributeValue: string
488
488
  attributeNode: HTMLAttributeNode
489
+ originalAttributeName: string
489
490
  parentNode: HTMLOpenTagNode
490
491
  }
491
492
 
@@ -493,6 +494,7 @@ export interface StaticAttributeDynamicValueParams {
493
494
  attributeName: string
494
495
  valueNodes: Node[]
495
496
  attributeNode: HTMLAttributeNode
497
+ originalAttributeName: string
496
498
  parentNode: HTMLOpenTagNode
497
499
  combinedValue?: string | null
498
500
  }
@@ -632,6 +634,7 @@ export abstract class AttributeVisitorMixin extends BaseRuleVisitor {
632
634
  private checkAttributesOnNode(node: HTMLOpenTagNode): void {
633
635
  forEachAttribute(node, (attributeNode) => {
634
636
  const staticAttributeName = getAttributeName(attributeNode)
637
+ const originalAttributeName = getAttributeName(attributeNode, false) || ""
635
638
  const isDynamicName = hasDynamicAttributeName(attributeNode)
636
639
  const staticAttributeValue = getStaticAttributeValue(attributeNode)
637
640
  const valueNodes = getAttributeValueNodes(attributeNode)
@@ -643,16 +646,17 @@ export abstract class AttributeVisitorMixin extends BaseRuleVisitor {
643
646
  attributeName: staticAttributeName,
644
647
  attributeValue: staticAttributeValue,
645
648
  attributeNode,
649
+ originalAttributeName,
646
650
  parentNode: node
647
651
  })
648
652
  } else if (staticAttributeName && isEffectivelyStaticValue && !hasOutputERB) {
649
653
  const validatableContent = getValidatableStaticContent(valueNodes) || ""
650
654
 
651
- this.checkStaticAttributeStaticValue({ attributeName: staticAttributeName, attributeValue: validatableContent, attributeNode, parentNode: node })
655
+ this.checkStaticAttributeStaticValue({ attributeName: staticAttributeName, attributeValue: validatableContent, attributeNode, originalAttributeName, parentNode: node })
652
656
  } else if (staticAttributeName && hasOutputERB) {
653
657
  const combinedValue = getAttributeValue(attributeNode)
654
658
 
655
- this.checkStaticAttributeDynamicValue({ attributeName: staticAttributeName, valueNodes, attributeNode, parentNode: node, combinedValue })
659
+ this.checkStaticAttributeDynamicValue({ attributeName: staticAttributeName, valueNodes, attributeNode, parentNode: node, originalAttributeName, combinedValue })
656
660
  } else if (isDynamicName && staticAttributeValue !== null) {
657
661
  const nameNode = attributeNode.name as HTMLAttributeNameNode
658
662
  const nameNodes = nameNode.children || []
@@ -673,28 +677,28 @@ export abstract class AttributeVisitorMixin extends BaseRuleVisitor {
673
677
  /**
674
678
  * Static attribute name with static value: class="container"
675
679
  */
676
- protected checkStaticAttributeStaticValue(params: StaticAttributeStaticValueParams): void {
680
+ protected checkStaticAttributeStaticValue(_params: StaticAttributeStaticValueParams): void {
677
681
  // Default implementation does nothing
678
682
  }
679
683
 
680
684
  /**
681
685
  * Static attribute name with dynamic value: class="<%= css_class %>"
682
686
  */
683
- protected checkStaticAttributeDynamicValue(params: StaticAttributeDynamicValueParams): void {
687
+ protected checkStaticAttributeDynamicValue(_params: StaticAttributeDynamicValueParams): void {
684
688
  // Default implementation does nothing
685
689
  }
686
690
 
687
691
  /**
688
692
  * Dynamic attribute name with static value: data-<%= key %>="foo"
689
693
  */
690
- protected checkDynamicAttributeStaticValue(params: DynamicAttributeStaticValueParams): void {
694
+ protected checkDynamicAttributeStaticValue(_params: DynamicAttributeStaticValueParams): void {
691
695
  // Default implementation does nothing
692
696
  }
693
697
 
694
698
  /**
695
699
  * Dynamic attribute name with dynamic value: data-<%= key %>="<%= value %>"
696
700
  */
697
- protected checkDynamicAttributeDynamicValue(params: DynamicAttributeDynamicValueParams): void {
701
+ protected checkDynamicAttributeDynamicValue(_params: DynamicAttributeDynamicValueParams): void {
698
702
  // Default implementation does nothing
699
703
  }
700
704
  }
@@ -44,8 +44,8 @@ class SVGTagNameCapitalizationVisitor extends BaseRuleVisitor {
44
44
  if (correctCamelCase && tagName !== correctCamelCase) {
45
45
  let type: string = node.type
46
46
 
47
- if (node.type == "AST_HTML_OPEN_TAG_NODE") type = "Opening"
48
- if (node.type == "AST_HTML_CLOSE_TAG_NODE") type = "Closing"
47
+ if (node.type === "AST_HTML_OPEN_TAG_NODE") type = "Opening"
48
+ if (node.type === "AST_HTML_CLOSE_TAG_NODE") type = "Closing"
49
49
 
50
50
  this.addOffense(
51
51
  `${type} SVG tag name \`${tagName}\` should use proper capitalization. Use \`${correctCamelCase}\` instead.`,