@herb-tools/linter 0.4.3 → 0.5.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.
- package/README.md +216 -19
- package/dist/herb-lint.js +420 -205
- package/dist/herb-lint.js.map +1 -1
- package/dist/index.cjs +61 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +61 -43
- package/dist/index.js.map +1 -1
- package/dist/package.json +4 -4
- package/dist/src/cli/argument-parser.js +28 -18
- package/dist/src/cli/argument-parser.js.map +1 -1
- package/dist/src/cli/file-processor.js +19 -13
- package/dist/src/cli/file-processor.js.map +1 -1
- package/dist/src/cli/formatters/detailed-formatter.js +9 -9
- package/dist/src/cli/formatters/detailed-formatter.js.map +1 -1
- package/dist/src/cli/formatters/github-actions-formatter.js +50 -0
- package/dist/src/cli/formatters/github-actions-formatter.js.map +1 -0
- package/dist/src/cli/formatters/index.js +2 -0
- package/dist/src/cli/formatters/index.js.map +1 -1
- package/dist/src/cli/formatters/json-formatter.js +58 -0
- package/dist/src/cli/formatters/json-formatter.js.map +1 -0
- package/dist/src/cli/formatters/simple-formatter.js +15 -15
- package/dist/src/cli/formatters/simple-formatter.js.map +1 -1
- package/dist/src/cli/output-manager.js +120 -0
- package/dist/src/cli/output-manager.js.map +1 -0
- package/dist/src/cli/summary-reporter.js +22 -22
- package/dist/src/cli/summary-reporter.js.map +1 -1
- package/dist/src/cli.js +41 -26
- package/dist/src/cli.js.map +1 -1
- package/dist/src/default-rules.js +2 -0
- package/dist/src/default-rules.js.map +1 -1
- package/dist/src/linter.js +1 -1
- package/dist/src/linter.js.map +1 -1
- package/dist/src/rules/erb-no-empty-tags.js +2 -2
- package/dist/src/rules/erb-no-empty-tags.js.map +1 -1
- package/dist/src/rules/erb-no-output-control-flow.js +2 -2
- package/dist/src/rules/erb-no-output-control-flow.js.map +1 -1
- package/dist/src/rules/erb-prefer-image-tag-helper.js +2 -2
- package/dist/src/rules/erb-prefer-image-tag-helper.js.map +1 -1
- package/dist/src/rules/erb-require-whitespace-inside-tags.js +2 -2
- package/dist/src/rules/erb-require-whitespace-inside-tags.js.map +1 -1
- package/dist/src/rules/erb-requires-trailing-newline.js.map +1 -1
- package/dist/src/rules/html-anchor-require-href.js +2 -2
- package/dist/src/rules/html-anchor-require-href.js.map +1 -1
- package/dist/src/rules/html-aria-attribute-must-be-valid.js +2 -2
- package/dist/src/rules/html-aria-attribute-must-be-valid.js.map +1 -1
- package/dist/src/rules/html-aria-level-must-be-valid.js +2 -2
- package/dist/src/rules/html-aria-level-must-be-valid.js.map +1 -1
- package/dist/src/rules/html-aria-role-heading-requires-level.js +2 -2
- package/dist/src/rules/html-aria-role-heading-requires-level.js.map +1 -1
- package/dist/src/rules/html-aria-role-must-be-valid.js +2 -2
- package/dist/src/rules/html-aria-role-must-be-valid.js.map +1 -1
- package/dist/src/rules/html-attribute-double-quotes.js +2 -2
- package/dist/src/rules/html-attribute-double-quotes.js.map +1 -1
- package/dist/src/rules/html-attribute-values-require-quotes.js +2 -2
- package/dist/src/rules/html-attribute-values-require-quotes.js.map +1 -1
- package/dist/src/rules/html-boolean-attributes-no-value.js +2 -2
- package/dist/src/rules/html-boolean-attributes-no-value.js.map +1 -1
- package/dist/src/rules/html-img-require-alt.js +2 -2
- package/dist/src/rules/html-img-require-alt.js.map +1 -1
- package/dist/src/rules/html-no-block-inside-inline.js +4 -4
- package/dist/src/rules/html-no-block-inside-inline.js.map +1 -1
- package/dist/src/rules/html-no-duplicate-attributes.js +2 -2
- package/dist/src/rules/html-no-duplicate-attributes.js.map +1 -1
- package/dist/src/rules/html-no-duplicate-ids.js +2 -2
- package/dist/src/rules/html-no-duplicate-ids.js.map +1 -1
- package/dist/src/rules/html-no-empty-headings.js +2 -2
- package/dist/src/rules/html-no-empty-headings.js.map +1 -1
- package/dist/src/rules/html-no-nested-links.js +2 -2
- package/dist/src/rules/html-no-nested-links.js.map +1 -1
- package/dist/src/rules/html-tag-name-lowercase.js +2 -2
- package/dist/src/rules/html-tag-name-lowercase.js.map +1 -1
- package/dist/src/rules/parser-no-errors.js +18 -0
- package/dist/src/rules/parser-no-errors.js.map +1 -0
- package/dist/src/rules/svg-tag-name-capitalization.js +2 -2
- package/dist/src/rules/svg-tag-name-capitalization.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/cli/argument-parser.d.ts +2 -1
- package/dist/types/cli/file-processor.d.ts +6 -5
- package/dist/types/cli/formatters/base-formatter.d.ts +2 -2
- package/dist/types/cli/formatters/detailed-formatter.d.ts +2 -2
- package/dist/types/cli/formatters/github-actions-formatter.d.ts +12 -0
- package/dist/types/cli/formatters/index.d.ts +2 -0
- package/dist/types/cli/formatters/json-formatter.d.ts +42 -0
- package/dist/types/cli/formatters/simple-formatter.d.ts +2 -2
- package/dist/types/cli/output-manager.d.ts +31 -0
- package/dist/types/cli/summary-reporter.d.ts +3 -3
- package/dist/types/cli.d.ts +3 -1
- package/dist/types/rules/erb-no-empty-tags.d.ts +2 -2
- package/dist/types/rules/erb-no-output-control-flow.d.ts +2 -2
- package/dist/types/rules/erb-prefer-image-tag-helper.d.ts +2 -2
- package/dist/types/rules/erb-require-whitespace-inside-tags.d.ts +2 -2
- package/dist/types/rules/html-anchor-require-href.d.ts +2 -2
- package/dist/types/rules/html-aria-attribute-must-be-valid.d.ts +2 -2
- package/dist/types/rules/html-aria-level-must-be-valid.d.ts +2 -2
- package/dist/types/rules/html-aria-role-heading-requires-level.d.ts +2 -2
- package/dist/types/rules/html-aria-role-must-be-valid.d.ts +2 -2
- package/dist/types/rules/html-attribute-double-quotes.d.ts +2 -2
- package/dist/types/rules/html-attribute-values-require-quotes.d.ts +2 -2
- package/dist/types/rules/html-boolean-attributes-no-value.d.ts +2 -2
- package/dist/types/rules/html-img-require-alt.d.ts +2 -2
- package/dist/types/rules/html-no-block-inside-inline.d.ts +2 -2
- package/dist/types/rules/html-no-duplicate-attributes.d.ts +2 -2
- package/dist/types/rules/html-no-duplicate-ids.d.ts +2 -2
- package/dist/types/rules/html-no-empty-headings.d.ts +2 -2
- package/dist/types/rules/html-no-nested-links.d.ts +2 -2
- package/dist/types/rules/html-tag-name-lowercase.d.ts +2 -2
- package/dist/types/rules/parser-no-errors.d.ts +8 -0
- package/dist/types/rules/svg-tag-name-capitalization.d.ts +2 -2
- package/dist/types/src/cli/argument-parser.d.ts +2 -1
- package/dist/types/src/cli/file-processor.d.ts +6 -5
- package/dist/types/src/cli/formatters/base-formatter.d.ts +2 -2
- package/dist/types/src/cli/formatters/detailed-formatter.d.ts +2 -2
- package/dist/types/src/cli/formatters/github-actions-formatter.d.ts +12 -0
- package/dist/types/src/cli/formatters/index.d.ts +2 -0
- package/dist/types/src/cli/formatters/json-formatter.d.ts +42 -0
- package/dist/types/src/cli/formatters/simple-formatter.d.ts +2 -2
- package/dist/types/src/cli/output-manager.d.ts +31 -0
- package/dist/types/src/cli/summary-reporter.d.ts +3 -3
- package/dist/types/src/cli.d.ts +3 -1
- package/dist/types/src/rules/erb-no-empty-tags.d.ts +2 -2
- package/dist/types/src/rules/erb-no-output-control-flow.d.ts +2 -2
- package/dist/types/src/rules/erb-prefer-image-tag-helper.d.ts +2 -2
- package/dist/types/src/rules/erb-require-whitespace-inside-tags.d.ts +2 -2
- package/dist/types/src/rules/html-anchor-require-href.d.ts +2 -2
- package/dist/types/src/rules/html-aria-attribute-must-be-valid.d.ts +2 -2
- package/dist/types/src/rules/html-aria-level-must-be-valid.d.ts +2 -2
- package/dist/types/src/rules/html-aria-role-heading-requires-level.d.ts +2 -2
- package/dist/types/src/rules/html-aria-role-must-be-valid.d.ts +2 -2
- package/dist/types/src/rules/html-attribute-double-quotes.d.ts +2 -2
- package/dist/types/src/rules/html-attribute-values-require-quotes.d.ts +2 -2
- package/dist/types/src/rules/html-boolean-attributes-no-value.d.ts +2 -2
- package/dist/types/src/rules/html-img-require-alt.d.ts +2 -2
- package/dist/types/src/rules/html-no-block-inside-inline.d.ts +2 -2
- package/dist/types/src/rules/html-no-duplicate-attributes.d.ts +2 -2
- package/dist/types/src/rules/html-no-duplicate-ids.d.ts +2 -2
- package/dist/types/src/rules/html-no-empty-headings.d.ts +2 -2
- package/dist/types/src/rules/html-no-nested-links.d.ts +2 -2
- package/dist/types/src/rules/html-tag-name-lowercase.d.ts +2 -2
- package/dist/types/src/rules/parser-no-errors.d.ts +8 -0
- package/dist/types/src/rules/svg-tag-name-capitalization.d.ts +2 -2
- package/dist/types/src/types.d.ts +3 -3
- package/dist/types/types.d.ts +3 -3
- package/docs/rules/README.md +1 -0
- package/docs/rules/parser-no-errors.md +84 -0
- package/package.json +4 -4
- package/src/cli/argument-parser.ts +33 -19
- package/src/cli/file-processor.ts +25 -17
- package/src/cli/formatters/base-formatter.ts +2 -2
- package/src/cli/formatters/detailed-formatter.ts +9 -9
- package/src/cli/formatters/github-actions-formatter.ts +70 -0
- package/src/cli/formatters/index.ts +2 -0
- package/src/cli/formatters/json-formatter.ts +107 -0
- package/src/cli/formatters/simple-formatter.ts +15 -15
- package/src/cli/output-manager.ts +143 -0
- package/src/cli/summary-reporter.ts +24 -24
- package/src/cli.ts +48 -31
- package/src/default-rules.ts +2 -0
- package/src/linter.ts +1 -1
- package/src/rules/erb-no-empty-tags.ts +3 -3
- package/src/rules/erb-no-output-control-flow.ts +3 -3
- package/src/rules/erb-prefer-image-tag-helper.ts +3 -3
- package/src/rules/erb-require-whitespace-inside-tags.ts +3 -3
- package/src/rules/erb-requires-trailing-newline.ts +2 -0
- package/src/rules/html-anchor-require-href.ts +3 -3
- package/src/rules/html-aria-attribute-must-be-valid.ts +3 -3
- package/src/rules/html-aria-level-must-be-valid.ts +3 -3
- package/src/rules/html-aria-role-heading-requires-level.ts +3 -3
- package/src/rules/html-aria-role-must-be-valid.ts +3 -3
- package/src/rules/html-attribute-double-quotes.ts +3 -3
- package/src/rules/html-attribute-values-require-quotes.ts +3 -3
- package/src/rules/html-boolean-attributes-no-value.ts +3 -3
- package/src/rules/html-img-require-alt.ts +3 -3
- package/src/rules/html-no-block-inside-inline.ts +5 -5
- package/src/rules/html-no-duplicate-attributes.ts +3 -3
- package/src/rules/html-no-duplicate-ids.ts +3 -3
- package/src/rules/html-no-empty-headings.ts +3 -3
- package/src/rules/html-no-nested-links.ts +3 -3
- package/src/rules/html-tag-name-lowercase.ts +3 -3
- package/src/rules/parser-no-errors.ts +25 -0
- package/src/rules/svg-tag-name-capitalization.ts +3 -3
- package/src/types.ts +3 -3
package/src/cli.ts
CHANGED
|
@@ -1,14 +1,41 @@
|
|
|
1
1
|
import { glob } from "glob"
|
|
2
2
|
import { Herb } from "@herb-tools/node-wasm"
|
|
3
|
-
import { ArgumentParser } from "./cli/argument-parser.js"
|
|
3
|
+
import { ArgumentParser, type FormatOption } from "./cli/argument-parser.js"
|
|
4
4
|
import { FileProcessor } from "./cli/file-processor.js"
|
|
5
|
-
import {
|
|
6
|
-
import { SummaryReporter } from "./cli/summary-reporter.js"
|
|
5
|
+
import { OutputManager } from "./cli/output-manager.js"
|
|
7
6
|
|
|
8
7
|
export class CLI {
|
|
9
8
|
private argumentParser = new ArgumentParser()
|
|
10
9
|
private fileProcessor = new FileProcessor()
|
|
11
|
-
private
|
|
10
|
+
private outputManager = new OutputManager()
|
|
11
|
+
|
|
12
|
+
private exitWithError(message: string, formatOption: FormatOption, exitCode: number = 1) {
|
|
13
|
+
this.outputManager.outputError(message, {
|
|
14
|
+
formatOption,
|
|
15
|
+
theme: 'auto',
|
|
16
|
+
wrapLines: false,
|
|
17
|
+
truncateLines: false,
|
|
18
|
+
showTiming: false,
|
|
19
|
+
startTime: 0,
|
|
20
|
+
startDate: new Date()
|
|
21
|
+
})
|
|
22
|
+
process.exit(exitCode)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
private exitWithInfo(message: string, formatOption: FormatOption, exitCode: number = 0, timingData?: { startTime: number, startDate: Date, showTiming: boolean }) {
|
|
26
|
+
const outputOptions = {
|
|
27
|
+
formatOption,
|
|
28
|
+
theme: 'auto' as const,
|
|
29
|
+
wrapLines: false,
|
|
30
|
+
truncateLines: false,
|
|
31
|
+
showTiming: timingData?.showTiming ?? false,
|
|
32
|
+
startTime: timingData?.startTime ?? Date.now(),
|
|
33
|
+
startDate: timingData?.startDate ?? new Date()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
this.outputManager.outputInfo(message, outputOptions)
|
|
37
|
+
process.exit(exitCode)
|
|
38
|
+
}
|
|
12
39
|
|
|
13
40
|
async run() {
|
|
14
41
|
const startTime = Date.now()
|
|
@@ -16,45 +43,35 @@ export class CLI {
|
|
|
16
43
|
|
|
17
44
|
const { pattern, formatOption, showTiming, theme, wrapLines, truncateLines } = this.argumentParser.parse(process.argv)
|
|
18
45
|
|
|
46
|
+
const outputOptions = {
|
|
47
|
+
formatOption,
|
|
48
|
+
theme,
|
|
49
|
+
wrapLines,
|
|
50
|
+
truncateLines,
|
|
51
|
+
showTiming,
|
|
52
|
+
startTime,
|
|
53
|
+
startDate
|
|
54
|
+
}
|
|
55
|
+
|
|
19
56
|
try {
|
|
20
57
|
await Herb.load()
|
|
21
58
|
|
|
22
59
|
const files = await glob(pattern)
|
|
23
60
|
|
|
24
61
|
if (files.length === 0) {
|
|
25
|
-
|
|
26
|
-
process.exit(0)
|
|
62
|
+
this.exitWithInfo(`No files found matching pattern: ${pattern}`, formatOption, 0, { startTime, startDate, showTiming })
|
|
27
63
|
}
|
|
28
64
|
|
|
29
|
-
const results = await this.fileProcessor.processFiles(files)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
: new DetailedFormatter(theme, wrapLines, truncateLines)
|
|
35
|
-
|
|
36
|
-
await formatter.format(allDiagnostics, files.length === 1)
|
|
37
|
-
|
|
38
|
-
this.summaryReporter.displayMostViolatedRules(ruleViolations)
|
|
39
|
-
this.summaryReporter.displaySummary({
|
|
40
|
-
files,
|
|
41
|
-
totalErrors,
|
|
42
|
-
totalWarnings,
|
|
43
|
-
filesWithViolations: filesWithIssues,
|
|
44
|
-
ruleCount,
|
|
45
|
-
startTime,
|
|
46
|
-
startDate,
|
|
47
|
-
showTiming,
|
|
48
|
-
ruleViolations
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
if (totalErrors > 0) {
|
|
65
|
+
const results = await this.fileProcessor.processFiles(files, formatOption)
|
|
66
|
+
|
|
67
|
+
await this.outputManager.outputResults({ ...results, files }, outputOptions)
|
|
68
|
+
|
|
69
|
+
if (results.totalErrors > 0) {
|
|
52
70
|
process.exit(1)
|
|
53
71
|
}
|
|
54
72
|
|
|
55
73
|
} catch (error) {
|
|
56
|
-
|
|
57
|
-
process.exit(1)
|
|
74
|
+
this.exitWithError(`Error: ${error}`, formatOption)
|
|
58
75
|
}
|
|
59
76
|
}
|
|
60
77
|
}
|
package/src/default-rules.ts
CHANGED
|
@@ -20,6 +20,7 @@ import { HTMLNoDuplicateIdsRule } from "./rules/html-no-duplicate-ids.js"
|
|
|
20
20
|
import { HTMLNoEmptyHeadingsRule } from "./rules/html-no-empty-headings.js"
|
|
21
21
|
import { HTMLNoNestedLinksRule } from "./rules/html-no-nested-links.js"
|
|
22
22
|
import { HTMLTagNameLowercaseRule } from "./rules/html-tag-name-lowercase.js"
|
|
23
|
+
import { ParserNoErrorsRule } from "./rules/parser-no-errors.js"
|
|
23
24
|
import { SVGTagNameCapitalizationRule } from "./rules/svg-tag-name-capitalization.js"
|
|
24
25
|
|
|
25
26
|
export const defaultRules: RuleClass[] = [
|
|
@@ -43,5 +44,6 @@ export const defaultRules: RuleClass[] = [
|
|
|
43
44
|
HTMLNoEmptyHeadingsRule,
|
|
44
45
|
HTMLNoNestedLinksRule,
|
|
45
46
|
HTMLTagNameLowercaseRule,
|
|
47
|
+
ParserNoErrorsRule,
|
|
46
48
|
SVGTagNameCapitalizationRule,
|
|
47
49
|
]
|
package/src/linter.ts
CHANGED
|
@@ -66,7 +66,7 @@ export class Linter {
|
|
|
66
66
|
} else if (this.isSourceRule(rule)) {
|
|
67
67
|
ruleOffenses = (rule as SourceRule).check(source, context)
|
|
68
68
|
} else {
|
|
69
|
-
ruleOffenses = (rule as ParserRule).check(parseResult
|
|
69
|
+
ruleOffenses = (rule as ParserRule).check(parseResult, context)
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
this.offenses.push(...ruleOffenses)
|
|
@@ -2,7 +2,7 @@ import { BaseRuleVisitor } from "./rule-utils.js"
|
|
|
2
2
|
|
|
3
3
|
import { ParserRule } from "../types.js"
|
|
4
4
|
import type { LintOffense, LintContext } from "../types.js"
|
|
5
|
-
import type {
|
|
5
|
+
import type { ParseResult, ERBContentNode } from "@herb-tools/core"
|
|
6
6
|
|
|
7
7
|
class ERBNoEmptyTagsVisitor extends BaseRuleVisitor {
|
|
8
8
|
visitERBContentNode(node: ERBContentNode): void {
|
|
@@ -25,10 +25,10 @@ class ERBNoEmptyTagsVisitor extends BaseRuleVisitor {
|
|
|
25
25
|
export class ERBNoEmptyTagsRule extends ParserRule {
|
|
26
26
|
name = "erb-no-empty-tags"
|
|
27
27
|
|
|
28
|
-
check(
|
|
28
|
+
check(result: ParseResult, context?: Partial<LintContext>): LintOffense[] {
|
|
29
29
|
const visitor = new ERBNoEmptyTagsVisitor(this.name, context)
|
|
30
30
|
|
|
31
|
-
visitor.visit(
|
|
31
|
+
visitor.visit(result.value)
|
|
32
32
|
|
|
33
33
|
return visitor.offenses
|
|
34
34
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BaseRuleVisitor } from "./rule-utils.js"
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type { ParseResult, ERBIfNode, ERBUnlessNode, ERBElseNode, ERBEndNode } from "@herb-tools/core"
|
|
4
4
|
import { ParserRule } from "../types.js"
|
|
5
5
|
import type { LintOffense, LintContext } from "../types.js"
|
|
6
6
|
|
|
@@ -53,10 +53,10 @@ class ERBNoOutputControlFlowRuleVisitor extends BaseRuleVisitor {
|
|
|
53
53
|
export class ERBNoOutputControlFlowRule extends ParserRule {
|
|
54
54
|
name = "erb-no-output-control-flow"
|
|
55
55
|
|
|
56
|
-
check(
|
|
56
|
+
check(result: ParseResult, context?: Partial<LintContext>): LintOffense[] {
|
|
57
57
|
const visitor = new ERBNoOutputControlFlowRuleVisitor(this.name, context)
|
|
58
58
|
|
|
59
|
-
visitor.visit(
|
|
59
|
+
visitor.visit(result.value)
|
|
60
60
|
|
|
61
61
|
return visitor.offenses
|
|
62
62
|
}
|
|
@@ -2,7 +2,7 @@ import { BaseRuleVisitor, getTagName, findAttributeByName, getAttributes } from
|
|
|
2
2
|
|
|
3
3
|
import { ParserRule } from "../types.js"
|
|
4
4
|
import type { LintOffense, LintContext } from "../types.js"
|
|
5
|
-
import type { HTMLOpenTagNode, HTMLSelfCloseTagNode, HTMLAttributeValueNode, ERBContentNode, LiteralNode,
|
|
5
|
+
import type { HTMLOpenTagNode, HTMLSelfCloseTagNode, HTMLAttributeValueNode, ERBContentNode, LiteralNode, ParseResult } from "@herb-tools/core"
|
|
6
6
|
|
|
7
7
|
class ERBPreferImageTagHelperVisitor extends BaseRuleVisitor {
|
|
8
8
|
visitHTMLOpenTagNode(node: HTMLOpenTagNode): void {
|
|
@@ -116,9 +116,9 @@ class ERBPreferImageTagHelperVisitor extends BaseRuleVisitor {
|
|
|
116
116
|
export class ERBPreferImageTagHelperRule extends ParserRule {
|
|
117
117
|
name = "erb-prefer-image-tag-helper"
|
|
118
118
|
|
|
119
|
-
check(
|
|
119
|
+
check(result: ParseResult, context?: Partial<LintContext>): LintOffense[] {
|
|
120
120
|
const visitor = new ERBPreferImageTagHelperVisitor(this.name, context)
|
|
121
|
-
visitor.visit(
|
|
121
|
+
visitor.visit(result.value)
|
|
122
122
|
return visitor.offenses
|
|
123
123
|
}
|
|
124
124
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ParseResult, Token, Node } from "@herb-tools/core"
|
|
2
2
|
import { isERBNode } from "@herb-tools/core";
|
|
3
3
|
import { ParserRule } from "../types.js"
|
|
4
4
|
import type { LintOffense, LintContext } from "../types.js"
|
|
@@ -85,9 +85,9 @@ class RequireWhitespaceInsideTags extends BaseRuleVisitor {
|
|
|
85
85
|
export class ERBRequireWhitespaceRule extends ParserRule {
|
|
86
86
|
name = "erb-require-whitespace-inside-tags"
|
|
87
87
|
|
|
88
|
-
check(
|
|
88
|
+
check(result: ParseResult, context?: Partial<LintContext>): LintOffense[] {
|
|
89
89
|
const visitor = new RequireWhitespaceInsideTags(this.name, context)
|
|
90
|
-
visitor.visit(
|
|
90
|
+
visitor.visit(result.value)
|
|
91
91
|
return visitor.offenses
|
|
92
92
|
}
|
|
93
93
|
}
|
|
@@ -21,7 +21,9 @@ export class ERBRequiresTrailingNewlineRule extends SourceRule {
|
|
|
21
21
|
|
|
22
22
|
check(source: string, context?: Partial<LintContext>): LintOffense[] {
|
|
23
23
|
const visitor = new ERBRequiresTrailingNewlineVisitor(this.name, context)
|
|
24
|
+
|
|
24
25
|
visitor.visit(source)
|
|
26
|
+
|
|
25
27
|
return visitor.offenses
|
|
26
28
|
}
|
|
27
29
|
}
|
|
@@ -2,7 +2,7 @@ import { BaseRuleVisitor, getTagName, hasAttribute } from "./rule-utils.js"
|
|
|
2
2
|
|
|
3
3
|
import { ParserRule } from "../types.js"
|
|
4
4
|
import type { LintOffense, LintContext } from "../types.js"
|
|
5
|
-
import type { HTMLOpenTagNode,
|
|
5
|
+
import type { HTMLOpenTagNode, ParseResult } from "@herb-tools/core"
|
|
6
6
|
|
|
7
7
|
class AnchorRechireHrefVisitor extends BaseRuleVisitor {
|
|
8
8
|
visitHTMLOpenTagNode(node: HTMLOpenTagNode): void {
|
|
@@ -30,10 +30,10 @@ class AnchorRechireHrefVisitor extends BaseRuleVisitor {
|
|
|
30
30
|
export class HTMLAnchorRequireHrefRule extends ParserRule {
|
|
31
31
|
name = "html-anchor-require-href"
|
|
32
32
|
|
|
33
|
-
check(
|
|
33
|
+
check(result: ParseResult, context?: Partial<LintContext>): LintOffense[] {
|
|
34
34
|
const visitor = new AnchorRechireHrefVisitor(this.name, context)
|
|
35
35
|
|
|
36
|
-
visitor.visit(
|
|
36
|
+
visitor.visit(result.value)
|
|
37
37
|
|
|
38
38
|
return visitor.offenses
|
|
39
39
|
}
|
|
@@ -8,7 +8,7 @@ import type {
|
|
|
8
8
|
HTMLAttributeNode,
|
|
9
9
|
HTMLOpenTagNode,
|
|
10
10
|
HTMLSelfCloseTagNode,
|
|
11
|
-
|
|
11
|
+
ParseResult,
|
|
12
12
|
} from "@herb-tools/core";
|
|
13
13
|
|
|
14
14
|
class AriaAttributeMustBeValid extends AttributeVisitorMixin {
|
|
@@ -34,9 +34,9 @@ class AriaAttributeMustBeValid extends AttributeVisitorMixin {
|
|
|
34
34
|
export class HTMLAriaAttributeMustBeValid extends ParserRule {
|
|
35
35
|
name = "html-aria-attribute-must-be-valid";
|
|
36
36
|
|
|
37
|
-
check(
|
|
37
|
+
check(result: ParseResult, context?: Partial<LintContext>): LintOffense[] {
|
|
38
38
|
const visitor = new AriaAttributeMustBeValid(this.name, context);
|
|
39
|
-
visitor.visit(
|
|
39
|
+
visitor.visit(result.value);
|
|
40
40
|
return visitor.offenses;
|
|
41
41
|
}
|
|
42
42
|
}
|
|
@@ -2,7 +2,7 @@ import { AttributeVisitorMixin } from "./rule-utils.js"
|
|
|
2
2
|
import { ParserRule } from "../types.js"
|
|
3
3
|
|
|
4
4
|
import type { LintOffense, LintContext } from "../types.js"
|
|
5
|
-
import type {
|
|
5
|
+
import type { ParseResult, HTMLAttributeNode, HTMLOpenTagNode, HTMLSelfCloseTagNode } from "@herb-tools/core"
|
|
6
6
|
|
|
7
7
|
class HTMLAriaLevelMustBeValidVisitor extends AttributeVisitorMixin {
|
|
8
8
|
protected checkAttribute(attributeName: string, attributeValue: string | null, attributeNode: HTMLAttributeNode, _parentNode: HTMLOpenTagNode | HTMLSelfCloseTagNode): void {
|
|
@@ -32,10 +32,10 @@ class HTMLAriaLevelMustBeValidVisitor extends AttributeVisitorMixin {
|
|
|
32
32
|
export class HTMLAriaLevelMustBeValidRule extends ParserRule {
|
|
33
33
|
name = "html-aria-level-must-be-valid"
|
|
34
34
|
|
|
35
|
-
check(
|
|
35
|
+
check(result: ParseResult, context?: Partial<LintContext>): LintOffense[] {
|
|
36
36
|
const visitor = new HTMLAriaLevelMustBeValidVisitor(this.name, context)
|
|
37
37
|
|
|
38
|
-
visitor.visit(
|
|
38
|
+
visitor.visit(result.value)
|
|
39
39
|
|
|
40
40
|
return visitor.offenses
|
|
41
41
|
}
|
|
@@ -2,7 +2,7 @@ import { AttributeVisitorMixin, getAttributeName, getAttributes } from "./rule-u
|
|
|
2
2
|
|
|
3
3
|
import { ParserRule } from "../types.js"
|
|
4
4
|
import type { LintOffense, LintContext } from "../types.js"
|
|
5
|
-
import type {
|
|
5
|
+
import type { ParseResult, HTMLAttributeNode, HTMLOpenTagNode, HTMLSelfCloseTagNode } from "@herb-tools/core"
|
|
6
6
|
|
|
7
7
|
class AriaRoleHeadingRequiresLevel extends AttributeVisitorMixin {
|
|
8
8
|
|
|
@@ -37,9 +37,9 @@ class AriaRoleHeadingRequiresLevel extends AttributeVisitorMixin {
|
|
|
37
37
|
export class HTMLAriaRoleHeadingRequiresLevelRule extends ParserRule {
|
|
38
38
|
name = "html-aria-role-heading-requires-level"
|
|
39
39
|
|
|
40
|
-
check(
|
|
40
|
+
check(result: ParseResult, context?: Partial<LintContext>): LintOffense[] {
|
|
41
41
|
const visitor = new AriaRoleHeadingRequiresLevel(this.name, context)
|
|
42
|
-
visitor.visit(
|
|
42
|
+
visitor.visit(result.value)
|
|
43
43
|
return visitor.offenses
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -2,7 +2,7 @@ import { AttributeVisitorMixin, VALID_ARIA_ROLES } from "./rule-utils.js"
|
|
|
2
2
|
|
|
3
3
|
import { ParserRule } from "../types.js"
|
|
4
4
|
import type { LintOffense, LintContext } from "../types.js"
|
|
5
|
-
import type {
|
|
5
|
+
import type { ParseResult, HTMLAttributeNode } from "@herb-tools/core"
|
|
6
6
|
|
|
7
7
|
class AriaRoleMustBeValid extends AttributeVisitorMixin {
|
|
8
8
|
checkAttribute(attributeName: string, attributeValue: string | null, attributeNode: HTMLAttributeNode,): void {
|
|
@@ -21,10 +21,10 @@ class AriaRoleMustBeValid extends AttributeVisitorMixin {
|
|
|
21
21
|
export class HTMLAriaRoleMustBeValidRule extends ParserRule {
|
|
22
22
|
name = "html-aria-role-must-be-valid"
|
|
23
23
|
|
|
24
|
-
check(
|
|
24
|
+
check(result: ParseResult, context?: Partial<LintContext>): LintOffense[] {
|
|
25
25
|
const visitor = new AriaRoleMustBeValid(this.name, context)
|
|
26
26
|
|
|
27
|
-
visitor.visit(
|
|
27
|
+
visitor.visit(result.value)
|
|
28
28
|
|
|
29
29
|
return visitor.offenses
|
|
30
30
|
}
|
|
@@ -2,7 +2,7 @@ import { AttributeVisitorMixin, getAttributeValueQuoteType, hasAttributeValue }
|
|
|
2
2
|
|
|
3
3
|
import { ParserRule } from "../types.js"
|
|
4
4
|
import type { LintOffense, LintContext } from "../types.js"
|
|
5
|
-
import type {
|
|
5
|
+
import type { ParseResult, HTMLAttributeNode } from "@herb-tools/core"
|
|
6
6
|
|
|
7
7
|
class AttributeDoubleQuotesVisitor extends AttributeVisitorMixin {
|
|
8
8
|
protected checkAttribute(attributeName: string, attributeValue: string | null, attributeNode: HTMLAttributeNode): void {
|
|
@@ -21,9 +21,9 @@ class AttributeDoubleQuotesVisitor extends AttributeVisitorMixin {
|
|
|
21
21
|
export class HTMLAttributeDoubleQuotesRule extends ParserRule {
|
|
22
22
|
name = "html-attribute-double-quotes"
|
|
23
23
|
|
|
24
|
-
check(
|
|
24
|
+
check(result: ParseResult, context?: Partial<LintContext>): LintOffense[] {
|
|
25
25
|
const visitor = new AttributeDoubleQuotesVisitor(this.name, context)
|
|
26
|
-
visitor.visit(
|
|
26
|
+
visitor.visit(result.value)
|
|
27
27
|
return visitor.offenses
|
|
28
28
|
}
|
|
29
29
|
}
|
|
@@ -2,7 +2,7 @@ import { AttributeVisitorMixin } from "./rule-utils.js"
|
|
|
2
2
|
|
|
3
3
|
import { ParserRule } from "../types.js"
|
|
4
4
|
import type { LintOffense, LintContext } from "../types.js"
|
|
5
|
-
import type { HTMLAttributeNode, HTMLAttributeValueNode,
|
|
5
|
+
import type { HTMLAttributeNode, HTMLAttributeValueNode, ParseResult } from "@herb-tools/core"
|
|
6
6
|
|
|
7
7
|
class AttributeValuesRequireQuotesVisitor extends AttributeVisitorMixin {
|
|
8
8
|
protected checkAttribute(attributeName: string, _attributeValue: string | null, attributeNode: HTMLAttributeNode): void {
|
|
@@ -23,9 +23,9 @@ class AttributeValuesRequireQuotesVisitor extends AttributeVisitorMixin {
|
|
|
23
23
|
export class HTMLAttributeValuesRequireQuotesRule extends ParserRule {
|
|
24
24
|
name = "html-attribute-values-require-quotes"
|
|
25
25
|
|
|
26
|
-
check(
|
|
26
|
+
check(result: ParseResult, context?: Partial<LintContext>): LintOffense[] {
|
|
27
27
|
const visitor = new AttributeValuesRequireQuotesVisitor(this.name, context)
|
|
28
|
-
visitor.visit(
|
|
28
|
+
visitor.visit(result.value)
|
|
29
29
|
return visitor.offenses
|
|
30
30
|
}
|
|
31
31
|
}
|
|
@@ -2,7 +2,7 @@ import { AttributeVisitorMixin, isBooleanAttribute, hasAttributeValue } from "./
|
|
|
2
2
|
|
|
3
3
|
import { ParserRule } from "../types.js"
|
|
4
4
|
import type { LintOffense, LintContext } from "../types.js"
|
|
5
|
-
import type { HTMLAttributeNode,
|
|
5
|
+
import type { HTMLAttributeNode, ParseResult } from "@herb-tools/core"
|
|
6
6
|
|
|
7
7
|
class BooleanAttributesNoValueVisitor extends AttributeVisitorMixin {
|
|
8
8
|
protected checkAttribute(attributeName: string, _attributeValue: string | null, attributeNode: HTMLAttributeNode): void {
|
|
@@ -20,9 +20,9 @@ class BooleanAttributesNoValueVisitor extends AttributeVisitorMixin {
|
|
|
20
20
|
export class HTMLBooleanAttributesNoValueRule extends ParserRule {
|
|
21
21
|
name = "html-boolean-attributes-no-value"
|
|
22
22
|
|
|
23
|
-
check(
|
|
23
|
+
check(result: ParseResult, context?: Partial<LintContext>): LintOffense[] {
|
|
24
24
|
const visitor = new BooleanAttributesNoValueVisitor(this.name, context)
|
|
25
|
-
visitor.visit(
|
|
25
|
+
visitor.visit(result.value)
|
|
26
26
|
return visitor.offenses
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -2,7 +2,7 @@ import { BaseRuleVisitor, getTagName, hasAttribute } from "./rule-utils.js"
|
|
|
2
2
|
|
|
3
3
|
import { ParserRule } from "../types.js"
|
|
4
4
|
import type { LintOffense, LintContext } from "../types.js"
|
|
5
|
-
import type { HTMLOpenTagNode, HTMLSelfCloseTagNode,
|
|
5
|
+
import type { HTMLOpenTagNode, HTMLSelfCloseTagNode, ParseResult } from "@herb-tools/core"
|
|
6
6
|
|
|
7
7
|
class ImgRequireAltVisitor extends BaseRuleVisitor {
|
|
8
8
|
visitHTMLOpenTagNode(node: HTMLOpenTagNode): void {
|
|
@@ -35,9 +35,9 @@ class ImgRequireAltVisitor extends BaseRuleVisitor {
|
|
|
35
35
|
export class HTMLImgRequireAltRule extends ParserRule {
|
|
36
36
|
name = "html-img-require-alt"
|
|
37
37
|
|
|
38
|
-
check(
|
|
38
|
+
check(result: ParseResult, context?: Partial<LintContext>): LintOffense[] {
|
|
39
39
|
const visitor = new ImgRequireAltVisitor(this.name, context)
|
|
40
|
-
visitor.visit(
|
|
40
|
+
visitor.visit(result.value)
|
|
41
41
|
return visitor.offenses
|
|
42
42
|
}
|
|
43
43
|
}
|
|
@@ -2,7 +2,7 @@ import { BaseRuleVisitor, isInlineElement, isBlockElement } from "./rule-utils.j
|
|
|
2
2
|
|
|
3
3
|
import { ParserRule } from "../types.js"
|
|
4
4
|
import type { LintOffense, LintContext } from "../types.js"
|
|
5
|
-
import type { HTMLOpenTagNode, HTMLElementNode,
|
|
5
|
+
import type { HTMLOpenTagNode, HTMLElementNode, ParseResult } from "@herb-tools/core"
|
|
6
6
|
|
|
7
7
|
class BlockInsideInlineVisitor extends BaseRuleVisitor {
|
|
8
8
|
private inlineStack: string[] = []
|
|
@@ -19,7 +19,7 @@ class BlockInsideInlineVisitor extends BaseRuleVisitor {
|
|
|
19
19
|
return { isInline, isBlock, isUnknown }
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
private
|
|
22
|
+
private addOffenseMessage(tagName: string, isBlock: boolean, openTag: HTMLOpenTagNode): void {
|
|
23
23
|
const parentInline = this.inlineStack[this.inlineStack.length - 1]
|
|
24
24
|
const elementType = isBlock ? "Block-level" : "Unknown"
|
|
25
25
|
|
|
@@ -62,7 +62,7 @@ class BlockInsideInlineVisitor extends BaseRuleVisitor {
|
|
|
62
62
|
const { isInline, isBlock, isUnknown } = this.getElementType(tagName)
|
|
63
63
|
|
|
64
64
|
if ((isBlock || isUnknown) && this.inlineStack.length > 0) {
|
|
65
|
-
this.
|
|
65
|
+
this.addOffenseMessage(tagName, isBlock, openTag)
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
if (isInline) {
|
|
@@ -77,9 +77,9 @@ class BlockInsideInlineVisitor extends BaseRuleVisitor {
|
|
|
77
77
|
export class HTMLNoBlockInsideInlineRule extends ParserRule {
|
|
78
78
|
name = "html-no-block-inside-inline"
|
|
79
79
|
|
|
80
|
-
check(
|
|
80
|
+
check(result: ParseResult, context?: Partial<LintContext>): LintOffense[] {
|
|
81
81
|
const visitor = new BlockInsideInlineVisitor(this.name, context)
|
|
82
|
-
visitor.visit(
|
|
82
|
+
visitor.visit(result.value)
|
|
83
83
|
return visitor.offenses
|
|
84
84
|
}
|
|
85
85
|
}
|
|
@@ -2,7 +2,7 @@ import { BaseRuleVisitor, forEachAttribute } from "./rule-utils.js"
|
|
|
2
2
|
|
|
3
3
|
import { ParserRule } from "../types.js"
|
|
4
4
|
import type { LintOffense, LintContext } from "../types.js"
|
|
5
|
-
import type { HTMLOpenTagNode, HTMLSelfCloseTagNode, HTMLAttributeNameNode,
|
|
5
|
+
import type { HTMLOpenTagNode, HTMLSelfCloseTagNode, HTMLAttributeNameNode, ParseResult } from "@herb-tools/core"
|
|
6
6
|
|
|
7
7
|
class NoDuplicateAttributesVisitor extends BaseRuleVisitor {
|
|
8
8
|
visitHTMLOpenTagNode(node: HTMLOpenTagNode): void {
|
|
@@ -52,9 +52,9 @@ class NoDuplicateAttributesVisitor extends BaseRuleVisitor {
|
|
|
52
52
|
export class HTMLNoDuplicateAttributesRule extends ParserRule {
|
|
53
53
|
name = "html-no-duplicate-attributes"
|
|
54
54
|
|
|
55
|
-
check(
|
|
55
|
+
check(result: ParseResult, context?: Partial<LintContext>): LintOffense[] {
|
|
56
56
|
const visitor = new NoDuplicateAttributesVisitor(this.name, context)
|
|
57
|
-
visitor.visit(
|
|
57
|
+
visitor.visit(result.value)
|
|
58
58
|
return visitor.offenses
|
|
59
59
|
}
|
|
60
60
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AttributeVisitorMixin } from "./rule-utils"
|
|
2
2
|
import { ParserRule } from "../types"
|
|
3
|
-
import type { Node } from "@herb-tools/core"
|
|
3
|
+
import type { ParseResult, Node } from "@herb-tools/core"
|
|
4
4
|
import type { LintOffense, LintContext } from "../types"
|
|
5
5
|
|
|
6
6
|
class NoDuplicateIdsVisitor extends AttributeVisitorMixin {
|
|
@@ -29,10 +29,10 @@ class NoDuplicateIdsVisitor extends AttributeVisitorMixin {
|
|
|
29
29
|
export class HTMLNoDuplicateIdsRule extends ParserRule {
|
|
30
30
|
name = "html-no-duplicate-ids"
|
|
31
31
|
|
|
32
|
-
check(
|
|
32
|
+
check(result: ParseResult, context?: Partial<LintContext>): LintOffense[] {
|
|
33
33
|
const visitor = new NoDuplicateIdsVisitor(this.name, context)
|
|
34
34
|
|
|
35
|
-
visitor.visit(
|
|
35
|
+
visitor.visit(result.value)
|
|
36
36
|
|
|
37
37
|
return visitor.offenses
|
|
38
38
|
}
|
|
@@ -2,7 +2,7 @@ import { BaseRuleVisitor, getTagName, getAttributes, findAttributeByName, getAtt
|
|
|
2
2
|
|
|
3
3
|
import { ParserRule } from "../types.js"
|
|
4
4
|
import type { LintOffense, LintContext } from "../types.js"
|
|
5
|
-
import type { HTMLElementNode, HTMLOpenTagNode, HTMLSelfCloseTagNode,
|
|
5
|
+
import type { HTMLElementNode, HTMLOpenTagNode, HTMLSelfCloseTagNode, ParseResult, LiteralNode, HTMLTextNode } from "@herb-tools/core"
|
|
6
6
|
|
|
7
7
|
class NoEmptyHeadingsVisitor extends BaseRuleVisitor {
|
|
8
8
|
visitHTMLElementNode(node: HTMLElementNode): void {
|
|
@@ -178,9 +178,9 @@ class NoEmptyHeadingsVisitor extends BaseRuleVisitor {
|
|
|
178
178
|
export class HTMLNoEmptyHeadingsRule extends ParserRule {
|
|
179
179
|
name = "html-no-empty-headings"
|
|
180
180
|
|
|
181
|
-
check(
|
|
181
|
+
check(result: ParseResult, context?: Partial<LintContext>): LintOffense[] {
|
|
182
182
|
const visitor = new NoEmptyHeadingsVisitor(this.name, context)
|
|
183
|
-
visitor.visit(
|
|
183
|
+
visitor.visit(result.value)
|
|
184
184
|
return visitor.offenses
|
|
185
185
|
}
|
|
186
186
|
}
|
|
@@ -2,7 +2,7 @@ import { BaseRuleVisitor, getTagName } from "./rule-utils.js"
|
|
|
2
2
|
|
|
3
3
|
import { ParserRule } from "../types.js"
|
|
4
4
|
import type { LintOffense, LintContext } from "../types.js"
|
|
5
|
-
import type { HTMLOpenTagNode, HTMLElementNode,
|
|
5
|
+
import type { HTMLOpenTagNode, HTMLElementNode, ParseResult } from "@herb-tools/core"
|
|
6
6
|
|
|
7
7
|
class NestedLinkVisitor extends BaseRuleVisitor {
|
|
8
8
|
private linkStack: HTMLOpenTagNode[] = []
|
|
@@ -58,9 +58,9 @@ class NestedLinkVisitor extends BaseRuleVisitor {
|
|
|
58
58
|
export class HTMLNoNestedLinksRule extends ParserRule {
|
|
59
59
|
name = "html-no-nested-links"
|
|
60
60
|
|
|
61
|
-
check(
|
|
61
|
+
check(result: ParseResult, context?: Partial<LintContext>): LintOffense[] {
|
|
62
62
|
const visitor = new NestedLinkVisitor(this.name, context)
|
|
63
|
-
visitor.visit(
|
|
63
|
+
visitor.visit(result.value)
|
|
64
64
|
return visitor.offenses
|
|
65
65
|
}
|
|
66
66
|
}
|
|
@@ -2,7 +2,7 @@ import { BaseRuleVisitor } from "./rule-utils.js"
|
|
|
2
2
|
|
|
3
3
|
import { ParserRule } from "../types.js"
|
|
4
4
|
import type { LintOffense, LintContext } from "../types.js"
|
|
5
|
-
import type { HTMLElementNode, HTMLOpenTagNode, HTMLCloseTagNode, HTMLSelfCloseTagNode,
|
|
5
|
+
import type { HTMLElementNode, HTMLOpenTagNode, HTMLCloseTagNode, HTMLSelfCloseTagNode, ParseResult } from "@herb-tools/core"
|
|
6
6
|
|
|
7
7
|
class TagNameLowercaseVisitor extends BaseRuleVisitor {
|
|
8
8
|
visitHTMLElementNode(node: HTMLElementNode): void {
|
|
@@ -58,9 +58,9 @@ class TagNameLowercaseVisitor extends BaseRuleVisitor {
|
|
|
58
58
|
export class HTMLTagNameLowercaseRule extends ParserRule {
|
|
59
59
|
name = "html-tag-name-lowercase"
|
|
60
60
|
|
|
61
|
-
check(
|
|
61
|
+
check(result: ParseResult, context?: Partial<LintContext>): LintOffense[] {
|
|
62
62
|
const visitor = new TagNameLowercaseVisitor(this.name, context)
|
|
63
|
-
visitor.visit(
|
|
63
|
+
visitor.visit(result.value)
|
|
64
64
|
return visitor.offenses
|
|
65
65
|
}
|
|
66
66
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ParserRule } from "../types.js"
|
|
2
|
+
|
|
3
|
+
import type { LintOffense } from "../types.js"
|
|
4
|
+
import type { ParseResult, HerbError } from "@herb-tools/core"
|
|
5
|
+
|
|
6
|
+
export class ParserNoErrorsRule extends ParserRule {
|
|
7
|
+
name = "parser-no-errors"
|
|
8
|
+
|
|
9
|
+
check(result: ParseResult): LintOffense[] {
|
|
10
|
+
return result.recursiveErrors().map(error =>
|
|
11
|
+
this.herbErrorToLintOffense(error)
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
private herbErrorToLintOffense(error: HerbError): LintOffense {
|
|
16
|
+
return {
|
|
17
|
+
message: `${error.message} (\`${error.type}\`)`,
|
|
18
|
+
location: error.location,
|
|
19
|
+
severity: error.severity,
|
|
20
|
+
rule: this.name,
|
|
21
|
+
code: this.name,
|
|
22
|
+
source: "linter"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -2,7 +2,7 @@ import { BaseRuleVisitor, SVG_CAMEL_CASE_ELEMENTS, SVG_LOWERCASE_TO_CAMELCASE }
|
|
|
2
2
|
|
|
3
3
|
import { ParserRule } from "../types.js"
|
|
4
4
|
import type { LintOffense, LintContext } from "../types.js"
|
|
5
|
-
import type { HTMLElementNode, HTMLOpenTagNode, HTMLCloseTagNode, HTMLSelfCloseTagNode,
|
|
5
|
+
import type { HTMLElementNode, HTMLOpenTagNode, HTMLCloseTagNode, HTMLSelfCloseTagNode, ParseResult } from "@herb-tools/core"
|
|
6
6
|
|
|
7
7
|
class SVGTagNameCapitalizationVisitor extends BaseRuleVisitor {
|
|
8
8
|
private insideSVG = false
|
|
@@ -66,9 +66,9 @@ class SVGTagNameCapitalizationVisitor extends BaseRuleVisitor {
|
|
|
66
66
|
export class SVGTagNameCapitalizationRule extends ParserRule {
|
|
67
67
|
name = "svg-tag-name-capitalization"
|
|
68
68
|
|
|
69
|
-
check(
|
|
69
|
+
check(result: ParseResult, context?: Partial<LintContext>): LintOffense[] {
|
|
70
70
|
const visitor = new SVGTagNameCapitalizationVisitor(this.name, context)
|
|
71
|
-
visitor.visit(
|
|
71
|
+
visitor.visit(result.value)
|
|
72
72
|
return visitor.offenses
|
|
73
73
|
}
|
|
74
74
|
}
|
package/src/types.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Diagnostic, LexResult, ParseResult } from "@herb-tools/core"
|
|
2
2
|
import type { defaultRules } from "./default-rules.js"
|
|
3
3
|
|
|
4
|
-
export type LintSeverity = "error" | "warning"
|
|
4
|
+
export type LintSeverity = "error" | "warning" | "info" | "hint"
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Automatically inferred union type of all available linter rule names.
|
|
@@ -23,7 +23,7 @@ export interface LintResult {
|
|
|
23
23
|
export abstract class ParserRule {
|
|
24
24
|
static type = "parser" as const
|
|
25
25
|
abstract name: string
|
|
26
|
-
abstract check(
|
|
26
|
+
abstract check(result: ParseResult, context?: Partial<LintContext>): LintOffense[]
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
export abstract class LexerRule {
|