Skip to content

Conversation

@baeseokjae
Copy link
Contributor

Closes #8566

Summary

Adds a new nursery rule noVueOptionsApi to detect Options API usage incompatible with Vue 3.6's Vapor Mode.

Motivation:

Vue 3.6's Vapor Mode only supports Composition API with <script setup>. The Options API (data, methods, computed, lifecycle hooks, etc.) is not compatible with
Vapor Mode.

This rule helps developers:

  • Identify Options API patterns that need refactoring before migrating to Vapor Mode
  • Learn the corresponding Composition API alternatives through specific diagnostic messages
  • Prepare their codebase for Vue 3.6 Vapor Mode adoption

What this rule does:

  • Detects Options API properties: data, methods, computed, watch, lifecycle hooks (Vue 2 & 3), props, emits, mixins, extends, etc.
  • Supports multiple Vue component patterns: export default {}, defineComponent(), createApp()
  • Provides property-specific Composition API alternatives in diagnostic messages:
    • data → "Use ref() or reactive()"
    • mounted → "Use onMounted()"
    • computed → "Use computed()"
    • watch → "Use watch() or watchEffect()"
  • Allows pure setup() function usage (valid Composition API pattern)

Example:

<!-- ❌ Invalid -->
<script>
export default {
  data() {
    return { count: 0 }
  }
}
</script>

<!-- ✅ Valid -->
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>

Test Plan

Comprehensive test coverage with 18 test cases:

Invalid cases (9):

  • Options API with data, methods, computed, watch, mounted
  • defineComponent with Options API
  • createApp with Options API
  • Mixed setup() + Options API
  • Multiple Options API properties

Valid cases (9):

  • <script setup> (Composition API)
  • Pure setup() function
  • defineComponent with only setup()
  • Empty objects
  • Non-Vue patterns (class exports, functional components)

Docs

The rule documentation is implemented in the code as rustdoc comments in no_vue_options_api.rs, following Biome's conventions:

  • ✅ Rule description and purpose
  • ✅ Multiple invalid examples with expect_diagnostic
  • ✅ Valid examples showing correct Composition API usage
  • ✅ Clear explanation of Vue Vapor Mode context

The diagnostic messages are self-documenting, providing specific Composition API alternatives for each detected Options API property.

AI Assistance Disclosure

This PR was created with AI assistance (Cursor / Claude Opus 4.5). I reviewed and adjusted the implementation, diagnostics, and snapshots.

@changeset-bot
Copy link

changeset-bot bot commented Jan 2, 2026

🦋 Changeset detected

Latest commit: 7bd398f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 13 packages
Name Type
@biomejs/biome Patch
@biomejs/cli-win32-x64 Patch
@biomejs/cli-win32-arm64 Patch
@biomejs/cli-darwin-x64 Patch
@biomejs/cli-darwin-arm64 Patch
@biomejs/cli-linux-x64 Patch
@biomejs/cli-linux-arm64 Patch
@biomejs/cli-linux-x64-musl Patch
@biomejs/cli-linux-arm64-musl Patch
@biomejs/wasm-web Patch
@biomejs/wasm-bundler Patch
@biomejs/wasm-nodejs Patch
@biomejs/backend-jsonrpc Patch

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

@github-actions github-actions bot added A-Project Area: project A-Linter Area: linter L-JavaScript Language: JavaScript and super languages A-Diagnostic Area: diagnostocis labels Jan 2, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 2, 2026

Walkthrough

Adds a new nursery lint rule noVueOptionsApi that detects and reports Vue Options API usage (export default object, defineComponent({...}), createApp({...}), and Options API properties such as data, methods, computed, watch, lifecycle hooks and props) to enforce Vue 3.6 Vapor Mode constraints. Implements diagnostics with a per-diagnostic RuleState (range), a helper to detect defineComponent/createApp calls, an empty NoVueOptionsApiOptions options type, updates useVueVapor docs to reference the rule, and adds extensive positive and negative tests.

Possibly related PRs

Suggested reviewers

  • ematipico
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding a new noVueOptionsApi lint rule.
Description check ✅ Passed The description thoroughly explains the rule's purpose, motivation, implementation details, test coverage, and documentation—all directly related to the changeset.
Linked Issues check ✅ Passed The PR successfully implements all coding requirements from issue #8566: detects Options API patterns, supports multiple Vue component patterns, provides property-specific diagnostics, and includes comprehensive test coverage.
Out of Scope Changes check ✅ Passed All changes are in scope—the new rule implementation, test cases, configuration, documentation, and a single reference update in a related rule. No extraneous modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings


📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6d4b309 and 7bd398f.

⛔ Files ignored due to path filters (29)
  • crates/biome_configuration/src/analyzer/linter/rules.rs is excluded by !**/rules.rs and included by **
  • crates/biome_configuration/src/generated/domain_selector.rs is excluded by !**/generated/**, !**/generated/** and included by **
  • crates/biome_diagnostics_categories/src/categories.rs is excluded by !**/categories.rs and included by **
  • crates/biome_js_analyze/src/lint/nursery.rs is excluded by !**/nursery.rs and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-createapp-data.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-createapp-empty.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-definecomponent-data.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-definecomponent-empty.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-definecomponent-setup-option.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-computed.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-data.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-methods.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-mounted.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-watch.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-full-options-api.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-mixed-setup-data.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-multiple-options.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-props-only.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-class-export.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-createapp-import.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-definecomponent-function-signature.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-definecomponent-function-signature.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-definecomponent-function-with-options.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-functional-component.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-non-vue-object.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-passthrough-export.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-script-setup.vue.snap is excluded by !**/*.snap and included by **
  • packages/@biomejs/backend-jsonrpc/src/workspace.ts is excluded by !**/backend-jsonrpc/src/workspace.ts and included by **
  • packages/@biomejs/biome/configuration_schema.json is excluded by !**/configuration_schema.json and included by **
📒 Files selected for processing (28)
  • .changeset/add-no-v-options-api.md
  • crates/biome_html_analyze/src/lint/nursery/use_vue_vapor.rs
  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-createapp-data.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-createapp-empty.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-definecomponent-data.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-definecomponent-empty.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-definecomponent-setup-option.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-computed.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-data.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-methods.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-mounted.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-watch.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-full-options-api.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-mixed-setup-data.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-multiple-options.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-props-only.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-class-export.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-createapp-import.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-definecomponent-function-signature.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-definecomponent-function-signature.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-definecomponent-function-with-options.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-functional-component.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-non-vue-object.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-passthrough-export.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-script-setup.vue
  • crates/biome_rule_options/src/lib.rs
  • crates/biome_rule_options/src/no_vue_options_api.rs
✅ Files skipped from review due to trivial changes (1)
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-passthrough-export.js
🚧 Files skipped from review as they are similar to previous changes (18)
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-createapp-import.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-definecomponent-function-signature.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-mounted.vue
  • crates/biome_rule_options/src/no_vue_options_api.rs
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-createapp-empty.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-mixed-setup-data.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-props-only.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-definecomponent-setup-option.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-definecomponent-empty.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-definecomponent-function-signature.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-class-export.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-data.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-watch.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-definecomponent-data.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-multiple-options.vue
  • crates/biome_html_analyze/src/lint/nursery/use_vue_vapor.rs
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-non-vue-object.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-functional-component.js
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Use inline rustdoc documentation for rules, assists, and their options
Use the dbg!() macro for debugging output in Rust tests and code
Use doc tests (doctest) format with code blocks in rustdoc comments; ensure assertions pass in tests

Files:

  • crates/biome_rule_options/src/lib.rs
  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
🧠 Learnings (28)
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Applies to crates/biome_formatter/**/biome_*_formatter/tests/specs/**/options.json : Create an `options.json` file (formatted as `biome.json`) in test specification folders to apply non-default formatting options to all test files in that folder

Applied to files:

  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-definecomponent-function-with-options.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-full-options-api.vue
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/tests/specs/**/* : Create test files with `invalid` and `valid` prefixes to represent code that should and should not trigger the rule

Applied to files:

  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-methods.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-createapp-data.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-full-options-api.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-script-setup.vue
📚 Learning: 2025-11-21T01:10:53.059Z
Learnt from: dyc3
Repo: biomejs/biome PR: 8171
File: crates/biome_js_analyze/src/lint/nursery/no_leaked_render.rs:125-137
Timestamp: 2025-11-21T01:10:53.059Z
Learning: In the Biome codebase, each lint rule has its own options type declaration (e.g., `type Options = RuleNameOptions`) as part of the codegen process, even if the options struct is empty or unused. This is standard practice and should not be flagged as an issue.

Applied to files:

  • .changeset/add-no-v-options-api.md
  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Deprecated rules must include a `deprecated` field in the `declare_lint_rule!` macro with an explanation of what rule to use instead

Applied to files:

  • .changeset/add-no-v-options-api.md
  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-21T21:15:03.796Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T21:15:03.796Z
Learning: For new nursery rules, send PRs to the maintenance branch `main`

Applied to files:

  • .changeset/add-no-v-options-api.md
📚 Learning: 2025-12-31T15:35:41.261Z
Learnt from: dyc3
Repo: biomejs/biome PR: 8639
File: crates/biome_js_analyze/src/lint/nursery/no_excessive_lines_per_file.rs:101-108
Timestamp: 2025-12-31T15:35:41.261Z
Learning: In crates/biome_analyze/**/*analyze/src/lint/nursery/**/*.rs, the `issue_number` field in `declare_lint_rule!` macro is optional and the vast majority of nursery rules do not need it. Do not recommend adding `issue_number` unless there's a specific reason.

Applied to files:

  • .changeset/add-no-v-options-api.md
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Rule options must be defined in the `biome_rule_options` crate with a file named after the rule

Applied to files:

  • crates/biome_rule_options/src/lib.rs
  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Use `Option<_>` wrapper for rule option fields to enable proper merging of configurations

Applied to files:

  • crates/biome_rule_options/src/lib.rs
  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Apply `#[serde(deny_unknown_fields)]` to rule option structs to enforce strict configuration validation

Applied to files:

  • crates/biome_rule_options/src/lib.rs
  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Apply `#[serde(rename_all = "camelCase")]` to rule option structs to match JSON configuration naming convention

Applied to files:

  • crates/biome_rule_options/src/lib.rs
  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-11-24T18:05:42.356Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:42.356Z
Learning: Applies to crates/biome_js_type_info/**/*.rs : No module may copy or clone data from another module in the module graph, not even behind an `Arc`

Applied to files:

  • crates/biome_rule_options/src/lib.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Implement `biome_deserialize::Merge` for rule option types to define how shared and user configurations are merged

Applied to files:

  • crates/biome_rule_options/src/lib.rs
  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Use `Box<[Box<str>]>` instead of `Vec<String>` for collections of strings in rule options to save memory

Applied to files:

  • crates/biome_rule_options/src/lib.rs
  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Rule option types must derive `Deserializable`, `Serialize`, `Deserialize`, and optionally `JsonSchema` traits

Applied to files:

  • crates/biome_rule_options/src/lib.rs
  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-04T13:29:49.287Z
Learnt from: dyc3
Repo: biomejs/biome PR: 8291
File: crates/biome_html_formatter/tests/specs/prettier/vue/html-vue/elastic-header.html:10-10
Timestamp: 2025-12-04T13:29:49.287Z
Learning: Files under `crates/biome_html_formatter/tests/specs/prettier` are test fixtures synced from Prettier and should not receive detailed code quality reviews (e.g., HTTP vs HTTPS, formatting suggestions, etc.). These files are test data meant to validate formatter behavior and should be preserved as-is.

Applied to files:

  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-script-setup.vue
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `declare_lint_rule!` macro with a `version` field set to `next` for new rules

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-31T15:35:32.899Z
Learnt from: dyc3
Repo: biomejs/biome PR: 8639
File: crates/biome_js_analyze/src/lint/nursery/no_excessive_lines_per_file.rs:101-108
Timestamp: 2025-12-31T15:35:32.899Z
Learning: In Rust lint rules under the nursery category, the issue_number field in declare_lint_rule! is optional and should not be added unless there is a compelling reason. In code reviews, verify that no unnecessary issue_number is included in nursery lint declarations. Only add issue_number if there is an explicit, justified reason (e.g., tracked issue for external observers). This guidance broadly applies to all nursery lint rule files, not just the single file.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Rule names should use the `no` prefix when the rule's sole intention is to forbid a single concept

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-22T09:26:56.943Z
Learnt from: ematipico
Repo: biomejs/biome PR: 8537
File: crates/biome_js_analyze/src/lint/nursery/no_leaked_render.rs:167-210
Timestamp: 2025-12-22T09:26:56.943Z
Learning: When defining lint rules (declare_lint_rule!), only specify fix_kind if the rule implements an action(...) function. Rules that only emit diagnostics without a code fix should omit fix_kind. This applies to all Rust lint rule definitions under crates/.../src/lint (e.g., crates/biome_js_analyze/src/lint/...).

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Rule names should use the `use` prefix when the rule's sole intention is to mandate a single concept

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Implement the `run` function to return `Option<Self::State>` or `Vec<Self::State>` (as `Box<[Self::State]>`) depending on whether the rule reports one or multiple signals

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-10-03T12:28:56.788Z
Learnt from: ematipico
Repo: biomejs/biome PR: 7670
File: crates/biome_service/src/file_handlers/html.rs:744-748
Timestamp: 2025-10-03T12:28:56.788Z
Learning: In Biome's codebase, when creating tokens with new text content, use the factory pattern with functions like `ident(text)` from the respective `*_factory` crates (e.g., `biome_html_factory::make::ident`). There is no `.with_text()` method on tokens. The `ident()` function creates a new detached token with the IDENT kind, which is the standard approach for token construction.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-11-24T18:05:27.810Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:27.810Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : For tokens that are not mandatory, use helper functions instead of hardcoding

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Implement the `action` function and add `fix_kind` metadata to the rule macro if the rule provides code actions

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-21T21:15:03.796Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T21:15:03.796Z
Learning: Applies to **/*.rs : Use inline rustdoc documentation for rules, assists, and their options

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use the `Semantic<T>` query type to access semantic information about bindings, references, and scope within a rule

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use helper functions like `map`, `filter`, and `and_then` to avoid excessive nested `if let` statements

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Check if a variable is global using the semantic model before reporting diagnostics for rules that ban global functions or variables

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
🧬 Code graph analysis (2)
crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-definecomponent-function-with-options.js (2)
crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-definecomponent-setup-option.js (1)
  • count (8-8)
crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-definecomponent-function-signature.js (1)
  • count (6-6)
crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs (5)
crates/biome_service/src/workspace.rs (1)
  • markup (1195-1197)
packages/@biomejs/plugin-api/index.d.ts (1)
  • Severity (1-1)
crates/biome_analyze/src/rule.rs (2)
  • recommended (625-628)
  • domains (655-658)
crates/biome_html_analyze/src/lint/nursery/use_vue_vapor.rs (2)
  • run (59-76)
  • diagnostic (78-91)
crates/biome_js_syntax/src/expr_ext.rs (1)
  • callee (33-38)
⏰ 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). (16)
  • GitHub Check: Validate rules documentation
  • GitHub Check: Bench (biome_js_analyze)
  • GitHub Check: Bench (biome_js_parser)
  • GitHub Check: Bench (biome_js_formatter)
  • GitHub Check: lint
  • GitHub Check: autofix
  • GitHub Check: Test Node.js API
  • GitHub Check: Check JS Files
  • GitHub Check: Documentation
  • GitHub Check: Bench (biome_configuration)
  • GitHub Check: Lint project (depot-windows-2022)
  • GitHub Check: Test (depot-windows-2022-16)
  • GitHub Check: Lint project (depot-ubuntu-24.04-arm-16)
  • GitHub Check: Test (depot-ubuntu-24.04-arm-16)
  • GitHub Check: End-to-end tests
  • GitHub Check: Check Dependencies
🔇 Additional comments (11)
crates/biome_rule_options/src/lib.rs (1)

271-271: LGTM!

New module export follows alphabetical ordering and aligns with the rule options convention.

crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs (4)

13-126: Well-documented rule with comprehensive examples.

The rustdoc covers invalid and valid patterns thoroughly, includes links to related rules and external resources. This meets the inline documentation guidelines.


148-182: Sound logic for component variant handling.

The branching correctly:

  • Allows <script setup> (Setup variant)
  • Allows defineComponent with function signature (via setup_func() check)
  • Flags object-based options in DefineComponent and CreateApp
  • Guards OptionsApi against edge cases with is_define_component_or_create_app

The as_js_object_expression().is_some() guard ensures function signatures aren't incorrectly flagged.


185-201: Diagnostic message follows agreed wording.

The notes provide clear guidance on Composition API adoption and link to Vue documentation.


204-216: Helper function placement is correct.

Moved below impl Rule as requested in previous review.

.changeset/add-no-v-options-api.md (1)

1-21: Changeset accurately describes the new rule.

Content aligns with the implementation and provides a clear example of what triggers the rule.

crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-computed.vue (1)

1-11: LGTM!

Valid test case for detecting Options API computed property usage. The invalid- prefix correctly indicates this should trigger diagnostics.

crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-script-setup.vue (1)

1-12: LGTM!

Clean and idiomatic <script setup> example — exactly what the rule should permit. Good test coverage for the Vapor Mode compatible pattern.

crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-methods.vue (1)

1-12: LGTM!

Minimal and focused test case for the methods Options API property. Correctly prefixed as invalid- and should trigger the expected diagnostic.

crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-definecomponent-function-with-options.js (1)

1-19: LGTM!

Important edge case test — the defineComponent(fn, options) signature is Composition API even when the second argument contains props and emits. This ensures the rule doesn't false-positive on Vue 3.3+ function-signature components with extra type declarations.

crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-full-options-api.vue (1)

1-30: LGTM!

Comprehensive test covering multiple Options API properties. The entire object expression gets flagged by the rule, so name is included in that context as part of the Options API component definition — no special exclusion needed.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 (5)
crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-functional-component.js (1)

1-5: Consider importing h for a more realistic test.

Whilst this correctly tests that functional components don't trigger the rule, the h function should be imported from 'vue' to represent valid Vue 3 code.

🔎 Suggested addition
+import { h } from 'vue'
+
 // should not generate diagnostics
 export default function MyComponent(props) {
   return h('div', props.message)
 }
crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-mixed-setup-data.vue (1)

5-5: Consider adding import { ref } from 'vue' for test realism (optional).

Whilst test fixtures needn't be executable, adding the import would make this more representative of real-world code. Not critical, as the rule analyses syntax rather than runtime behaviour.

Suggested enhancement
 <script>
+import { ref } from 'vue'
+
 // Mixed setup() with Options API is not supported in Vapor Mode
 export default {
 	setup() {
crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-full-options-api.vue (1)

2-4: Consider clarifying the comment regarding which properties are flagged.

The comment states "all should be flagged", but name (line 4) is component metadata rather than an Options API property requiring migration. The rule targets data, methods, computed, watch, lifecycle hooks, props, etc.

Suggested clarification
-// Full Options API component with multiple properties - all should be flagged
+// Full Options API component - all Options API properties should be flagged
 export default {
   name: 'MyComponent',
crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-composition-setup-only.vue (1)

1-11: Test case looks good.

Correctly validates that pure Composition API with setup() doesn't trigger the rule.

Optional: Add import for completeness

Whilst not required for lint testing, adding the import would make the example more realistic:

 <script>
+import { ref } from 'vue'
 /* should not generate diagnostics */
 // Pure Composition API with setup() is valid
 export default {
crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs (1)

188-224: Consider extracting the duplicated detection logic.

The three match arms for OptionsApi, DefineComponent, and CreateApp contain identical logic. This could be refactored to reduce duplication.

🔎 Proposed refactor

If the VueOptionsApiBasedComponent trait (or similar) exposes iter_declaration_groups(), you could unify this:

-        match component.kind() {
-            AnyVueComponent::OptionsApi(opts) => {
-                for (name, member) in opts.iter_declaration_groups() {
-                    let name_text = name.text();
-                    // Allow pure setup() - only flag if has other Options API props
-                    if name_text != "setup" && OPTIONS_API_PROPERTIES.contains(&name_text) {
-                        signals.push(RuleState {
-                            range: member.range(),
-                            property_name: name_text.to_string(),
-                        });
-                    }
-                }
-            }
-            AnyVueComponent::DefineComponent(dc) => {
-                for (name, member) in dc.iter_declaration_groups() {
-                    let name_text = name.text();
-                    if name_text != "setup" && OPTIONS_API_PROPERTIES.contains(&name_text) {
-                        signals.push(RuleState {
-                            range: member.range(),
-                            property_name: name_text.to_string(),
-                        });
-                    }
-                }
-            }
-            AnyVueComponent::CreateApp(ca) => {
-                for (name, member) in ca.iter_declaration_groups() {
-                    let name_text = name.text();
-                    if name_text != "setup" && OPTIONS_API_PROPERTIES.contains(&name_text) {
-                        signals.push(RuleState {
-                            range: member.range(),
-                            property_name: name_text.to_string(),
-                        });
-                    }
-                }
-            }
-            _ => {}
-        }
+        let declaration_groups: Box<dyn Iterator<Item = _>> = match component.kind() {
+            AnyVueComponent::OptionsApi(opts) => Box::new(opts.iter_declaration_groups()),
+            AnyVueComponent::DefineComponent(dc) => Box::new(dc.iter_declaration_groups()),
+            AnyVueComponent::CreateApp(ca) => Box::new(ca.iter_declaration_groups()),
+            _ => return signals,
+        };
+
+        for (name, member) in declaration_groups {
+            let name_text = name.text();
+            if name_text != "setup" && OPTIONS_API_PROPERTIES.contains(&name_text) {
+                signals.push(RuleState {
+                    range: member.range(),
+                    property_name: name_text.to_string(),
+                });
+            }
+        }

Alternatively, a helper closure or macro could achieve the same. This is a minor nit—the current code is perfectly readable.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3a27a7 and 0794874.

⛔ Files ignored due to path filters (24)
  • crates/biome_configuration/src/analyzer/linter/rules.rs is excluded by !**/rules.rs and included by **
  • crates/biome_configuration/src/generated/domain_selector.rs is excluded by !**/generated/**, !**/generated/** and included by **
  • crates/biome_diagnostics_categories/src/categories.rs is excluded by !**/categories.rs and included by **
  • crates/biome_js_analyze/src/lint/nursery.rs is excluded by !**/nursery.rs and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-createapp-data.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-definecomponent-data.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-computed.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-data.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-methods.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-mounted.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-watch.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-full-options-api.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-mixed-setup-data.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-multiple-options.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-class-export.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-composition-setup-only.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-definecomponent-setup.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-empty-object.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-functional-component.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-non-vue-object.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-passthrough-export.js.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-script-setup.vue.snap is excluded by !**/*.snap and included by **
  • packages/@biomejs/backend-jsonrpc/src/workspace.ts is excluded by !**/backend-jsonrpc/src/workspace.ts and included by **
  • packages/@biomejs/biome/configuration_schema.json is excluded by !**/configuration_schema.json and included by **
📒 Files selected for processing (22)
  • .changeset/add-no-v-options-api.md
  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-createapp-data.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-definecomponent-data.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-computed.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-data.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-methods.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-mounted.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-watch.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-full-options-api.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-mixed-setup-data.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-multiple-options.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-class-export.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-composition-setup-only.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-definecomponent-setup.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-empty-object.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-functional-component.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-non-vue-object.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-passthrough-export.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-script-setup.vue
  • crates/biome_rule_options/src/lib.rs
  • crates/biome_rule_options/src/no_vue_options_api.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Use inline rustdoc documentation for rules, assists, and their options
Use the dbg!() macro for debugging output in Rust tests and code
Use doc tests (doctest) format with code blocks in rustdoc comments; ensure assertions pass in tests

Files:

  • crates/biome_rule_options/src/no_vue_options_api.rs
  • crates/biome_rule_options/src/lib.rs
  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
🧠 Learnings (32)
📓 Common learnings
Learnt from: dyc3
Repo: biomejs/biome PR: 8171
File: crates/biome_js_analyze/src/lint/nursery/no_leaked_render.rs:125-137
Timestamp: 2025-11-21T01:10:53.059Z
Learning: In the Biome codebase, each lint rule has its own options type declaration (e.g., `type Options = RuleNameOptions`) as part of the codegen process, even if the options struct is empty or unused. This is standard practice and should not be flagged as an issue.
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/tests/specs/**/*invalid* : Create test files prefixed with `invalid` for code that should trigger the rule

Applied to files:

  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-definecomponent-data.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-multiple-options.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-mixed-setup-data.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-createapp-data.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-full-options-api.vue
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/tests/specs/**/*valid* : Create test files prefixed with `valid` for code that should not trigger the rule

Applied to files:

  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-definecomponent-data.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-functional-component.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-non-vue-object.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-class-export.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-multiple-options.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-script-setup.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-createapp-data.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-full-options-api.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-empty-object.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-composition-setup-only.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-passthrough-export.js
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/biome_rule_options/lib/**/*.rs : Use `deny_unknown_fields` in serde derive macro for rule options

Applied to files:

  • crates/biome_rule_options/src/no_vue_options_api.rs
  • crates/biome_rule_options/src/lib.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/biome_rule_options/lib/**/*.rs : Rule options struct must derive `Deserializable`, `Serialize`, `Deserialize`, and optionally `JsonSchema`

Applied to files:

  • crates/biome_rule_options/src/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/biome_rule_options/lib/**/*.rs : Wrap rule options fields in `Option<>` to properly track set and unset options during merge

Applied to files:

  • crates/biome_rule_options/src/no_vue_options_api.rs
  • crates/biome_rule_options/src/lib.rs
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-multiple-options.vue
  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/biome_rule_options/lib/**/*.rs : Use `rename_all = "camelCase"` in serde derive macro for rule options

Applied to files:

  • crates/biome_rule_options/src/no_vue_options_api.rs
  • crates/biome_rule_options/src/lib.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Rule documentation must include `## Options` section if the rule has options

Applied to files:

  • crates/biome_rule_options/src/no_vue_options_api.rs
  • crates/biome_rule_options/src/lib.rs
  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/biome_rule_options/lib/**/*.rs : Implement `Merge` trait for rule options to support configuration inheritance

Applied to files:

  • crates/biome_rule_options/src/no_vue_options_api.rs
  • crates/biome_rule_options/src/lib.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/biome_rule_options/lib/**/*.rs : Rule options must be placed inside the `biome_rule_options` crate

Applied to files:

  • crates/biome_rule_options/src/no_vue_options_api.rs
  • crates/biome_rule_options/src/lib.rs
📚 Learning: 2025-11-21T01:10:53.059Z
Learnt from: dyc3
Repo: biomejs/biome PR: 8171
File: crates/biome_js_analyze/src/lint/nursery/no_leaked_render.rs:125-137
Timestamp: 2025-11-21T01:10:53.059Z
Learning: In the Biome codebase, each lint rule has its own options type declaration (e.g., `type Options = RuleNameOptions`) as part of the codegen process, even if the options struct is empty or unused. This is standard practice and should not be flagged as an issue.

Applied to files:

  • crates/biome_rule_options/src/no_vue_options_api.rs
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-multiple-options.vue
  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
  • .changeset/add-no-v-options-api.md
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Use `full_options` code block property for complete biome.json configuration snippets in documentation

Applied to files:

  • crates/biome_rule_options/src/no_vue_options_api.rs
  • crates/biome_rule_options/src/lib.rs
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-multiple-options.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-full-options-api.vue
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Use `options` code block property for rule-specific configuration snippets in documentation

Applied to files:

  • crates/biome_rule_options/src/no_vue_options_api.rs
  • crates/biome_rule_options/src/lib.rs
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-multiple-options.vue
  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Applies to crates/biome_formatter/**/biome_*_formatter/tests/specs/**/options.json : Create an `options.json` file (formatted as `biome.json`) in test specification folders to apply non-default formatting options to all test files in that folder

Applied to files:

  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-non-vue-object.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-multiple-options.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-full-options-api.vue
📚 Learning: 2025-12-04T13:29:49.287Z
Learnt from: dyc3
Repo: biomejs/biome PR: 8291
File: crates/biome_html_formatter/tests/specs/prettier/vue/html-vue/elastic-header.html:10-10
Timestamp: 2025-12-04T13:29:49.287Z
Learning: Files under `crates/biome_html_formatter/tests/specs/prettier` are test fixtures synced from Prettier and should not receive detailed code quality reviews (e.g., HTTP vs HTTPS, formatting suggestions, etc.). These files are test data meant to validate formatter behavior and should be preserved as-is.

Applied to files:

  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-non-vue-object.js
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-script-setup.vue
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/biome_rule_options/lib/**/*.rs : Use `Box<[T]>` instead of `Vec<T>` for rule options arrays to save memory

Applied to files:

  • crates/biome_rule_options/src/lib.rs
📚 Learning: 2025-11-24T18:05:42.356Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:42.356Z
Learning: Applies to crates/biome_js_type_info/**/*.rs : No module may copy or clone data from another module in the module graph, not even behind an `Arc`

Applied to files:

  • crates/biome_rule_options/src/lib.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/tests/specs/**/*.jsonc : Use `.jsonc` files to contain arrays of code snippet strings for snapshot tests

Applied to files:

  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-multiple-options.vue
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-script-setup.vue
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Lint rules should perform static analysis of source code to detect invalid or error-prone patterns and emit diagnostics with proposed fixes

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Set `version` field to `next` in `declare_lint_rule!` macro

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-31T15:35:32.899Z
Learnt from: dyc3
Repo: biomejs/biome PR: 8639
File: crates/biome_js_analyze/src/lint/nursery/no_excessive_lines_per_file.rs:101-108
Timestamp: 2025-12-31T15:35:32.899Z
Learning: In Rust lint rules under the nursery category, the issue_number field in declare_lint_rule! is optional and should not be added unless there is a compelling reason. In code reviews, verify that no unnecessary issue_number is included in nursery lint declarations. Only add issue_number if there is an explicit, justified reason (e.g., tracked issue for external observers). This guidance broadly applies to all nursery lint rule files, not just the single file.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/nursery/**/*.rs : Place new rules inside the `nursery` group during development

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
  • .changeset/add-no-v-options-api.md
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Use `declare_lint_rule!` macro to declare analyzer rule types and implement the RuleMeta trait

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Add `deprecated` field to `declare_lint_rule!` macro when deprecating a rule

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Use `RuleSource::Eslint(...).same()` when implementing a rule that matches the behavior of an ESLint rule

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Use `RuleSource::Eslint(...).inspired()` when implementing a rule inspired by but with different behavior than an ESLint rule

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Each invalid code example in rule documentation must emit exactly one diagnostic

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Rule documentation code blocks should be ordered as language, expect_diagnostic, options/full_options/use_options, ignore, file

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Invalid code examples in rule documentation must be marked with `expect_diagnostic` code block property

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-22T09:26:56.943Z
Learnt from: ematipico
Repo: biomejs/biome PR: 8537
File: crates/biome_js_analyze/src/lint/nursery/no_leaked_render.rs:167-210
Timestamp: 2025-12-22T09:26:56.943Z
Learning: When defining lint rules (declare_lint_rule!), only specify fix_kind if the rule implements an action(...) function. Rules that only emit diagnostics without a code fix should omit fix_kind. This applies to all Rust lint rule definitions under crates/.../src/lint (e.g., crates/biome_js_analyze/src/lint/...).

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-21T21:15:03.796Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-12-21T21:15:03.796Z
Learning: For new nursery rules, send PRs to the maintenance branch `main`

Applied to files:

  • .changeset/add-no-v-options-api.md
📚 Learning: 2025-12-31T15:35:41.261Z
Learnt from: dyc3
Repo: biomejs/biome PR: 8639
File: crates/biome_js_analyze/src/lint/nursery/no_excessive_lines_per_file.rs:101-108
Timestamp: 2025-12-31T15:35:41.261Z
Learning: In crates/biome_analyze/**/*analyze/src/lint/nursery/**/*.rs, the `issue_number` field in `declare_lint_rule!` macro is optional and the vast majority of nursery rules do not need it. Do not recommend adding `issue_number` unless there's a specific reason.

Applied to files:

  • .changeset/add-no-v-options-api.md
🧬 Code graph analysis (3)
crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-functional-component.js (1)
crates/biome_js_analyze/tests/specs/suspicious/noRedeclare/valid-declaration-merging.ts (1)
  • h (131-133)
crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs (1)
crates/biome_analyze/src/rule.rs (3)
  • recommended (619-622)
  • domains (649-652)
  • sources (634-637)
crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-passthrough-export.js (1)
crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-functional-component.js (1)
  • MyComponent (2-4)
🔇 Additional comments (20)
crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-class-export.js (1)

1-6: Good test case for preventing false positives.

This correctly validates that class-based exports with methods named like Options API properties shouldn't trigger the rule. The noVueOptionsApi rule properly targets Vue component patterns (plain objects, defineComponent, createApp) rather than arbitrary classes.

crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-empty-object.vue (1)

1-5: LGTM!

Valid test case – an empty component object correctly demonstrates that the rule doesn't flag non-Options-API patterns.

crates/biome_rule_options/src/lib.rs (1)

261-261: LGTM!

Module correctly added in alphabetical order amongst the other Vue rule options.

crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-multiple-options.vue (1)

1-14: LGTM!

Test correctly validates detection of multiple Options API properties in a single component.

crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-definecomponent-data.vue (1)

1-10: LGTM!

Test correctly validates that Options API usage is detected within defineComponent() wrappers.

crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-definecomponent-setup.vue (1)

1-13: Test fixture correctly represents valid Composition API usage.

This test case properly demonstrates defineComponent with setup() function, which is Vapor Mode compatible and should not trigger diagnostics.

crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-createapp-data.vue (1)

1-10: Test fixture correctly represents invalid Options API usage.

This test case properly demonstrates createApp with the Options API data property, which should trigger diagnostics as it's incompatible with Vapor Mode.

crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-script-setup.vue (1)

1-12: Test fixture correctly represents valid Composition API usage.

This test case properly demonstrates the <script setup> syntax, which is the recommended Vapor Mode compatible pattern and should not trigger diagnostics.

crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-mounted.vue (1)

1-9: Test fixture correctly represents invalid Options API usage.

This test case properly demonstrates the Options API mounted() lifecycle hook, which should trigger diagnostics as it's incompatible with Vapor Mode.

crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-methods.vue (1)

1-11: Test fixture correctly represents invalid Options API usage.

This test case properly demonstrates the Options API methods property, which should trigger diagnostics as it's incompatible with Vapor Mode.

crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-data.vue (1)

1-8: Test fixture looks correct.

Clear, minimal test case for detecting data() Options API usage. Comment appropriately explains the incompatibility.

.changeset/add-no-v-options-api.md (1)

1-22: Changeset documentation is clear and well-structured.

Proper format, concise explanation, and helpful examples contrasting invalid and valid patterns. Good work.

crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-watch.vue (1)

1-10: Test fixture appropriately demonstrates watch detection.

The fixture correctly tests Options API watch option detection. The referenced count property needn't be defined for the lint rule to function.

crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-full-options-api.vue (1)

5-27: Excellent comprehensive test coverage.

This fixture nicely exercises multiple Options API properties (props, data, computed, watch, methods, mounted) in a single component, ensuring the rule can detect and report multiple diagnostics correctly.

crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-passthrough-export.js (1)

1-3: Test case looks good.

The passthrough export pattern is correctly identified as valid—the rule should only flag component definitions, not re-exports.

crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-computed.vue (1)

1-10: Test case looks good.

Correctly demonstrates Options API computed usage that should trigger diagnostics for Vapor Mode incompatibility.

crates/biome_rule_options/src/no_vue_options_api.rs (1)

1-6: Spot on—follows all conventions.

Empty options struct with proper derives (Deserializable, Merge, serde traits) and attributes (camelCase, deny_unknown_fields). Standard practice for rules without configuration options.

crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/valid-non-vue-object.js (1)

1-6: Edge case properly tested. Plain objects with Options API–like properties in .js files correctly bypass the rule since the implementation distinguishes Vue components from regular exports via file type and component pattern detection.

crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs (2)

11-74: Well-structured rule declaration.

Documentation is clear, examples are correctly annotated with expect_diagnostic, and the metadata follows nursery conventions (version: "next", recommended: false). Based on learnings, this aligns with Biome's lint rule guidelines.


229-247: Clear and helpful diagnostics.

The diagnostic messages are well-crafted: they identify the offending property, explain the Vapor Mode constraint, and suggest a specific Composition API alternative. This will be genuinely useful for developers migrating their codebases.

@baeseokjae baeseokjae marked this pull request as draft January 2, 2026 09:49
@baeseokjae baeseokjae marked this pull request as ready for review January 2, 2026 09:50
Copy link
Member

@ematipico ematipico left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! The code can be improved and simplified

@baeseokjae baeseokjae requested a review from ematipico January 2, 2026 12:05
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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_js_analyze/src/lint/nursery/no_vue_options_api.rs (1)

244-277: Consider extracting the common iteration logic.

The three match arms for OptionsApi, DefineComponent, and CreateApp perform identical operations. You could reduce duplication with a helper function, though the current structure is perfectly functional.

🔎 Potential refactor
fn check_properties<'a>(
    iter: impl Iterator<Item = (TokenText, impl AstNode)>,
) -> Option<RuleState> {
    for (name, member) in iter {
        let name_text = name.text();
        if name_text != "setup" && OPTIONS_API_PROPERTIES.contains(&name_text) {
            return Some(RuleState {
                range: member.range(),
                property_name: name,
            });
        }
    }
    None
}

// Then in run():
match component.kind() {
    AnyVueComponent::OptionsApi(opts) => check_properties(opts.iter_declaration_groups()),
    AnyVueComponent::DefineComponent(dc) => check_properties(dc.iter_declaration_groups()),
    AnyVueComponent::CreateApp(ca) => check_properties(ca.iter_declaration_groups()),
    _ => None,
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 435e3a9 and b80da67.

⛔ Files ignored due to path filters (2)
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-full-options-api.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-multiple-options.vue.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (1)
  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Use inline rustdoc documentation for rules, assists, and their options
Use the dbg!() macro for debugging output in Rust tests and code
Use doc tests (doctest) format with code blocks in rustdoc comments; ensure assertions pass in tests

Files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
🧠 Learnings (27)
📓 Common learnings
Learnt from: dyc3
Repo: biomejs/biome PR: 8171
File: crates/biome_js_analyze/src/lint/nursery/no_leaked_render.rs:125-137
Timestamp: 2025-11-21T01:10:53.059Z
Learning: In the Biome codebase, each lint rule has its own options type declaration (e.g., `type Options = RuleNameOptions`) as part of the codegen process, even if the options struct is empty or unused. This is standard practice and should not be flagged as an issue.
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Rule documentation must include `## Options` section if the rule has options

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/biome_rule_options/lib/**/*.rs : Wrap rule options fields in `Option<>` to properly track set and unset options during merge

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Set `version` field to `next` in `declare_lint_rule!` macro

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Use `options` code block property for rule-specific configuration snippets in documentation

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-11-21T01:10:53.059Z
Learnt from: dyc3
Repo: biomejs/biome PR: 8171
File: crates/biome_js_analyze/src/lint/nursery/no_leaked_render.rs:125-137
Timestamp: 2025-11-21T01:10:53.059Z
Learning: In the Biome codebase, each lint rule has its own options type declaration (e.g., `type Options = RuleNameOptions`) as part of the codegen process, even if the options struct is empty or unused. This is standard practice and should not be flagged as an issue.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-31T15:35:32.899Z
Learnt from: dyc3
Repo: biomejs/biome PR: 8639
File: crates/biome_js_analyze/src/lint/nursery/no_excessive_lines_per_file.rs:101-108
Timestamp: 2025-12-31T15:35:32.899Z
Learning: In Rust lint rules under the nursery category, the issue_number field in declare_lint_rule! is optional and should not be added unless there is a compelling reason. In code reviews, verify that no unnecessary issue_number is included in nursery lint declarations. Only add issue_number if there is an explicit, justified reason (e.g., tracked issue for external observers). This guidance broadly applies to all nursery lint rule files, not just the single file.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Lint rules should perform static analysis of source code to detect invalid or error-prone patterns and emit diagnostics with proposed fixes

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/nursery/**/*.rs : Place new rules inside the `nursery` group during development

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Add `deprecated` field to `declare_lint_rule!` macro when deprecating a rule

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-22T09:26:56.943Z
Learnt from: ematipico
Repo: biomejs/biome PR: 8537
File: crates/biome_js_analyze/src/lint/nursery/no_leaked_render.rs:167-210
Timestamp: 2025-12-22T09:26:56.943Z
Learning: When defining lint rules (declare_lint_rule!), only specify fix_kind if the rule implements an action(...) function. Rules that only emit diagnostics without a code fix should omit fix_kind. This applies to all Rust lint rule definitions under crates/.../src/lint (e.g., crates/biome_js_analyze/src/lint/...).

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Use `full_options` code block property for complete biome.json configuration snippets in documentation

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Return `Option<State>` from `run` function for single diagnostic signals

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Return `Vec<State>` or `Box<[State]>` from `run` function for multiple diagnostic signals

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-10-03T12:28:56.788Z
Learnt from: ematipico
Repo: biomejs/biome PR: 7670
File: crates/biome_service/src/file_handlers/html.rs:744-748
Timestamp: 2025-10-03T12:28:56.788Z
Learning: In Biome's codebase, when creating tokens with new text content, use the factory pattern with functions like `ident(text)` from the respective `*_factory` crates (e.g., `biome_html_factory::make::ident`). There is no `.with_text()` method on tokens. The `ident()` function creates a new detached token with the IDENT kind, which is the standard approach for token construction.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Avoid string allocations by comparing against `&str` or using `TokenText`

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/biome_rule_options/lib/**/*.rs : Rule options must be placed inside the `biome_rule_options` crate

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/biome_rule_options/lib/**/*.rs : Use `Box<[T]>` instead of `Vec<T>` for rule options arrays to save memory

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/biome_rule_options/lib/**/*.rs : Use `deny_unknown_fields` in serde derive macro for rule options

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/biome_rule_options/lib/**/*.rs : Use `rename_all = "camelCase"` in serde derive macro for rule options

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-11-24T18:05:27.810Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:27.810Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : For tokens that are not mandatory, use helper functions instead of hardcoding

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Use `use_options` code block property for code examples that follow an options configuration in documentation

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Use `RuleSource::Eslint(...).same()` when implementing a rule that matches the behavior of an ESLint rule

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Each invalid code example in rule documentation must emit exactly one diagnostic

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Use `RuleSource::Eslint(...).inspired()` when implementing a rule inspired by but with different behavior than an ESLint rule

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/lint/**/*.rs : Lint rules should check syntax according to language specification and emit error diagnostics

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-19T12:53:30.413Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2025-12-19T12:53:30.413Z
Learning: Applies to crates/biome_analyze/**/*analyze/src/**/*.rs : Rule documentation code blocks should be ordered as language, expect_diagnostic, options/full_options/use_options, ignore, file

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
🔇 Additional comments (7)
crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs (7)

1-10: LGTM!

Imports are correctly structured and follow Biome lint rule conventions.


12-134: Verify whether an Options section is needed for empty options.

The rule declares type Options = NoVueOptionsApiOptions. According to retrieved learnings, rule documentation must include an ## Options section if the rule has options. However, the PR summary indicates this is an empty options struct. Please confirm whether an Options section should be added to the documentation even when the options struct contains no fields.

Based on learnings, as per coding guidelines.


136-172: LGTM!

Comprehensive coverage of Options API properties, including both Vue 2 and Vue 3 lifecycle hooks. The commented grouping aids readability.


174-213: LGTM!

Excellent property-specific guidance for Composition API alternatives. The comprehensive mappings align well with the OPTIONS_API_PROPERTIES list.


215-221: LGTM!

Proper use of TokenText avoids unnecessary string allocations, following Biome best practices.


229-282: LGTM!

The logic correctly:

  • Skips <script setup> components
  • Allows pure setup() functions
  • Detects Options API properties across all component patterns
  • Uses TokenText to avoid allocations

Past review feedback has been properly addressed (OptionSelf::State, TokenText usage).


284-303: LGTM!

Diagnostic messaging is clear and provides actionable guidance with property-specific Composition API alternatives.

@baeseokjae
Copy link
Contributor Author

baeseokjae commented Jan 2, 2026

@ematipico Thanks for the review! I've addressed all the feedback. Let me know if anything else needs to be changed.

@github-actions github-actions bot added the L-HTML Language: HTML and super languages label Jan 2, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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_js_analyze/src/lint/nursery/no_vue_options_api.rs (1)

113-117: Consider adding a direct link to Vue Options API documentation.

The Resources section links to Composition API docs and API comparison, but a direct link to the Options API documentation would help users understand what's being flagged.

Suggested addition
 /// ## Resources
 ///
+/// - [Vue Options API](https://vuejs.org/api/options-state.html)
 /// - [Vue 3 Composition API](https://vuejs.org/api/composition-api-setup.html)
 /// - [Options API vs Composition API](https://vuejs.org/guide/introduction.html#api-styles)

Based on learnings, this addresses ematipico's earlier feedback about providing links to the Options API.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b80da67 and 5b14ee2.

⛔ Files ignored due to path filters (11)
  • crates/biome_configuration/src/analyzer/linter/rules.rs is excluded by !**/rules.rs and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-createapp-data.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-definecomponent-data.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-computed.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-data.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-methods.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-mounted.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-export-default-watch.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-full-options-api.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-mixed-setup-data.vue.snap is excluded by !**/*.snap and included by **
  • crates/biome_js_analyze/tests/specs/nursery/noVueOptionsApi/invalid-multiple-options.vue.snap is excluded by !**/*.snap and included by **
📒 Files selected for processing (2)
  • crates/biome_html_analyze/src/lint/nursery/use_vue_vapor.rs
  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
✅ Files skipped from review due to trivial changes (1)
  • crates/biome_html_analyze/src/lint/nursery/use_vue_vapor.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Use inline rustdoc documentation for rules, assists, and their options
Use the dbg!() macro for debugging output in Rust tests and code
Use doc tests (doctest) format with code blocks in rustdoc comments; ensure assertions pass in tests

Files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
🧠 Learnings (21)
📚 Learning: 2026-01-02T14:58:16.514Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.514Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `declare_lint_rule!` macro with a `version` field set to `next` for new rules

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.514Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.514Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Deprecated rules must include a `deprecated` field in the `declare_lint_rule!` macro with an explanation of what rule to use instead

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-11-21T01:10:53.059Z
Learnt from: dyc3
Repo: biomejs/biome PR: 8171
File: crates/biome_js_analyze/src/lint/nursery/no_leaked_render.rs:125-137
Timestamp: 2025-11-21T01:10:53.059Z
Learning: In the Biome codebase, each lint rule has its own options type declaration (e.g., `type Options = RuleNameOptions`) as part of the codegen process, even if the options struct is empty or unused. This is standard practice and should not be flagged as an issue.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-31T15:35:32.899Z
Learnt from: dyc3
Repo: biomejs/biome PR: 8639
File: crates/biome_js_analyze/src/lint/nursery/no_excessive_lines_per_file.rs:101-108
Timestamp: 2025-12-31T15:35:32.899Z
Learning: In Rust lint rules under the nursery category, the issue_number field in declare_lint_rule! is optional and should not be added unless there is a compelling reason. In code reviews, verify that no unnecessary issue_number is included in nursery lint declarations. Only add issue_number if there is an explicit, justified reason (e.g., tracked issue for external observers). This guidance broadly applies to all nursery lint rule files, not just the single file.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.514Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.514Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Rule names should use the `no` prefix when the rule's sole intention is to forbid a single concept

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.514Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.514Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Rule options must be defined in the `biome_rule_options` crate with a file named after the rule

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.514Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.514Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Use `Option<_>` wrapper for rule option fields to enable proper merging of configurations

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.514Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.514Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : New rules must be placed inside the `nursery` group before promotion to other groups

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-12-22T09:26:56.943Z
Learnt from: ematipico
Repo: biomejs/biome PR: 8537
File: crates/biome_js_analyze/src/lint/nursery/no_leaked_render.rs:167-210
Timestamp: 2025-12-22T09:26:56.943Z
Learning: When defining lint rules (declare_lint_rule!), only specify fix_kind if the rule implements an action(...) function. Rules that only emit diagnostics without a code fix should omit fix_kind. This applies to all Rust lint rule definitions under crates/.../src/lint (e.g., crates/biome_js_analyze/src/lint/...).

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.514Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.514Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Rule names should use the `use` prefix when the rule's sole intention is to mandate a single concept

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.514Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.514Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Implement the `run` function to return `Option<Self::State>` or `Vec<Self::State>` (as `Box<[Self::State]>`) depending on whether the rule reports one or multiple signals

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-10-03T12:28:56.788Z
Learnt from: ematipico
Repo: biomejs/biome PR: 7670
File: crates/biome_service/src/file_handlers/html.rs:744-748
Timestamp: 2025-10-03T12:28:56.788Z
Learning: In Biome's codebase, when creating tokens with new text content, use the factory pattern with functions like `ident(text)` from the respective `*_factory` crates (e.g., `biome_html_factory::make::ident`). There is no `.with_text()` method on tokens. The `ident()` function creates a new detached token with the IDENT kind, which is the standard approach for token construction.

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.514Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.514Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Apply `#[serde(deny_unknown_fields)]` to rule option structs to enforce strict configuration validation

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.514Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.514Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Rule option types must derive `Deserializable`, `Serialize`, `Deserialize`, and optionally `JsonSchema` traits

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.514Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.514Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Use `Box<[Box<str>]>` instead of `Vec<String>` for collections of strings in rule options to save memory

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2025-11-24T18:05:27.810Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:27.810Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : For tokens that are not mandatory, use helper functions instead of hardcoding

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.514Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.514Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Apply `#[serde(rename_all = "camelCase")]` to rule option structs to match JSON configuration naming convention

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.514Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.514Z
Learning: Applies to crates/biome_analyze/biome_rule_options/lib/**/*.rs : Implement `biome_deserialize::Merge` for rule option types to define how shared and user configurations are merged

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.514Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.514Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Check if a variable is global using the semantic model before reporting diagnostics for rules that ban global functions or variables

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.514Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.514Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Code blocks in rule documentation must specify a language identifier and be tagged with `expect_diagnostic` for invalid examples or remain untagged for valid examples

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
📚 Learning: 2026-01-02T14:58:16.514Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.514Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Invalid code snippets in rule documentation must emit exactly one diagnostic

Applied to files:

  • crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs
🧬 Code graph analysis (1)
crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs (4)
crates/biome_service/src/workspace.rs (1)
  • markup (1195-1197)
crates/biome_analyze/src/rule.rs (2)
  • recommended (619-622)
  • domains (649-652)
crates/biome_js_syntax/src/expr_ext.rs (1)
  • callee (33-38)
crates/biome_html_analyze/src/lint/nursery/use_vue_vapor.rs (2)
  • run (59-76)
  • diagnostic (78-91)
🔇 Additional comments (4)
crates/biome_js_analyze/src/lint/nursery/no_vue_options_api.rs (4)

1-12: Imports look good.

All necessary imports are present and follow Biome conventions.


128-132: RuleState structure is appropriate.

Simple and focused state for passing range information to diagnostics.


160-213: Implementation follows conventions correctly.

The rule implementation properly uses the VueComponent framework helpers and follows Biome patterns. The simplified approach (flagging any Options API usage rather than providing property-specific alternatives) aligns with the feedback that Vapor Mode doesn't support Options API at all.


134-148: The duplicate detection logic is necessary and correct.

The VueComponentQuery matches multiple independent node types (JsExportDefaultExpressionClause and JsCallExpression), so code like export default defineComponent({data(){...}}) would be categorised as both OptionsApi (the export default) and DefineComponent (the call expression). Without the check, both cases would fire and generate duplicate diagnostics. The test snapshots confirm only one diagnostic is generated per case, validating this approach.

@baeseokjae baeseokjae requested a review from dyc3 January 2, 2026 15:13
@baeseokjae
Copy link
Contributor Author

@dyc3
Thank you for the review! I've addressed your feedback and added cross-references between the two rules.

Regarding the simplification suggestion: since Options API usage results in a compile-time error in Vapor Mode, I understand the concern that a linter rule might seem redundant. The intent here is to provide early, actionable feedback so developers can identify and refactor incompatible patterns before hitting compiler errors during migration.

Please let me know if there’s anything else you’d like me to adjust.

@dyc3 dyc3 added the D-Vue Domains: Vue label Jan 5, 2026
@github-actions github-actions bot added A-CLI Area: CLI A-Parser Area: parser A-Formatter Area: formatter L-CSS Language: CSS labels Jan 6, 2026
@baeseokjae baeseokjae force-pushed the feat/ban-vue-options-api branch from 0978dbc to 3692dd4 Compare January 6, 2026 14:57
@github-actions github-actions bot removed A-Parser Area: parser A-Formatter Area: formatter L-CSS Language: CSS labels Jan 6, 2026
@baeseokjae baeseokjae requested a review from dyc3 January 6, 2026 15:13
@baeseokjae
Copy link
Contributor Author

Hi @dyc3, thank you for the thorough review.

I've addressed all of your feedback in the latest commits. In particular, I added the guard for defineComponent used with the function signature, along with corresponding tests, as discussed.

Please take another look when you have a chance. Thanks again!

@codspeed-hq
Copy link

codspeed-hq bot commented Jan 6, 2026

CodSpeed Performance Report

Merging this PR will not alter performance

Comparing BaeSeokJae:feat/ban-vue-options-api (7bd398f) with main (0d15370)

Summary

✅ 58 untouched benchmarks
⏩ 95 skipped benchmarks1

Footnotes

  1. 95 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@dyc3
Copy link
Contributor

dyc3 commented Jan 6, 2026

One of my comments hasn't been addressed #8648 (comment)

@baeseokjae
Copy link
Contributor Author

Apologies — it seems the change didn’t get applied earlier. I’ve applied it now!

@dyc3
Copy link
Contributor

dyc3 commented Jan 6, 2026

No worries! It happens :)

@dyc3
Copy link
Contributor

dyc3 commented Jan 6, 2026

Snapshots need to be updated

@baeseokjae
Copy link
Contributor Author

Done!

@dyc3
Copy link
Contributor

dyc3 commented Jan 7, 2026

Please avoid merging main into this branch because it invalidates the CI, and since you are a first time contributor, we have to manually approve the runs. If there's merge conflicts, we'll handle it.

@baeseokjae
Copy link
Contributor Author

Got it, thanks!
I won’t merge main into this branch and will leave any conflicts as-is.

baeseokjae and others added 6 commits January 15, 2026 16:44
  Detects Vue Options API usage incompatible with Vue 3.6 Vapor Mode.

  - Flags Options API properties: data, methods, computed, watch, lifecycle hooks
  - Provides Composition API alternatives specific to each property
  - Supports export default, defineComponent, createApp patterns
  - Includes 18 test cases (9 invalid, 9 valid patterns)
  - Severity: Error, recommended: false (nursery)

  Helps prepare Vue codebases for Vapor Mode migration.
Addressed review comments for the `noVueOptionsApi` rule:

- Changed `type Signals` from `Vec<Self::State>` to `Option<Self::State>`
- Changed `property_name` type from `String` to `TokenText` to avoid heap allocation
- Changed `type Options` from `()` to `NoVueOptionsApiOptions` (generated options type)
- Removed empty `sources: &[]` field

- Added more Invalid examples: `computed`, `mounted`, `defineComponent`
- Added more Valid examples: `computed()`, `onMounted()`
- Added `## Resources` section with Vue official documentation links

- `just test-lintrule noVueOptionsApi` - 18 tests passed
- `just f` / `just l` / `just gen-analyzer` - all passed
- Add useVueVapor reference to noVueOptionsApi docs
- Add noVueOptionsApi reference to useVueVapor docs
- Update test snapshots
- Remove redundant test cases
Add comprehensive test coverage for defineComponent and createApp edge cases.
Update snapshots and fix documentation.
Co-authored-by: Carson McManus <dyc3@users.noreply.github.com>
@dyc3 dyc3 force-pushed the feat/ban-vue-options-api branch from 69d9c20 to 7bd398f Compare January 15, 2026 21:44
@dyc3 dyc3 dismissed ematipico’s stale review January 15, 2026 21:45

requested changes were addressed

@dyc3 dyc3 merged commit 96d09f4 into biomejs:main Jan 15, 2026
20 checks passed
@github-actions github-actions bot mentioned this pull request Jan 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-CLI Area: CLI A-Diagnostic Area: diagnostocis A-Linter Area: linter A-Project Area: project D-Vue Domains: Vue L-HTML Language: HTML and super languages L-JavaScript Language: JavaScript and super languages

3 participants