github biomejs/biome @biomejs/biome@2.6.5
Biome CLI v2.6.5

4 hours ago

2.6.5

Patch Changes

  • #12755 bbc4887 Thanks @dyc3! - Added the new nursery rule noArrayForEach, which reports forEach() calls that can be written as for...of loops. Values known not to be arrays, such as a Map or a Set, are ignored.

    array.forEach((element) => {
    	bar(element);
    });
  • #12777 ba692e4 Thanks @dyc3! - Added the new nursery rule noAwaitInPromiseMethods, which reports await inside the array passed to Promise.all(), Promise.allSettled(), Promise.any(), or Promise.race(). The await pauses the code before the method is called, so the promises no longer run at the same time.

    Promise.all([await promise, anotherPromise]);
  • #12765 af84fb4 Thanks @dyc3! - Added the new nursery rule noChainedComparison, which reports comparisons chained like a < b < c or a === b === c. JavaScript compares a with b first, and then compares the resulting true or false with c, so 3 > 2 > 1 is false.

    if (a < b < c) {}
  • #12547 0a2073d Thanks @dyc3! - Added the nursery rule noDynamicDelete, which disallows using delete with a property name that is computed at runtime. Fixed property names written as string or number literals are allowed.

    delete container[name];
  • #12481 ed7adc2 Thanks @dyc3! - Added the nursery rule noLateEventControl, which reports calls to preventDefault(), stopPropagation(), and stopImmediatePropagation() that run after the browser has finished handling the event, where they have no effect.

    element.addEventListener("click", async (event) => {
      await save();
      event.preventDefault();
    });
  • #12795 179666d Thanks @dyc3! - Added the nursery rule noMapSpread, which disallows spreading objects or arrays in the values returned by map() and flatMap() callbacks. Each spread copies a whole object or array for every item, which is slow for large arrays. Its unsafe fix replaces an object that starts with a spread with Object.assign().

    const users = getUsers();
    const rows = users.map((user) => ({ ...user, role: getRole(user) }));
  • #12793 d9a99fd Thanks @dyc3! - Added the nursery rule noMismatchedMapKey, which reports get() and set() calls that use a different key than the has() check before them. Checking one key and then using another is usually a copy-paste mistake.

    if (map.has(key)) {
      map.get(otherKey); // reported
    }
  • #12342 1db7c0d Thanks @vibbix! - Added the nursery rule noMissingScssInterpolation, which disallows Sass variables and function calls in custom property values without #{} interpolation. Sass copies these values into the CSS unchanged, so the browser receives $gap or math.div(8px, 2) instead of their results. Its unsafe fix wraps variables in #{}.

    :root {
      --gap: $gap;
      --half: math.div(8px, 2);
    }
  • #12792 de86b37 Thanks @dyc3! - Added the nursery rule noMissingThrow, which reports errors that are created with new but never thrown. Its unsafe fix adds the missing throw keyword.

    function check(value) {
      if (!value) {
        new Error("Missing value");
      }
    }
  • #12790 c23e4c3 Thanks @dyc3! - Added the new nursery rule noObjectLiteralComparison, which reports comparisons with an empty object {} or an empty array []. These comparisons never check whether a value is empty, because objects and arrays are compared by reference.

    if (value === {}) {}
  • #12450 793f07d Thanks @dyc3! - Added the new nursery rule noPlaywrightUnsafeReferences, which reports functions passed to page.evaluate() or page.addInitScript() that use variables declared outside of them. Playwright runs these functions in the browser page, where those variables don't exist.

    const x = 7;
    await page.evaluate(() => x * 2); // reported: `x` must be passed as an argument
  • #12388 a0160a4 Thanks @vibbix! - Added the nursery rule noPseudoElementInFunctionalPseudoClass, which disallows pseudo-elements inside :is(), :where(), :not() and :has(). Browsers drop these selectors, so the styles never apply to the pseudo-element.

    .card:is(::before, ::after) {
      content: "";
    }
  • #12779 bc1befb Thanks @dyc3! - Added the new nursery rule noSinglePromiseInPromiseMethods, which reports an array with a single element passed to Promise.all(), Promise.any(), or Promise.race(). The rule offers a fix that awaits the value directly or uses Promise.resolve().

    const result = await Promise.all([promise]);
  • #12241 d96de1d Thanks @dyc3! - Added the nursery rule noSvelteBindValueOnCheckableInputs, which reports bind:value on checkbox and radio inputs in Svelte files. Users change whether these inputs are checked, not their value, so bind:value does not track their choice.

    <input type="checkbox" bind:value={accepted} />
  • #12764 e166d08 Thanks @dyc3! - Added the new nursery rule noSyncMethods, which reports calls to functions whose names end with Sync, such as fs.readFileSync(). These calls block the program until they finish. The allowAtRootLevel option allows them outside of functions, and the ignore option allows specific function names.

    const contents = fs.readFileSync("data.txt");
  • #12515 c0a4174 Thanks @dyc3! - Added the nursery rule noTanstackQueryVoidQueryFn, which disallows TanStack Query functions that don't return any data. TanStack Query doesn't accept undefined as the data of a query, so the query fails with an error.

    import { useQuery } from "@tanstack/react-query";
    
    useQuery({
        queryKey: ["todos"],
        queryFn: async () => {
            await fetch("/api/todos");
        },
    });

    The rule belongs to the tanstackQuery and types domains.

  • #12482 1e6e407 Thanks @dyc3! - Added the nursery rule noUnnecessaryStringTrim, which reports trim() calls before startsWith() or endsWith() when only one side of the string matters. Use trimStart() or trimEnd() instead.

    value.trim().startsWith("-");
  • #12772 a108773 Thanks @dyc3! - Added the nursery rule noUselessAwait, which reports await on values that are never promises, such as literals, arrays, and the results of comparisons.

    await [fetchUser(), fetchPosts()];
  • #12783 d0931b0 Thanks @dyc3! - Added the new nursery rule noUselessLengthCheck, which reports array length checks that don't change the result: a check that the array is empty next to every(), a check that it isn't empty next to some(), or a check that it isn't empty around a for...of loop over the same array.

    if (array.length > 0 && array.some(Boolean)) {}
  • #12488 93e0e73 Thanks @dyc3! - Added the new nursery rule noUselessTypeAssertion, which reports type assertions that don't change the type of an expression, such as a non-null assertion on a value that can't be null or undefined.

    function double(value: number): number {
      return value! * 2;
    }
  • #12632 0e197b4 Thanks @dyc3! - Added the nursery rule noVueChildContent, which disallows content inside elements that use v-html or v-text. These directives replace the content of their element, so Vue discards anything written there.

    <template>
      <div v-html="html">Loading...</div>
    </template>
  • #12616 cb7b888 Thanks @dyc3! - Added the new nursery rule noVueDeprecatedConfigKeyCodes, which reports uses of Vue.config.keyCodes. Vue 3 removed this option, so custom key names defined with it no longer work.

    Vue.config.keyCodes = { f1: 112 };
  • #12568 59f3a42 Thanks @dyc3! - Added the nursery rule noVueDeprecatedDestroyedLifecycle, which reports the beforeDestroy and destroyed lifecycle hooks in Vue components. Vue 3 renamed them to beforeUnmount and unmounted, and no longer calls hooks with the old names.

    <script>
    export default {
      destroyed() {},
    };
    </script>
  • #12654 bcb1e0f Thanks @dyc3! - Added the nursery rule noVueDeprecatedEventsApi, which reports calls to the $on, $off, and $once instance methods in Vue components. Vue 3 removed these methods, so calling them throws an error.

    <script>
    export default {
      mounted() {
        this.$on("start", handler); // reported
      },
    };
    </script>
  • #12590 b9872ef Thanks @dyc3! - Added the nursery rule noVueDeprecatedFunctionalTemplate, which reports the functional attribute on the <template> of a Vue component. Vue 3 no longer supports this attribute.

    <template functional>
      <div>{{ props.message }}</div>
    </template>
  • #12552 b71b705 Thanks @dyc3! - Added the nursery rule noVueDeprecatedHtmlElementIs, which disallows the is attribute on HTML elements in Vue templates. Vue 3 no longer renders a component in place of these elements, unless the value starts with vue:.

    <template>
      <tr is="my-row"></tr>
    </template>
  • #12553 4a613e1 Thanks @dyc3! - Added the nursery rule noVueDeprecatedInlineTemplate, which disallows the inline-template attribute on Vue components. Vue 3 removed this feature, so the content between the component's tags is no longer used as its template.

    <template>
      <my-component inline-template>
        <div>{{ message }}</div>
      </my-component>
    </template>
  • #12617 0e9ca5b Thanks @dyc3! - Added the nursery rule noVueDeprecatedModelDefinition, which reports the model option in Vue components. Vue 3 ignores this option, so v-model on the component always uses the modelValue prop and the update:modelValue event.

    <script>
    export default {
      model: {
        prop: "checked",
        event: "change",
      },
    };
    </script>
  • #12604 e998921 Thanks @dyc3! - Added the nursery rule noVueDeprecatedPropsDefaultThis, which reports this inside the function that computes the default value of a Vue prop. Vue doesn't give this function access to the component, so this doesn't point to it. Read other props from the function's first argument instead.

    <script>
    export default {
      props: {
        size: Number,
        sizes: {
          type: Array,
          default() {
            return [this.size];
          },
        },
      },
    };
    </script>
  • #12633 f65fe1e Thanks @dyc3! - Added the nursery rule noVueDeprecatedSlotAttribute, which reports the slot attribute in Vue templates. Vue 3 no longer uses this attribute to fill named slots, so use v-slot (or #) on a <template> element instead.

    <template>
      <MyComponent>
        <template slot="header">Title</template>
      </MyComponent>
    </template>
  • #12589 8ccb19a Thanks @dyc3! - Added the new nursery rule noVueDeprecatedVBindSync, which reports the .sync modifier on Vue v-bind directives. Vue 3 removed this modifier, so the rule suggests v-model with the same argument instead.

    <MyComponent :title.sync="pageTitle" />
  • #12609 e1e102b Thanks @dyc3! - Added the new nursery rule noVueDeprecatedVOnNativeModifier, which disallows the .native modifier on Vue's v-on directive. Vue 3 removed this modifier.

    <MyComponent @click.native="onClick" />
  • #12667 de354e7 Thanks @dyc3! - Added the new nursery rule noVueExcessiveProps, which reports Vue components that declare more props than the maxProps option allows. The default limit is 10.

    <!-- With "maxProps": 2 -->
    <script setup lang="ts">
    defineProps<{ title: string; subtitle: string; icon: string }>(); // reported
    </script>
  • #12666 c3dc557 Thanks @dyc3! - Added the nursery rule noVueLoneTemplate, which reports <template> elements inside a Vue template that don't use v-if, v-else-if, v-else, v-for, or v-slot. Vue renders these as regular HTML <template> elements, so their content isn't shown.

    <template>
      <template>
        <p>Hello</p>
      </template>
    </template>
  • #12533 4b1089d Thanks @dyc3! - Added the new nursery rule noVueMixin, which reports the mixins option in Vue components. In Vue 3, composables are the recommended way to share logic between components. The rule is recommended and part of the vue domain.

    <script>
    export default {
      mixins: [counterMixin],
    };
    </script>
  • #12658 807e358 Thanks @dyc3! - Added the new nursery rule noVueMultipleObjectsInClass, which reports :class arrays in Vue templates that contain more than one object. Merge the conditional classes into a single object instead.

    <template>
      <div :class="[{ active: isActive }, { disabled: isDisabled }]" />
    </template>
  • #12564 78c1dd5 Thanks @dyc3! - Added the nursery rule noVueRefObjectReactivityLoss, which reports reads of a Vue ref's value that run only once, in the same function that creates the ref. Such a read copies the current value, and the copy doesn't update when the ref changes.

    import { ref } from "vue";
    
    const count = ref(0);
    const doubled = count.value * 2;
  • #12517 5044c56 Thanks @dyc3! - Added the nursery rule noVueRestrictedCallAfterAwait, which reports calls to configured functions that come after an await in a Vue component's setup() function.

    For example, with { "functions": [{ "module": "vue-i18n", "path": "useI18n" }] }, the following call is reported:

    <script>
    import { useI18n } from "vue-i18n";
    
    export default {
      async setup() {
        await fetchUser();
        const { t } = useI18n();
        return { t };
      },
    };
    </script>
  • #12558 e898da4 Thanks @dyc3! - Added the nursery rule noVueRestrictedVOn, which reports v-on event listeners that are disallowed through the listeners option. An entry can match an event name, a set of modifiers, and an element. For example, with { "listeners": [{ "event": "click", "element": "MyButton" }] }, <MyButton @click="onClick" /> is now reported.

  • #12573 65c6b0b Thanks @dyc3! - Added the new nursery rule noVueTemplateKey, which disallows the key attribute on <template> elements in Vue files. A key on a <template> that also uses v-for is still allowed.

    <template>
      <template :key="item.id"><div /></template>
    </template>
  • #12629 2a34da1 Thanks @dyc3! - Added the new nursery rule noVueTemplateShadow, which disallows v-for and v-slot variables that hide a variable with the same name from an outer scope of a Vue template.

    <template>
      <div v-for="item in groups">
        <span v-for="item in item.children">{{ item }}</span>
      </div>
    </template>
  • #12610 40de561 Thanks @dyc3! - Added the new nursery rule noVueTextareaMustache, which disallows {{ }} text interpolation inside a Vue <textarea>. Vue doesn't support it there; use v-model instead.

    <template>
      <textarea>{{ message }}</textarea>
    </template>
  • #12665 7742209 Thanks @dyc3! - Added the new nursery rule noVueThisInBeforeRouteEnter, which reports this in the beforeRouteEnter navigation guard of a Vue component. Vue Router calls this guard before it creates the component, so this is undefined there.

    <script>
    export default {
      beforeRouteEnter(to, from, next) {
        this.loadUser(to.params.id); // reported
        next();
      },
    };
    </script>
  • #12620 70d7173 Thanks @dyc3! - Added the nursery rule noVueThisInTemplate, which reports this in Vue templates. Templates can read the properties of the component directly, so this.text can be written as text:

    <template>
      <p>{{ this.text }}</p>
    </template>
  • #12601 1d4ed92 Thanks @dyc3! - Added the new nursery rule noVueUndeclaredEmits, which reports events that a Vue component emits without declaring them in the emits option or in defineEmits().

    <script setup>
    const emit = defineEmits(["change"]);
    
    emit("close"); // reported: "close" is not declared
    </script>
  • #12583 4e870a8 Thanks @dyc3! - Added the nursery rule noVueUndeclaredProperties, which reports names that a Vue component uses but doesn't declare, in its template, in this.name, and in props.name.

    <script setup>
    const count = 0;
    </script>
    
    <template>
      <!-- `cnt` isn't declared -->
      <p>{{ cnt }}</p>
    </template>
  • #12657 b45fe79 Thanks @dyc3! - Added the new nursery rule noVueUndeclaredSlots, which reports <slot> elements in Vue components written in TypeScript when the slot isn't declared with defineSlots() or with the slots option.

    <script setup lang="ts">
    defineSlots<{
      default(props: { msg: string }): any;
    }>();
    </script>
    
    <template>
      <slot name="footer" /> <!-- reported -->
    </template>
  • #12789 041c800 Thanks @dyc3! - Added the new nursery rule noVueUselessTemplateAttributes, which reports attributes and directives that have no effect on a <template> element with v-if, v-else-if, v-else, v-for, or v-slot in Vue files. Vue renders only the content of such an element, so it ignores the other attributes.

    <template>
      <template v-if="visible" class="heading">Title</template>
    </template>
  • #12592 36531cc Thanks @dyc3! - Added the nursery rule noVueUselessVBind, which reports v-bind directives whose value is a fixed string. A plain attribute does the same thing.

    <template>
      <div :id="'foo'" /> <!-- reported, use id="foo" instead -->
    </template>
  • #12522 59838bb Thanks @dyc3! - Added the nursery rule noVueVForTemplateKeyOnChild, which reports a key placed on a child element of a <template v-for> instead of on the <template> tag.

    <template>
      <template v-for="todo in todos">
        <TodoItem :key="todo.id" />
      </template>
    </template>
  • #12516 2d9e57e Thanks @dyc3! - Added the nursery rule useAccessorPairs. The rule reports setters that have no matching getter in object literals, classes, and property descriptors.

    const user = {
        set name(value) {
            this._name = value;
        },
    };
  • #12756 1c6e3ef Thanks @dyc3! - Added the new nursery rule useObjectFromEntries, which reports code that builds an object from a list of key-value pairs with reduce(), a for...of loop, or _.fromPairs() instead of Object.fromEntries(). The functions option adds other helper functions to report.

    const object = pairs.reduce((object, [key, value]) => ({ ...object, [key]: value }), {});
  • #12778 5432756 Thanks @dyc3! - Added the new nursery rule useSetSize, which reports code that copies a Set into an array only to read the array's length, and suggests reading the size property of the Set instead.

    const uniqueCount = [...new Set(userIds)].length;
  • #12302 b0d3390 Thanks @dyc3! - Added the nursery rule useSvelteStoreInitialValue, which requires writable(), readable(), and derived() stores from svelte/store to be created with an initial value.

    import { writable } from "svelte/store";
    
    export const count = writable();
  • #12290 c973fed Thanks @dyc3! - Added the nursery rule useTailwindVariablesShorthand for JavaScript and HTML. It reports Tailwind CSS classes that read a CSS variable with [var()], and fixes them to the shorthand that Tailwind CSS v4 added.

    <div className="bg-[var(--brand)]" />; // use `bg-(--brand)`
  • #12518 e9d9616 Thanks @dyc3! - Added the nursery rule useTanstackQueryStableQueryClient, which reports a TanStack Query QueryClient created inside a React component or custom hook. Such a client is created again on every render, and its cache starts empty each time.

    import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
    
    function App() {
        const queryClient = new QueryClient();
        return <QueryClientProvider client={queryClient}><Home /></QueryClientProvider>;
    }
  • #12650 0ddd08f Thanks @dyc3! - Added the nursery rule useVueBlockOrder, which enforces the order of the top-level blocks in Vue components. By default, <script> and <template> blocks come first, in any order, followed by <style> blocks. The order can be changed with the order option.

    <style></style>
    <script></script>
  • #12715 7863f32 Thanks @dyc3! - Added the nursery rule useVueBooleanPropTypeFirst, which requires Boolean to come first in the list of types of a Vue prop. When String comes before Boolean, a prop written in a template without a value is set to an empty string instead of true.

    <script setup>
    defineProps({
      disabled: [String, Boolean],
    });
    </script>
  • #12563 91ac4cb Thanks @dyc3! - Added the nursery rule useVueComputedPropertyReturn, which requires the getters of Vue computed properties to return a value on every path.

    <script setup>
    import { computed, ref } from "vue";
    
    const count = ref(0);
    const double = computed(() => {
      count.value * 2; // reported: the getter never returns a value
    });
    </script>
  • #12716 ae535ea Thanks @dyc3! - Added the new nursery rule useVueConsistentBooleanPropStyle, which enforces a consistent style for Vue component props set to true. By default, it requires the shorthand form; the style option can require the longhand form instead.

    <template>
      <MyComponent :disabled="true" />
    </template>
  • #12675 2a16d59 Thanks @dyc3! - Added the new nursery rule useVueConsistentDefineEmitsDeclaration, which enforces one declaration style for defineEmits in <script setup lang="ts">. By default, events must be declared with a type. The style option can instead require each event to be a property of that type, such as change: [id: number], or require an argument, such as defineEmits(["change"]).

    <script setup lang="ts">
    const emit = defineEmits(["change", "update"]);
    </script>
  • #12612 ab53e4f Thanks @dyc3! - Added the nursery rule useVueConsistentPropNameCasing, which requires prop names in Vue components to use one casing style. By default, prop names must be in camelCase. The casing option switches the rule to snake_case.

    <script setup>
    defineProps({
      greeting_text: String,
    });
    </script>
  • #12608 0928a75 Thanks @dyc3! - Added the nursery rule useVueConsistentVForDelimiter, which requires the same word, in or of, between the item and the list in every Vue v-for directive. The default is in, and the delimiter option switches it to of.

    <!-- reported by default -->
    <div v-for="item of items"></div>
  • #12611 d2df495 Thanks @dyc3! - Added the nursery rule useVueConsistentVSlotStyle, which enforces one style for Vue slots: #name, v-slot:name, or v-slot for the default slot. By default, it expects v-slot on a component and # on <template> elements.

    <template>
      <MyComponent>
        <template v-slot:header>Title</template>
      </MyComponent>
    </template>
  • #12780 69467e0 Thanks @dyc3! - Added the nursery rule useVueDefaultExport, which reports a <script> block of a Vue component that has no default export, when the file has no <script setup> block.

    <script>
    const foo = "foo";
    </script>
  • #12655 8a576b4 Thanks @dyc3! - Added the nursery rule useVueDefaultProp, which reports optional props of Vue components that have no default value. Props that only accept Boolean are not reported.

    For example, the following component doesn't say what size is when a parent component leaves it out:

    <script setup>
    defineProps({
      size: Number,
    });
    </script>
  • #12676 530000a Thanks @dyc3! - Added the nursery rule useVueEmitValidator, which requires a validator function for each event declared in the emits option or in defineEmits().

    <script setup>
    // Reported: the event "change" has no validator function.
    defineEmits(["change"]);
    </script>
  • #12605 093c7ca Thanks @dyc3! - Added the new nursery rule useVueEmitsValidatorReturn, which reports Vue event validators that never return a true value. Vue prints a warning in development mode each time such an event is emitted.

    <script setup>
    defineEmits({
      submit(payload) {
        payload.email.includes("@");
      },
    });
    </script>
  • #12668 1690307 Thanks @dyc3! - Added the new nursery rule useVueMacroVariableName, which requires specific variable names for the results of defineProps(), defineEmits(), defineSlots(), useSlots() and useAttrs() in Vue <script setup> blocks. The names can be changed with the rule's options.

    <script setup>
    const propsDefined = defineProps({ msg: String }); // reported, should be `props`
    </script>
  • #12773 8f28e3f Thanks @dyc3! - Added the nursery rule useVueOneComponentPerFile, which reports files that define more than one Vue component. The rule counts <script setup> blocks, export default { ... } in .vue files, and defineComponent() and createApp() calls that define a component in place with an options object or a setup function. It doesn't report the main component of a .vue file.

    <script setup>
    import { defineComponent, h } from "vue";
    
    const Badge = defineComponent({
      render: () => h("span", "New"),
    });
    </script>
  • #12571 a357b2f Thanks @dyc3! - Added the new nursery rule useVuePropTypeConstructor, which reports Vue prop types that aren't constructors, such as a type name written as a string.

    <script>
    export default {
      props: {
        size: 'Number', // reported, use `Number` instead
      },
    };
    </script>
  • #12566 e69572b Thanks @dyc3! - Added the nursery rule useVueRenderReturn, which requires the render function of a Vue component to return a value on every path.

    The following example is invalid because the render function returns nothing when this.visible is false:

    <script>
    import { h } from "vue";
    
    export default {
      render() {
        if (this.visible) {
          return h("div", "hello");
        }
      },
    };
    </script>
  • #12619 3703a36 Thanks @dyc3! - Added the nursery rule useVueSeparateStaticClass, which reports class names in a Vue :class binding that always apply, such as header in <div :class="['header', theme]">. These classes belong in the plain class attribute.

  • #12677 f6b7f15 Thanks @dyc3! - Added the nursery rule useVueSingleEventPayload, which reports Vue component events that are emitted or declared with more than one value. A listener written inline in a template, such as @change="onChange($event)", only receives the first value.

    <script setup>
    const emit = defineEmits(["change"]);
    emit("change", value, extra);
    </script>
  • #12646 3d92356 Thanks @dyc3! - Added the new nursery rule useVueSlotNameCasing, which enforces a consistent casing for the names of <slot> elements in Vue templates. Slot names must be in camelCase by default. The casing option can require kebab-case or a single lowercase word instead.

    <template>
      <slot name="foo-bar" />
    </template>
  • #12572 cb16268 Thanks @dyc3! - Added the nursery rule useVueSlotsAsFunctions, which reports slots in this.$slots that are used as their content instead of being called. In Vue 3, each slot is a function that returns its content.

    export default {
      render() {
        return this.$slots.default.filter(isVisible); // reported
      },
    };
  • #12659 e7691f7 Thanks @Object,! - Added the new nursery rule useVueTypedObjectProps, which reports Vue props declared with Object or Array without a TypeScript type in TypeScript files and Vue files with <script lang="ts">.

    <script setup lang="ts">
    defineProps({
     // reported
      items: Array as PropType<string[]>,
    });
    </script>
  • #12574 bb8ca38 Thanks @dyc3! - Added the nursery rule useVueValidAttributeName, which reports invalid attribute names in Vue templates, including names bound with v-bind. Attributes on components aren't checked.

    <template>
      <p 0abc :-def="value"></p>
    </template>
  • #12582 f6ac8eb Thanks @dyc3! - Added the nursery rule useVueValidDefaultProp, which requires the default value of a Vue prop to match the type of the prop. Default objects and arrays must also be returned from a function, so that each component instance gets its own copy.

    <script>
    export default {
      props: {
        count: { type: Number, default: "zero" }, // reported
        items: { type: Array, default: [] }, // reported
      },
    };
    </script>
  • #12613 071324d Thanks @dyc3! - Added the nursery rule useVueValidDefineOptions, which reports invalid calls to Vue's defineOptions() macro in <script setup>. It reports a call that is repeated, that has no options or has type arguments, that declares props, emits, expose, or slots, or that uses variables declared in <script setup>.

    <script setup>
    const options = { name: "Foo" };
    defineOptions(options);
    </script>
  • #12557 f1eb303 Thanks @dyc3! - Added the new nursery rule useVueValidNextTick, which reports Vue nextTick calls that don't wait for Vue to update the page. The rule is recommended and part of the Vue domain.

    import { nextTick } from "vue";
    
    nextTick(); // reported: the Promise is ignored
    nextTick.then(callback); // reported: `nextTick` isn't called
  • #12674 361c9f2 Thanks @dyc3! - Fixed #12672: Astro and Svelte formatting now preserves comments and whitespace inside preformatted elements such as <pre> and <textarea>.

    -<pre><code>Hello</code></pre>
    +<pre>
    +  <!-- hello -->
    +  <code>Hello</code>
    +</pre>
  • #12746 2ebd7b6 Thanks @ematipico! - Improved #2730: Biome now reports the active analyzer rule and source range when a rule panics, and suggests disabling the rule as a workaround.

  • #12758 1df6d85 Thanks @dyc3! - Fixed #12739, #12741, and #12742: the Markdown formatter now adds a blank line between a top-level paragraph and a header, fenced code block, list, or blockquote that directly follows it, matching Prettier.

     Some text:
    +
     - bullet 1
     - bullet 2
  • #12806 03261de Thanks @Jayllyz! - Added the nursery rule useTanstackQueryInfiniteQueryPropertyOrder, which enforces the order queryFn, getPreviousPageParam, getNextPageParam in the options of TanStack Query infinite queries. TanStack Query infers types from this order.

    import { useInfiniteQuery } from "@tanstack/react-query";
    
    useInfiniteQuery({
      getNextPageParam: (lastPage) => lastPage.nextId,
      queryFn: ({ pageParam }) => fetchProjects(pageParam),
    });
  • #12762 69187a9 Thanks @dyc3! - Fixed #12738: the Markdown formatter now collapses consecutive blank lines between blocks into a single blank line.

     Some paragraph.
    
    -
    -
     ## Next section
  • #12708 e87ec37 Thanks @nhedger! - Fixed .editorconfig section globs that skipped the character following a bracket expression. For example, [{[ab],c}.json] now matches a.json, b.json, and c.json.

  • #11623 37440f9 Thanks @Bsibz! - Fixed #11548: The typeMember selector of useNamingConvention no longer applies to TypeScript type parameters.

  • #12106 ff1d8b8 Thanks @dyc3! - Added the nursery rule noExcessiveNestedBlocks, which reports blocks nested deeper than the configured maximum (4 by default). It checks if, switch, try, and loop statements in JavaScript, and nested rules and at-rules in CSS.

  • #12747 397b0eb Thanks @ematipico! - Fixed #8094: Biome's language server now skips unchanged dynamic capability registrations, preventing duplicate watched-file notifications in affected editors.

  • #12708 e87ec37 Thanks @nhedger! - Fixed #12683: .editorconfig section globs with nested braces, such as [{*.{js,json},biome.jsonc}], are now supported instead of being ignored.

  • #12910 6f8313d Thanks @dyc3! - Fixed a slowdown in biome lint, biome check and biome format that grew with the number of files: looking up an open file took longer after every file Biome had already processed. Large projects are processed faster again.

  • #12787 53c3a49 Thanks @dyc3! - Fixed the GritQL formatter treating a single line break between list items as a blank line. Formatting a broken list no longer adds blank lines between its items, and blank lines from the source are still kept.

      $x <: [
    -   `1`,
    -
    -   `2`,
    +   `1`, `2`,
    
        `3`
      ]
  • #12864 c2c2590 Thanks @nhedger! - Fixed #12862: Biome now applies the options under the top-level grit configuration key. Previously, options such as grit.formatter.lineWidth and grit.formatter.enabled were ignored, and Grit files were formatted with the global formatter settings.

  • #12543 0ec0a72 Thanks @dyc3! - Fixed noVueUndeclaredDirectives not reporting undeclared custom directives in components that export their options with export { options as default }.

    <script>
    const options = {};
    export { options as default };
    </script>
    
    <template>
      <div v-highlight></div>
    </template>
  • #12745 86be8b8 Thanks @vidigoat! - Fixed the formatter removing the parentheses that end an optional chain when a non-null assertion, type arguments or more parentheses follow them. The output either short-circuited the rest of the chain, as in a?.b!.c for (a?.b)!.c, or didn't parse, as with new a?.b!(), a template tag or an assignment target.

    - a?.b!.c;
    + (a?.b)!.c;
    - new a?.b!();
    + new (a?.b)!();
    - a?.b`template`;
    + (a?.b)`template`;
  • #12821 44626ba Thanks @Suto-Michimasa! - Fixed #12820: usePlaywrightValidDescribeCallback no longer reports an anonymous test.describe(callback) as a missing callback.

    test.describe(() => {
      test.use({ colorScheme: "dark" });
    });
  • #12819 b620cbc Thanks @Suto-Michimasa! - Fixed #12766: usePlaywrightValidDescribeCallback no longer reports test.describe(title, details, callback). The rule now validates the last argument as the callback, as the original ESLint rule does.

    test.describe("suite", { tag: "@smoke" }, () => {});
  • #12898 291f034 Thanks @dyc3! - Fixed #12882: the Tailwind class parser no longer reports a parse error for unknown utilities with a dashed name and an arbitrary value or a CSS variable, such as foo-bar-[1px] or foo-bar-(--my-var). useTailwindSortedClasses sorts these classes first, like other unknown classes.

  • #12639 bd19436 Thanks @dyc3! - Fixed #12623: the safe fix of useConsistentTestIt no longer leaves an unused import when applied to every call in a file. When all calls to an imported test function are renamed, the import is now replaced with an alias, such as test as it, instead of keeping the original specifier. When the original specifier is kept, the alias is now added as test, test as it instead of test , test as it.

  • #12870 378798f Thanks @dyc3! - Improved the performance of grit plugins that use regexes.

  • #12769 6d23980 Thanks @ematipico! - Fixed #12757: the Markdown formatter no longer turns an indented paragraph line that starts with -, 1., #, or > into a list, heading, or blockquote. Such a line now joins the previous line, matching Prettier.

    -- Item
    -      - Nested item
    +- Item - Nested item
       continuation line
  • #12737 162ed76 Thanks @xgbtxy! - Fixed #12726: useMathMinMax now recognizes directly listed nonnumeric elements in array reductions, such as ["foo", "bar"].reduce((a, b) => a > b ? a : b). This also covers Date values and local constant arrays used only by reductions, including parentheses and TypeScript assertions. Spread elements and other unclassified inputs retain their existing behavior.

  • #12782 44d6768 Thanks @dyc3! - Added the new nursery rule noInvalidRemoveEventListener, which reports calls to removeEventListener() that pass an inline function or the result of .bind(). These create a new function, so the listener that was added is never removed.

    window.removeEventListener("click", listener.bind(window));
  • #12858 b312e95 Thanks @dyc3! - Fixed #12851: a plugin that throws or fails to run now reports an error diagnostic instead of an info diagnostic, so biome lint and biome check exit with a non-zero code.

  • #12813 a55d360 Thanks @dyc3! - Improved the performance of JavaScript plugins that read node.kind or token.kind.

  • #12913 4ada6fc Thanks @dyc3! - Fixed #12909: Biome no longer crashes with an access violation when formatting, linting or checking files on Windows ARM64.

  • #12443 cccbc03 Thanks @dyc3! - Fixed the code fixes of noMisusedPromises, noFloatingPromises, and noVueDataObjectDeclaration duplicating comments attached to the wrapped expression. For example, the noFloatingPromises fix for an array of promises preceded by a comment no longer copies that comment into Promise.all(...).

  • #12769 6d23980 Thanks @ematipico! - Fixed #12768: the Markdown formatter no longer splits a blockquote in two when an empty > line separates its list items.

     > - one
     > - two
    -
    +>
     > - three
  • #12769 6d23980 Thanks @ematipico! - Fixed #12767: the Markdown formatter no longer moves a list item out of a blockquote when the item follows a nested list item. The formatter also keeps the > of a line that directly follows a list inside a blockquote and starts a nested blockquote, a heading, or a different list.

     > - one
     >   - nested
    -  - two
    +> - two
  • #12769 6d23980 Thanks @ematipico! - Fixed #12703: the Markdown formatter no longer indents the empty > line between a list and a paragraph in a blockquote. Formatting again no longer moves the paragraph out of the quote.

     > - item one
     >   continued.
    -  >
    +>
     > Paragraph line one
     > line two.
  • #12465 5127af1 Thanks @Th3S4mur41! - Expanded useLogicalProperties to report multi-value physical shorthands and logical longhand pairs that can be combined. Dynamic shorthands such as padding: var(--spacing) 2px are also reported without an automatic fix because the variable may supply multiple values.


  • #12860 31f1820 Thanks @vibbix! - Fixed the SCSS formatter joining comma-separated multi-value declarations onto one line. SCSS now prints them one value per line, as the CSS formatter and Prettier do.

     .a {
    -	transition: opacity 1s, color 2s;
    +	transition:
    +		opacity 1s,
    +		color 2s;
     }
  • #12868 ac70a85 Thanks @dyc3! - Added node.descendants(kinds) and node.walk(kinds, enter, exit) to JavaScript plugins. They find the nodes inside a node whose kind is in a set created with nodeKinds(), and are much faster than visiting every node with node.children().

    const CALLS = nodeKinds("JS_CALL_EXPRESSION");
    
    for (const call of root.descendants(CALLS)) {
      registerDiagnostic(call, "information", "Found a call.");
    }
  • #12786 126c172 Thanks @dyc3! - Added the allowBlackAndWhite option to noTailwindRawColors. It defaults to true. When set to false, the rule also reports classes that use black or white, such as bg-white and text-black/50, and suggests similar colors from your theme when tailwind.stylesheet is set.

    { "options": { "allowBlackAndWhite": false } }
  • #12754 a00eb5a Thanks @dyc3! - Fixed #12724: when proseWrap is "always" or "never", the Markdown formatter now wraps the text inside emphasis, strong emphasis, and strikethrough like the surrounding prose, instead of keeping their source line breaks and forcing line breaks around them. Text inside block quotes keeps its current formatting. With a lineWidth of 50:

    - Some words before the strong text,
    - **stop and tell
    - them**
    - after the strong text.
    + Some words before the strong text, **stop and tell
    + them** after the strong text.
  • #12708 e87ec37 Thanks @nhedger! - Fixed .editorconfig section globs with unbalanced braces. As in the EditorConfig reference implementation, all braces in such a glob are now matched literally, so [{a,b}}.json] only matches a file named {a,b}}.json.

What's Changed

  • feat(lint): add useVueConsistentDefineEmitsDeclaration by @dyc3 in #12675
  • feat(lint): add tests for logical shorthands and longhands by @Th3S4mur41 in #12465
  • refactor: use our parser for rule docs by @ematipico in #12744
  • feat(deserialize): yaml by @ematipico in #12064
  • feat(analyzer): panic handler by @ematipico in #12746
  • fix(deps): bump libz-sys to 1.1.31 (RUSTSEC-2026-0418) by @nhedger in #12750
  • fix(lint): skip nonnumeric reductions in useMathMinMax by @xgbtxy in #12737
  • fix(format/md): fix various missing empty lines bugs by @dyc3 in #12758
  • fix(format/js): keep the parens that end an optional chain before !, type arguments or more parens by @vidigoat in #12745
  • fix(lsp): dynamic capability registration by @ematipico in #12747
  • fix(editorconfig): support nested brace alternates in section globs by @nhedger in #12708
  • fix(format/md): collapse consecutive blank lines between blocks by @dyc3 in #12762
  • fix(md/fmt): quote blocks and lists by @ematipico in #12769
  • chore: fix formatting in some of our readmes by @dyc3 in #12774
  • feat(lint): add useVueValidNextTick by @dyc3 in #12557
  • feat(lint): add noPseudoElementInFunctionalPseudoClass by @vibbix in #12388
  • feat(lint): add noMissingScssInterpolation by @vibbix in #12342
  • chore: add oxlint rule source by @dyc3 in #12784
  • feat(lint): add useTailwindVariablesShorthand by @dyc3 in #12290
  • feat(lint): add noVueVForTemplateKeyOnChild by @dyc3 in #12522
  • feat(lint): add noVueLoneTemplate by @dyc3 in #12666
  • feat(lint): add noVueDeprecatedSlotScope by @dyc3 in #12634
  • feat(lint): add useVueRenderReturn by @dyc3 in #12566
  • fix(js/useNamingconvention): prevent typeMember from matching type parameters by @Bsibz in #11623
  • feat(rules_check): build vue semantic models and use them by @dyc3 in #12535
  • feat(lint): add useVueValidDefineOptions by @dyc3 in #12613
  • feat(lint): add useVueSlotNameCasing by @dyc3 in #12646
  • feat(lint): add noVueMixin by @dyc3 in #12533
  • feat(lint): add noVueUndeclaredEmits by @dyc3 in #12601
  • feat(lint): add noVueDeprecatedPropsDefaultThis by @dyc3 in #12604
  • feat(lint): add noVueRestrictedCallAfterAwait by @dyc3 in #12517
  • feat(lint): add noVueDeprecatedModelDefinition by @dyc3 in #12617
  • refactor(noVueUndeclaredDirectives): use vue semantic model by @dyc3 in #12543
  • feat(lint): add noVueDeprecatedConfigKeyCodes by @dyc3 in #12616
  • perf(plugins/js): strings emitted by the .kind property are now static by @dyc3 in #12813
  • chore: correct wording in changelog by @dyc3 in #12839
  • feat(lint): add useAccessorPairs by @dyc3 in #12516
  • feat(lint): add noDynamicDelete by @dyc3 in #12547
  • feat(lint): add noUselessTypeAssertion by @dyc3 in #12488
  • feat(lint): add noTanstackQueryVoidQueryFn by @dyc3 in #12515
  • feat(lint): add useTanstackQueryStableQueryClient by @dyc3 in #12518
  • feat(lint): add noVueRefObjectReactivityLoss by @dyc3 in #12564
  • feat(lint): add useVueComputedPropertyReturn by @dyc3 in #12563
  • feat(lint): add noVueRestrictedVOn by @dyc3 in #12558
  • feat(lint): add noVueDeprecatedInlineTemplate by @dyc3 in #12553
  • feat(lint): add noVueDeprecatedHtmlElementIs by @dyc3 in #12552
  • feat(lint): add noVueDeprecatedDestroyedLifecycle by @dyc3 in #12568
  • feat(lint): add useVuePropTypeConstructor by @dyc3 in #12571
  • chore: fix changeset attribution by @dyc3 in #12816
  • feat(lint): add noVueMultipleObjectsInClass by @dyc3 in #12658
  • feat(lint): add noVueThisInBeforeRouteEnter by @dyc3 in #12665
  • feat(lint): add noVueUndeclaredSlots by @dyc3 in #12657
  • feat(lint): add useVueDefaultProp by @dyc3 in #12655
  • feat(lint/js): add useTanstackQueryInfiniteQueryPropertyOrder by @Jayllyz in #12806
  • fix(lint): accept anonymous describe in usePlaywrightValidDescribeCallback by @Suto-Michimasa in #12821
  • fix(format/html): preserve comments in <pre> in astro and svelte files by @dyc3 in #12674
  • fix(useConsistentTestIt): don't leave an unused import after the safe fix by @dyc3 in #12639
  • feat(noTailwindRawColors): add allowBlackAndWhite option by @dyc3 in #12786
  • chore: update rule metadata by @dyc3 in #12847
  • feat(lint): add useSetSize by @dyc3 in #12778
  • fix(lint): keep comments once when code fixes wrap a node by @dyc3 in #12443
  • feat(lint): add noVueDeprecatedVBindSync by @dyc3 in #12589
  • feat(lint): add noVueDeprecatedVOnNativeModifier by @dyc3 in #12609
  • feat(lint): add noVueDeprecatedFunctionalTemplate by @dyc3 in #12590
  • feat(lint): add noVueUselessVBind by @dyc3 in #12592
  • feat(lint): add noVueTemplateKey by @dyc3 in #12573
  • feat(lint): add noVueDeprecatedEventsApi by @dyc3 in #12654
  • feat(lint): add noVueExcessiveProps by @dyc3 in #12667
  • feat(lint): add useVueTypedObjectProps by @dyc3 in #12659
  • feat(lint): add noVueDeprecatedSlotAttribute by @dyc3 in #12633
  • feat(lint): add useVueValidAttributeName by @dyc3 in #12574
  • feat(lint): add useVueBlockOrder by @dyc3 in #12650
  • feat(lint): add noVueChildContent by @dyc3 in #12632
  • feat(lint): add useVueValidDefaultProp by @dyc3 in #12582
  • feat(lint): add noVueUndeclaredProperties by @dyc3 in #12583
  • feat(lint): add noVueTemplateShadow by @dyc3 in #12629
  • feat(lint): add useVueEmitsValidatorReturn by @dyc3 in #12605
  • feat(lint): add noVueThisInTemplate by @dyc3 in #12620
  • feat(lint): add useVueConsistentVForDelimiter by @dyc3 in #12608
  • feat(lint): add useVueSlotsAsFunctions by @dyc3 in #12572
  • feat(lint): add useVueEmitValidator by @dyc3 in #12676
  • feat(lint): add useVueSingleEventPayload by @dyc3 in #12677
  • feat(lint): add useVueBooleanPropTypeFirst by @dyc3 in #12715
  • refactor(cli): read environment variables through an injectable source by @ematipico in #12427
  • feat(plugins/js): add tokenKinds and nodeKinds APIs by @dyc3 in #12812
  • fix(grit/fmt): don't treat a single line break in lists as a blank line by @dyc3 in #12787
  • fix(plugins/js): report plugin failures as errors by @dyc3 in #12858
  • fix(markdown_formatter): wrap emphasis content with surrounding prose by @dyc3 in #12754
  • fix(lint): accept details argument in usePlaywrightValidDescribeCallback by @Suto-Michimasa in #12819
  • fix(lint): multi-value declarations for SCSS don't match prettier by @vibbix in #12860
  • feat(lint): add useVueConsistentPropNameCasing by @dyc3 in #12612
  • feat(lint): add useVueConsistentVSlotStyle by @dyc3 in #12611
  • feat(lint): add useVueSeparateStaticClass by @dyc3 in #12619
  • feat(lint): add useVueMacroVariableName by @dyc3 in #12668
  • feat(lint): add noUnnecessaryStringTrim by @dyc3 in #12482
  • feat(lint): add useVueTrueAttributeShorthand by @dyc3 in #12716
  • feat(lint): add noUselessLengthCheck by @dyc3 in #12783
  • feat(lint): add useVueDefaultExport by @dyc3 in #12780
  • feat(lint): add noVueTextareaMustache by @dyc3 in #12610
  • feat(lint): add useObjectFromEntries by @dyc3 in #12756
  • feat(lint): add noArrayForEach by @dyc3 in #12755
  • feat(lint): add noSyncMethods by @dyc3 in #12764
  • feat(lint): add noSinglePromiseInPromiseMethods by @dyc3 in #12779
  • feat(lint): add noAwaitInPromiseMethods by @dyc3 in #12777
  • feat(lint): add noInvalidRemoveEventListener by @dyc3 in #12782
  • feat(lint): add noChainedComparison by @dyc3 in #12765
  • feat(lint): add noLateEventControl by @dyc3 in #12481
  • feat(lint/js): add noExcessiveNestedBlocks by @dyc3 in #12106
  • feat(lint): add noMissingThrow by @dyc3 in #12792
  • feat(lint): add noPlaywrightUnsafeReferences by @dyc3 in #12450
  • feat(lint): add noUselessAwait by @dyc3 in #12772
  • feat(lint): add noObjectLiteralComparison by @dyc3 in #12790
  • feat(lint): add useSvelteStoreInitialValue by @dyc3 in #12302
  • feat(lint): add noMapSpread by @dyc3 in #12795
  • feat(lint): add noMismatchedMapKey by @dyc3 in #12793
  • feat(lint): add noVueUselessTemplateAttributes by @dyc3 in #12789
  • feat(lint): add useVueOneComponentPerFile by @dyc3 in #12773
  • feat(lint): add noSvelteBindValueOnCheckableInputs by @dyc3 in #12241
  • chore: update rule metadata by @dyc3 in #12875
  • fix(service): apply the top-level grit configuration by @nhedger in #12864
  • perf(grit): bump grit-pattern-matcher and grit-util to 0.5.2 by @dyc3 in #12870
  • feat(plugins/js): add optimized traversal APIs by @dyc3 in #12868
  • fix(parse/tailwind): handle long dashed base names when aribtrary values are involved by @dyc3 in #12898
  • perf(analyze): make a disabled rule timer free by @dyc3 in #12911
  • chore(deps): pin mimalloc again, add the bad versions to cargo deny by @dyc3 in #12913
  • feat(plugins/js): add union to node and token kind sets by @dyc3 in #12914
  • perf(service): finish resizes of the file view maps in the writer that starts them by @dyc3 in #12910
  • chore: increase size of release builders by @dyc3 in #12919
  • ci: release by @github-actions[bot] in #12918

New Contributors

Full Changelog: https://github.com/biomejs/biome/compare/@biomejs/biome@2.6.4...@biomejs/biome@2.6.5

Don't miss a new biome release

NewReleases is sending notifications on new releases.