-
-
Notifications
You must be signed in to change notification settings - Fork 794
feat(lint/vue): add noVueVIfWithVFor, useVueHyphenatedAttributes
#8097
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
🦋 Changeset detectedLatest commit: 95ddb39 The changes in this PR will be included in the next version bump. This PR includes changesets to release 13 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
CodSpeed Performance ReportMerging #8097 will not alter performanceComparing Summary
Footnotes
|
999910c to
b3187b8
Compare
bb7a5b1 to
c65e860
Compare
WalkthroughAdds two Vue-focused HTML lints and supporting infra: Possibly related PRs
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (1)
crates/biome_html_analyze/src/lint/nursery/use_vue_hyphenated_attributes.rs (1)
196-200: Consider refactoring for clarity (optional).The double-negative logic here (
if NOT (v-bind or v-model) then return None) is functionally correct but slightly harder to read. Consider a positive guard instead:- if let Ok(name) = directive.name_token().map(|name| name.token_text_trimmed()) - && !(name == "v-bind" || name == "v-model") - { - return None; - } + if let Ok(name) = directive.name_token().map(|name| name.token_text_trimmed()) + && name != "v-bind" && name != "v-model" + { + return None; + }Or restructure as:
if let Ok(name) = directive.name_token().map(|name| name.token_text_trimmed()) { if name != "v-bind" && name != "v-model" { return None; } }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (18)
crates/biome_configuration/src/analyzer/linter/rules.rsis excluded by!**/rules.rsand included by**crates/biome_diagnostics_categories/src/categories.rsis excluded by!**/categories.rsand included by**crates/biome_html_analyze/src/lint/nursery.rsis excluded by!**/nursery.rsand included by**crates/biome_html_analyze/tests/specs/nursery/noVueVIfWithVFor/invalid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/nursery/noVueVIfWithVFor/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/ignore/valid-ignored.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/invalid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_parser/tests/html_specs/ok/vue/v-bind-dynamic.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_parser/tests/html_specs/ok/vue/v-bind-mixed.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_parser/tests/html_specs/ok/vue/v-dynamic-chains.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_parser/tests/html_specs/ok/vue/v-else-if.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_parser/tests/html_specs/ok/vue/v-html-text.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_parser/tests/html_specs/ok/vue/v-mixed-complex.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_parser/tests/html_specs/ok/vue/v-model-mixed.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_parser/tests/html_specs/ok/vue/v-on-mixed.vue.snapis excluded by!**/*.snapand included by**packages/@biomejs/backend-jsonrpc/src/workspace.tsis excluded by!**/backend-jsonrpc/src/workspace.tsand included by**packages/@biomejs/biome/configuration_schema.jsonis excluded by!**/configuration_schema.jsonand included by**
📒 Files selected for processing (17)
.changeset/evil-experts-repeat.md(1 hunks).changeset/great-mammals-hide.md(1 hunks).changeset/loose-chairs-wonder.md(1 hunks)crates/biome_html_analyze/src/lint/nursery/no_vue_v_if_with_v_for.rs(1 hunks)crates/biome_html_analyze/src/lint/nursery/use_vue_hyphenated_attributes.rs(1 hunks)crates/biome_html_analyze/tests/spec_tests.rs(3 hunks)crates/biome_html_analyze/tests/specs/nursery/noVueVIfWithVFor/invalid.vue(1 hunks)crates/biome_html_analyze/tests/specs/nursery/noVueVIfWithVFor/valid.vue(1 hunks)crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/ignore/options.json(1 hunks)crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/ignore/valid-ignored.vue(1 hunks)crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/invalid.vue(1 hunks)crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/valid.vue(1 hunks)crates/biome_html_parser/src/lexer/mod.rs(2 hunks)crates/biome_html_parser/tests/quick_test.rs(1 hunks)crates/biome_rule_options/src/lib.rs(2 hunks)crates/biome_rule_options/src/no_vue_v_if_with_v_for.rs(1 hunks)crates/biome_rule_options/src/use_vue_hyphenated_attributes.rs(1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-10-25T07:02:26.457Z
Learnt from: ematipico
Repo: biomejs/biome PR: 7856
File: .changeset/yellow-crews-guess.md:1-5
Timestamp: 2025-10-25T07:02:26.457Z
Learning: The Biome documentation website uses kebab-case URL slugs for rule pages (e.g., `/linter/rules/no-continue/`), not camelCase.
Applied to files:
crates/biome_html_analyze/src/lint/nursery/use_vue_hyphenated_attributes.rs.changeset/great-mammals-hide.md
📚 Learning: 2025-08-05T14:43:29.581Z
Learnt from: dyc3
Repo: biomejs/biome PR: 7081
File: packages/@biomejs/biome/configuration_schema.json:7765-7781
Timestamp: 2025-08-05T14:43:29.581Z
Learning: The file `packages/biomejs/biome/configuration_schema.json` is auto-generated and should not be manually edited or reviewed for schema issues; any changes should be made at the code generation source.
Applied to files:
crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/ignore/options.json.changeset/great-mammals-hide.md
📚 Learning: 2025-09-25T12:32:59.003Z
Learnt from: arendjr
Repo: biomejs/biome PR: 7593
File: crates/biome_service/src/workspace/server.rs:1306-1306
Timestamp: 2025-09-25T12:32:59.003Z
Learning: In the biomejs/biome project, do not flag compilation errors during code review as they are handled by the existing test infrastructure and CI. Focus on other code quality aspects instead.
Applied to files:
crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/ignore/options.json
🧬 Code graph analysis (4)
crates/biome_html_parser/tests/quick_test.rs (1)
crates/biome_html_parser/src/parser.rs (1)
options(32-34)
crates/biome_html_analyze/src/lint/nursery/use_vue_hyphenated_attributes.rs (2)
crates/biome_analyze/src/rule.rs (3)
domains(632-635)sources(617-620)same(246-251)crates/biome_string_case/src/lib.rs (1)
identify(112-175)
crates/biome_html_analyze/src/lint/nursery/no_vue_v_if_with_v_for.rs (2)
crates/biome_analyze/src/rule.rs (4)
recommended(602-605)domains(632-635)sources(617-620)same(246-251)crates/biome_html_analyze/src/lint/nursery/use_vue_hyphenated_attributes.rs (2)
run(64-90)diagnostic(92-108)
crates/biome_html_analyze/tests/spec_tests.rs (1)
crates/biome_html_parser/src/lib.rs (1)
parse_html(37-40)
🪛 LanguageTool
.changeset/loose-chairs-wonder.md
[style] ~4-~4: Consider using a different verb for a more formal wording.
Context: --- "@biomejs/biome": patch --- Fixed an issue with the HTML parser where it ...
(FIX_RESOLVE)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: Test (depot-windows-2022-16)
- GitHub Check: Documentation
- GitHub Check: Test (depot-ubuntu-24.04-arm-16)
- GitHub Check: End-to-end tests
- GitHub Check: Check Dependencies
- GitHub Check: Check JS Files
- GitHub Check: autofix
- GitHub Check: Test Node.js API
- GitHub Check: Bench (biome_configuration)
🔇 Additional comments (23)
crates/biome_html_parser/tests/quick_test.rs (1)
8-11: LGTM! Vue dynamic argument syntax test updated correctly.The test now exercises Vue's dynamic directive argument syntax (
:[dynamicArg]), and the options correctly enable Vue parsing mode. Since this is an ignored quick test, it serves its purpose as a developer scratch pad..changeset/evil-experts-repeat.md (1)
1-5: LGTM!The changeset is clear and follows the standard format.
crates/biome_html_parser/src/lexer/mod.rs (2)
136-143: Good addition for Vue dynamic directive arguments.The bracket token support enables parsing of Vue's dynamic directive syntax (e.g.,
v-bind:[key]).
1078-1078: Correctly excludes Vue-specific characters from attribute names.This ensures Vue directive special characters (
:,.,[,]) are tokenised separately rather than as part of attribute names.crates/biome_html_analyze/tests/spec_tests.rs (1)
154-154: Good refactoring for Vue-aware parsing.Deriving parse options from the source type ensures Vue files are re-parsed with the correct Vue-specific lexer context.
Also applies to: 182-182
.changeset/loose-chairs-wonder.md (1)
1-5: LGTM!The changeset clearly documents the parser fix for Vue directive argument handling.
crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/ignore/options.json (1)
1-21: LGTM!The test configuration correctly exercises the rule's ignore options.
crates/biome_html_analyze/tests/specs/nursery/noVueVIfWithVFor/invalid.vue (1)
1-13: LGTM!The test fixtures correctly demonstrate both orderings of the v-if/v-for anti-pattern.
crates/biome_rule_options/src/lib.rs (1)
249-249: LGTM!The new rule option modules are correctly exported in alphabetical order.
Also applies to: 378-378
crates/biome_html_analyze/tests/specs/nursery/noVueVIfWithVFor/valid.vue (1)
1-13: LGTM!The test fixture correctly demonstrates the valid pattern where
v-ifandv-forare on separate elements. This aligns well with the rule's intent.crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/valid.vue (1)
1-28: LGTM!Excellent coverage of valid hyphenated attribute patterns across plain HTML, Vue directives, and custom components. The edge cases (dynamic arguments, non-v-bind directives) are particularly helpful.
crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/ignore/valid-ignored.vue (1)
1-4: LGTM!The fixture correctly validates that the
ignoreandignore_tagsoptions suppress diagnostics as expected.crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/invalid.vue (1)
1-18: LGTM!Good coverage of invalid patterns including camelCase, PascalCase, CONSTANT_CASE, and snake_case across plain HTML attributes and Vue directives.
crates/biome_rule_options/src/no_vue_v_if_with_v_for.rs (1)
1-6: LGTM!The empty options struct is appropriate for a rule without configuration, and all the derives and serde attributes are correctly applied.
crates/biome_rule_options/src/use_vue_hyphenated_attributes.rs (1)
1-13: LGTM!The options struct is well-designed with
FxHashSetfor efficient lookups and clear documentation for both configuration fields.crates/biome_html_analyze/src/lint/nursery/no_vue_v_if_with_v_for.rs (3)
60-91: LGTM!The
run()method correctly identifies bothv-ifandv-fordirectives on the same element and captures their ranges. The logic is straightforward and handles the case where either directive is missing.
93-109: LGTM!The diagnostic provides clear, actionable feedback with helpful suggestions for resolving the issue. The use of both the primary message and detail is well-structured.
45-45: No action required.The rule name is correct. The ESLint Vue.js rule is
vue/no-use-v-if-with-v-for, and the codebase correctly uses"no-use-v-if-with-v-for"as the suffix argument toRuleSource::EslintVueJs(). This matches the pattern used throughout the codebase for all Vue rules.Likely an incorrect or invalid review comment.
crates/biome_html_analyze/src/lint/nursery/use_vue_hyphenated_attributes.rs (5)
13-56: LGTM!The rule declaration is well-documented with clear examples. The
Unsafefix kind is appropriately marked with a comment indicating it's intentional whilst the team gains confidence in the rule.
64-90: LGTM!The
run()method correctly implements the ignore logic, checking tags first then individual attributes. The flow is clean and efficient.
92-108: LGTM!Clear diagnostic message with helpful context from the Vue style guide.
110-181: LGTM!The action method correctly handles token replacement for plain HTML attributes, Vue directives, and shorthand syntax. The batch mutation and trivia transfer are properly implemented.
227-230: LGTM!The
is_hyphenated()helper correctly usesCase::identify()with strict mode and appropriately accepts both kebab-case and pure lowercase attributes.
|
Great job! |
60c3473 to
794a504
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
crates/biome_service/src/configuration.rs (1)
433-452: HTML rules and assists now participate in analyser configuration.Adding
html_lint_metadatato bothpush_to_analyzer_rulesandpush_to_analyzer_assistbrings HTML/Vue rules into the same configuration pipeline as the other languages and allows their options to flow correctly through overrides.If you ever add HTML rules with
RuleDomain::Project, it may be worth also registering the HTML registry inProjectScanComputer::computeso project scans account for them too; not urgent today as the current Vue rules are non‑project domain.crates/biome_html_analyze/src/lint/nursery/no_vue_v_if_with_v_for.rs (1)
49-91: Implementation correctly detects elements combiningv-ifandv-for.Scanning the
HtmlAttributeListfor Vue directives and tracking thev-if/v-forranges is straightforward and robust; in practice there will only be one of each per element, so this works well.You could shave a few cycles by breaking out of the loop once both
v_ifandv_forhave been found, but that’s firmly in the micro‑optimisation bucket.crates/biome_html_analyze/src/lint/nursery/use_vue_hyphenated_attributes.rs (1)
158-229: Fix logic covers the important Vue surface area without over‑reaching.Handling plain HTML attributes,
v-bindwith static arguments, andv-bindshorthand in a single batch mutation keeps the implementation tidy while avoiding dynamic or non‑binding directives; the use ofCase::Kebab.convertshould give predictable rename suggestions.If you ever need to touch more directive shapes, consider extracting the repeated “replace static argument token with
suggested” snippet into a tiny helper to keep the action body from getting too branchy.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (18)
crates/biome_configuration/src/analyzer/linter/rules.rsis excluded by!**/rules.rsand included by**crates/biome_diagnostics_categories/src/categories.rsis excluded by!**/categories.rsand included by**crates/biome_html_analyze/src/lint/nursery.rsis excluded by!**/nursery.rsand included by**crates/biome_html_analyze/tests/specs/nursery/noVueVIfWithVFor/invalid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/nursery/noVueVIfWithVFor/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/ignore/valid-ignored.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/invalid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_parser/tests/html_specs/ok/vue/v-bind-dynamic.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_parser/tests/html_specs/ok/vue/v-bind-mixed.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_parser/tests/html_specs/ok/vue/v-dynamic-chains.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_parser/tests/html_specs/ok/vue/v-else-if.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_parser/tests/html_specs/ok/vue/v-html-text.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_parser/tests/html_specs/ok/vue/v-mixed-complex.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_parser/tests/html_specs/ok/vue/v-model-mixed.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_parser/tests/html_specs/ok/vue/v-on-mixed.vue.snapis excluded by!**/*.snapand included by**packages/@biomejs/backend-jsonrpc/src/workspace.tsis excluded by!**/backend-jsonrpc/src/workspace.tsand included by**packages/@biomejs/biome/configuration_schema.jsonis excluded by!**/configuration_schema.jsonand included by**
📒 Files selected for processing (20)
.changeset/evil-experts-repeat.md(1 hunks).changeset/great-mammals-hide.md(1 hunks).changeset/loose-chairs-wonder.md(1 hunks)crates/biome_html_analyze/src/lint/nursery/no_vue_v_if_with_v_for.rs(1 hunks)crates/biome_html_analyze/src/lint/nursery/use_vue_hyphenated_attributes.rs(1 hunks)crates/biome_html_analyze/tests/spec_tests.rs(3 hunks)crates/biome_html_analyze/tests/specs/nursery/noVueVIfWithVFor/invalid.vue(1 hunks)crates/biome_html_analyze/tests/specs/nursery/noVueVIfWithVFor/valid.vue(1 hunks)crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/ignore/valid-ignored.options.json(1 hunks)crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/ignore/valid-ignored.vue(1 hunks)crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/invalid.vue(1 hunks)crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/valid.vue(1 hunks)crates/biome_html_parser/src/lexer/mod.rs(2 hunks)crates/biome_html_parser/tests/quick_test.rs(1 hunks)crates/biome_rule_options/src/lib.rs(2 hunks)crates/biome_rule_options/src/no_vue_v_if_with_v_for.rs(1 hunks)crates/biome_rule_options/src/use_vue_hyphenated_attributes.rs(1 hunks)crates/biome_service/src/configuration.rs(2 hunks)crates/biome_service/src/file_handlers/html.rs(3 hunks)crates/biome_service/src/settings.rs(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
- crates/biome_html_parser/src/lexer/mod.rs
- crates/biome_html_analyze/tests/spec_tests.rs
- crates/biome_rule_options/src/no_vue_v_if_with_v_for.rs
- crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/invalid.vue
- crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/valid.vue
- crates/biome_rule_options/src/use_vue_hyphenated_attributes.rs
- crates/biome_html_parser/tests/quick_test.rs
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-10-25T07:02:26.457Z
Learnt from: ematipico
Repo: biomejs/biome PR: 7856
File: .changeset/yellow-crews-guess.md:1-5
Timestamp: 2025-10-25T07:02:26.457Z
Learning: The Biome documentation website uses kebab-case URL slugs for rule pages (e.g., `/linter/rules/no-continue/`), not camelCase.
Applied to files:
.changeset/great-mammals-hide.mdcrates/biome_html_analyze/src/lint/nursery/use_vue_hyphenated_attributes.rs
📚 Learning: 2025-08-05T14:43:29.581Z
Learnt from: dyc3
Repo: biomejs/biome PR: 7081
File: packages/@biomejs/biome/configuration_schema.json:7765-7781
Timestamp: 2025-08-05T14:43:29.581Z
Learning: The file `packages/biomejs/biome/configuration_schema.json` is auto-generated and should not be manually edited or reviewed for schema issues; any changes should be made at the code generation source.
Applied to files:
crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/ignore/valid-ignored.options.json
🧬 Code graph analysis (4)
crates/biome_service/src/configuration.rs (2)
crates/biome_service/src/file_handlers/graphql.rs (8)
settings(308-308)settings(312-312)settings(316-316)settings(353-353)settings(369-369)settings(387-387)settings(401-401)settings(500-500)crates/biome_service/src/file_handlers/css.rs (8)
settings(383-383)settings(387-387)settings(391-391)settings(456-456)settings(478-478)settings(496-496)settings(510-510)settings(544-544)
crates/biome_html_analyze/src/lint/nursery/no_vue_v_if_with_v_for.rs (1)
crates/biome_analyze/src/rule.rs (4)
recommended(602-605)domains(632-635)sources(617-620)same(246-251)
crates/biome_service/src/file_handlers/html.rs (2)
crates/biome_analyze/src/options.rs (1)
configuration(167-169)crates/biome_service/src/configuration.rs (1)
to_analyzer_rules(434-452)
crates/biome_html_analyze/src/lint/nursery/use_vue_hyphenated_attributes.rs (2)
crates/biome_analyze/src/rule.rs (1)
same(246-251)crates/biome_string_case/src/lib.rs (1)
identify(112-175)
🪛 LanguageTool
.changeset/loose-chairs-wonder.md
[style] ~4-~4: Consider using a different verb for a more formal wording.
Context: --- "@biomejs/biome": patch --- Fixed an issue with the HTML parser where it ...
(FIX_RESOLVE)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
- GitHub Check: Test Node.js API
- GitHub Check: Documentation
- GitHub Check: Check Dependencies
- GitHub Check: End-to-end tests
- GitHub Check: Test (depot-ubuntu-24.04-arm-16)
- GitHub Check: Test (depot-windows-2022-16)
- GitHub Check: Lint project (depot-windows-2022)
- GitHub Check: Check JS Files
- GitHub Check: autofix
- GitHub Check: Bench (biome_configuration)
🔇 Additional comments (19)
.changeset/loose-chairs-wonder.md (1)
1-5: LGTM!The changeset clearly documents the parser fix for Vue dynamic directive arguments.
crates/biome_service/src/settings.rs (2)
1403-1407: LGTM!The HTML analyzer metadata integration for linter rules follows the established pattern used by other language analyzers.
1431-1435: LGTM!The HTML analyzer metadata integration for assist actions is consistent with the existing structure.
.changeset/evil-experts-repeat.md (1)
1-12: LGTM!The changeset clearly explains the new rule with a helpful example that illustrates the invalid pattern.
crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/ignore/valid-ignored.options.json (1)
1-20: LGTM!The test options configuration correctly specifies the
ignoreandignoreTagssettings for validating the rule's ignore functionality.crates/biome_html_analyze/tests/specs/nursery/noVueVIfWithVFor/invalid.vue (1)
1-13: LGTM!The test fixture properly demonstrates the invalid patterns with
v-ifandv-foron the same element in both orderings..changeset/great-mammals-hide.md (1)
1-13: LGTM!The changeset clearly documents the new rule with a concise example showing the camelCase → kebab-case transformation.
crates/biome_rule_options/src/lib.rs (2)
250-250: LGTM!The
no_vue_v_if_with_v_formodule export is correctly positioned in alphabetical order.
380-380: LGTM!The
use_vue_hyphenated_attributesmodule export is correctly positioned in alphabetical order.crates/biome_html_analyze/tests/specs/nursery/noVueVIfWithVFor/valid.vue (1)
1-13: LGTM!The test fixture correctly demonstrates valid patterns where
v-ifandv-forare not combined on the same element.crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/ignore/valid-ignored.vue (1)
1-4: Fixture nicely exercises bothignoreandignoreTags.The two lines cleanly cover the component/tag ignore and attribute-name ignore paths, matching the described options; nothing more to ask for here.
crates/biome_service/src/configuration.rs (1)
25-25: HTML lint metadata import is consistent with other languages.Pulling in
biome_html_analyze::METADATAunder a dedicated alias mirrors the existing JS/CSS/JSON/GraphQL imports and keeps things uniform.crates/biome_service/src/file_handlers/html.rs (1)
7-16: HTML analyser options now correctly carry rule configuration.Using
to_analyzer_rules(global, path.as_path())to build anAnalyzerConfigurationand wiring it intoAnalyzerOptionsbrings HTML/Vue in line with the other languages and allows rule options to be honoured; the signature change from_globaltoglobalis the only behavioural tweak and looks spot on.Also applies to: 195-205, 208-210
crates/biome_html_analyze/src/lint/nursery/no_vue_v_if_with_v_for.rs (2)
9-47: Rule metadata and documentation align with the Vue style guide.The rule name, domain (
Vue), recommended status and ESLint Vue source all look correct, and the examples nicely mirror the common misuse patterns and fixes.
93-109: Diagnostic messaging is clear and points to concrete remedies.Highlighting the
v-foras the main span and using a.detailon thev-ifto suggest moving it to a wrapper or using a computed property matches common Vue guidance and should be very understandable to users.crates/biome_html_analyze/src/lint/nursery/use_vue_hyphenated_attributes.rs (4)
15-100: Rule definition and options match Vue’s attribute‑hyphenation expectations.The rule metadata, examples and the
ignore/ignoreTagsoptions map neatly onto the existing Vue ecosystem, and marking the fix asUnsafeis a sensible bit of honesty given it might not always match component APIs.
102-138: Signal collection respects ignore options and focuses on true case violations.Querying
AnyTagWithAttributes, short‑circuiting onignoreTags, then filtering attributes viaextract_attribute_name+is_hyphenatedgives you a tight signal set; the per‑attributeignorecheck slots in cleanly and should be cheap in practice.
140-157: Diagnostics are concise and attribute‑centric.Re‑deriving the attribute name for the message keeps things precise, and the note nudging users back towards the Vue style guide strikes a good balance between helpful and terse.
231-294: Helper utilities (AnyTagWithAttributes,extract_attribute_name,is_hyphenated) are well factored.The small union for tags plus the focused extractors make the rule easier to read and reuse, and restricting
is_hyphenatedtoKebab | LowerviaCase::identifydoes exactly what the docs promise.
794a504 to
95ddb39
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
crates/biome_html_analyze/src/lint/nursery/use_vue_hyphenated_attributes.rs (1)
158-227: Action logic is sound; consider extracting the mutation helper.The fix correctly handles plain HTML attributes and Vue directives (v-bind, v-model, shorthand), preserving trivia and skipping dynamic arguments. The duplicated token-replacement pattern (lines 172-178, 189-195, 205-210) could be extracted into a helper function to improve maintainability.
Example refactor for the mutation helper:
fn replace_name_token( mutation: &mut impl biome_rowan::BatchMutation, old_token: biome_html_syntax::HtmlSyntaxToken, new_name: &str, ) { let new_token = biome_html_syntax::HtmlSyntaxToken::new_detached( old_token.kind(), new_name, [], [], ); mutation.replace_token_transfer_trivia(old_token, new_token); }Then use:
replace_name_token(&mut mutation, old_token, &suggested);
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (18)
crates/biome_configuration/src/analyzer/linter/rules.rsis excluded by!**/rules.rsand included by**crates/biome_diagnostics_categories/src/categories.rsis excluded by!**/categories.rsand included by**crates/biome_html_analyze/src/lint/nursery.rsis excluded by!**/nursery.rsand included by**crates/biome_html_analyze/tests/specs/nursery/noVueVIfWithVFor/invalid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/nursery/noVueVIfWithVFor/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/ignore/valid-ignored.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/invalid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/valid.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_parser/tests/html_specs/ok/vue/v-bind-dynamic.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_parser/tests/html_specs/ok/vue/v-bind-mixed.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_parser/tests/html_specs/ok/vue/v-dynamic-chains.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_parser/tests/html_specs/ok/vue/v-else-if.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_parser/tests/html_specs/ok/vue/v-html-text.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_parser/tests/html_specs/ok/vue/v-mixed-complex.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_parser/tests/html_specs/ok/vue/v-model-mixed.vue.snapis excluded by!**/*.snapand included by**crates/biome_html_parser/tests/html_specs/ok/vue/v-on-mixed.vue.snapis excluded by!**/*.snapand included by**packages/@biomejs/backend-jsonrpc/src/workspace.tsis excluded by!**/backend-jsonrpc/src/workspace.tsand included by**packages/@biomejs/biome/configuration_schema.jsonis excluded by!**/configuration_schema.jsonand included by**
📒 Files selected for processing (20)
.changeset/evil-experts-repeat.md(1 hunks).changeset/great-mammals-hide.md(1 hunks).changeset/loose-chairs-wonder.md(1 hunks)crates/biome_html_analyze/src/lint/nursery/no_vue_v_if_with_v_for.rs(1 hunks)crates/biome_html_analyze/src/lint/nursery/use_vue_hyphenated_attributes.rs(1 hunks)crates/biome_html_analyze/tests/spec_tests.rs(3 hunks)crates/biome_html_analyze/tests/specs/nursery/noVueVIfWithVFor/invalid.vue(1 hunks)crates/biome_html_analyze/tests/specs/nursery/noVueVIfWithVFor/valid.vue(1 hunks)crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/ignore/valid-ignored.options.json(1 hunks)crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/ignore/valid-ignored.vue(1 hunks)crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/invalid.vue(1 hunks)crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/valid.vue(1 hunks)crates/biome_html_parser/src/lexer/mod.rs(2 hunks)crates/biome_html_parser/tests/quick_test.rs(1 hunks)crates/biome_rule_options/src/lib.rs(2 hunks)crates/biome_rule_options/src/no_vue_v_if_with_v_for.rs(1 hunks)crates/biome_rule_options/src/use_vue_hyphenated_attributes.rs(1 hunks)crates/biome_service/src/configuration.rs(2 hunks)crates/biome_service/src/file_handlers/html.rs(3 hunks)crates/biome_service/src/settings.rs(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (11)
- .changeset/evil-experts-repeat.md
- crates/biome_service/src/settings.rs
- crates/biome_html_analyze/tests/specs/nursery/noVueVIfWithVFor/invalid.vue
- crates/biome_service/src/file_handlers/html.rs
- crates/biome_html_analyze/tests/spec_tests.rs
- crates/biome_html_parser/src/lexer/mod.rs
- crates/biome_rule_options/src/use_vue_hyphenated_attributes.rs
- crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/invalid.vue
- crates/biome_rule_options/src/lib.rs
- crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/valid.vue
- crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/ignore/valid-ignored.options.json
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-10-25T07:02:26.457Z
Learnt from: ematipico
Repo: biomejs/biome PR: 7856
File: .changeset/yellow-crews-guess.md:1-5
Timestamp: 2025-10-25T07:02:26.457Z
Learning: The Biome documentation website uses kebab-case URL slugs for rule pages (e.g., `/linter/rules/no-continue/`), not camelCase.
Applied to files:
crates/biome_html_analyze/src/lint/nursery/use_vue_hyphenated_attributes.rs.changeset/great-mammals-hide.md
📚 Learning: 2025-08-05T14:43:29.581Z
Learnt from: dyc3
Repo: biomejs/biome PR: 7081
File: packages/@biomejs/biome/configuration_schema.json:7765-7781
Timestamp: 2025-08-05T14:43:29.581Z
Learning: The file `packages/biomejs/biome/configuration_schema.json` is auto-generated and should not be manually edited or reviewed for schema issues; any changes should be made at the code generation source.
Applied to files:
.changeset/great-mammals-hide.md
🧬 Code graph analysis (4)
crates/biome_service/src/configuration.rs (2)
crates/biome_service/src/file_handlers/css.rs (9)
settings(383-383)settings(387-387)settings(391-391)settings(456-456)settings(478-478)settings(496-496)settings(510-510)settings(544-544)settings(614-614)crates/biome_service/src/file_handlers/graphql.rs (7)
settings(308-308)settings(312-312)settings(316-316)settings(353-353)settings(369-369)settings(387-387)settings(401-401)
crates/biome_html_parser/tests/quick_test.rs (1)
crates/biome_html_parser/src/parser.rs (1)
options(32-34)
crates/biome_html_analyze/src/lint/nursery/no_vue_v_if_with_v_for.rs (2)
crates/biome_html_analyze/src/lint/nursery/use_vue_hyphenated_attributes.rs (3)
name(230-235)run(112-138)diagnostic(140-156)crates/biome_analyze/src/rule.rs (4)
recommended(602-605)domains(632-635)sources(617-620)same(246-251)
crates/biome_html_analyze/src/lint/nursery/use_vue_hyphenated_attributes.rs (2)
crates/biome_analyze/src/rule.rs (4)
recommended(602-605)domains(632-635)sources(617-620)same(246-251)crates/biome_string_case/src/lib.rs (1)
identify(112-175)
🪛 LanguageTool
.changeset/loose-chairs-wonder.md
[style] ~4-~4: Consider using a different verb for a more formal wording.
Context: --- "@biomejs/biome": patch --- Fixed an issue with the HTML parser where it ...
(FIX_RESOLVE)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
- GitHub Check: Check JS Files
- GitHub Check: Test (depot-windows-2022-16)
- GitHub Check: Test (depot-ubuntu-24.04-arm-16)
- GitHub Check: Documentation
- GitHub Check: End-to-end tests
- GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
- GitHub Check: Check Dependencies
- GitHub Check: Lint project (depot-windows-2022)
- GitHub Check: autofix
- GitHub Check: Test Node.js API
- GitHub Check: Bench (biome_configuration)
🔇 Additional comments (17)
.changeset/loose-chairs-wonder.md (1)
1-5: LGTM!The changeset clearly documents the parser fix for Vue dynamic arguments. The phrasing is standard and appropriate for a patch-level change.
.changeset/great-mammals-hide.md (1)
1-13: LGTM!The changeset is well-written and provides a clear example demonstrating the rule. The URL slug correctly follows the kebab-case convention.
crates/biome_html_parser/tests/quick_test.rs (1)
8-11: LGTM!The test correctly enables Vue parsing mode to exercise dynamic argument syntax. The builder-style API usage is clean and idiomatic.
crates/biome_html_analyze/tests/specs/nursery/noVueVIfWithVFor/valid.vue (1)
1-13: LGTM!The fixture correctly demonstrates the recommended pattern with
v-ifon the parent andv-foron the child, which should not trigger diagnostics.crates/biome_html_analyze/tests/specs/nursery/useVueHyphenatedAttributes/ignore/valid-ignored.vue (1)
1-4: LGTM!The fixture appropriately tests the ignore functionality, validating that configured exclusions prevent diagnostics from being generated.
crates/biome_service/src/configuration.rs (2)
25-25: LGTM!The HTML lint metadata import follows the established pattern for other language analyzers.
434-452: LGTM!The integration of HTML lint metadata into analyzer rules and assist actions is consistent with the existing CSS, JSON, and GraphQL handling. Well done!
crates/biome_rule_options/src/no_vue_v_if_with_v_for.rs (1)
1-6: LGTM!The options struct follows the established pattern with appropriate derives and serde attributes. The empty body is fine for a rule with no configurable options (yet).
crates/biome_html_analyze/src/lint/nursery/no_vue_v_if_with_v_for.rs (3)
9-47: LGTM!The rule declaration is comprehensive with clear documentation, examples, and proper metadata. The Vue style guide reference adds valuable context.
60-91: LGTM!The detection logic correctly identifies both
v-ifandv-fordirectives on the same element. The state is only returned when both are present, which is exactly right.
93-109: LGTM!The diagnostic provides clear messaging with helpful context. Highlighting the
v-forrange whilst adding detail for thev-ifrange effectively shows both problem locations.crates/biome_html_analyze/src/lint/nursery/use_vue_hyphenated_attributes.rs (6)
1-14: LGTM!Imports are clean and appropriate for the rule implementation.
15-100: Well-documented rule with sensible defaults.The documentation is comprehensive, examples are clear, and marking the fix as
Unsafeis appropriately conservative for automated attribute renaming.
229-243: LGTM!Clean helper implementation for abstracting over opening and self-closing elements.
289-292: LGTM!Correctly identifies kebab-case and pure lowercase as valid, using strict mode for accurate case detection.
112-138: Attribute comparison is correctly trimmed and consistent.Verification confirms
attr_nameis already trimmed viatoken_text_trimmed()(line 251), and calling.text()on it returns that trimmed text—matching the pattern used elsewhere in the codebase. Both tag and attribute comparisons operate on trimmed text, so the ignore list matching behaves correctly regardless of user configuration.
245-287: Code is correct — no changes needed.The parser properly separates directive names from modifiers. Line 258's
name_token()returns just the directive name (e.g.,"v-model"), whilst modifiers are accessed separately via.modifiers(). The filter correctly matchesv-modelandv-bindregardless of modifiers like.lazyor.number, sov-model.lazywill still be captured as expected.
Summary
This PR adds
noVueVIfWithVFor, anduseVueHyphenatedAttributes.It also fixes a parsing bug that I found while working on these rules, and implements html lint rules actually being able to receive options from configuration (it wasn't plumbed up before).
Test Plan
Added snapshot tests.
Docs