Skip to content

All versions since 2.6.3

2.6.3

Patch Changes

  • #12275 807e616 Thanks @dyc3! - Added the new nursery rule noArraySortForMinMax, which reports sorting an array only to read its smallest or largest value. Use Math.min() or Math.max() instead.

    const minimum = array.toSorted((a, b) => a - b)[0];
  • #12432 cf61682 Thanks @dyc3! - Added the nursery rule noBooleanSortComparator, which reports sort comparators that return a boolean instead of a number. For example, array.sort((a, b) => a > b) never puts the first item before the second, so the array isn’t sorted correctly.

  • #12304 b4654c5 Thanks @dyc3! - Added the new nursery rule noEagerArrayMethodsInLoops, which reports .map() and .filter() calls in the header of for...of loops. These calls build a new array that is only used by the loop.

    for (const name of users.map((user) => user.name)) {
    console.log(name);
    }
  • #12121 66c3791 Thanks @dyc3! - Added the nursery rule noNewRequire, which disallows calling require with new, such as new require("app-header").

  • #12316 34b520d Thanks @dyc3! - Added the new nursery rule noObsoleteAttributes, which disallows obsolete attributes on HTML elements and suggests what to use instead.

    <table bgcolor="#ffffff" cellpadding="5"></table>
  • #12258 cce2385 Thanks @dyc3! - Added the nursery rule noPathConcat, which disallows building file paths and URLs by joining strings to __dirname, __filename, import.meta.dirname, import.meta.filename, or import.meta.url.

    const fullPath = __dirname + "/foo.js"; // reported
  • #12287 e12ad78 Thanks @dyc3! - Added the new nursery rule noPlaywrightNthMethods, which disallows selecting Playwright elements by position with first(), last(), and nth(). A test that relies on the position of an element can act on a different element when the page changes.

    await page.locator("button").first().click();
  • #12343 62ad123 Thanks @vibbix! - Added the nursery rule noSelfNestedLayer, which disallows nesting a cascade layer inside a layer with the same name. Layer names inside an @layer block are relative to it, so the inner layer below creates the sublayer components.components instead of adding to components.

    @layer components {
    @layer components {
    .button {
    color: red;
    }
    }
    }
  • #12289 bbbd95d Thanks @dyc3! - Added the nursery rule noShortTimeValues, which reports CSS animation and transition times that are shorter than the configured minimum number of milliseconds. The rule does nothing until minimum is set.

    For example, the following code is invalid when minimum is 100:

    a {
    transition-duration: 80ms;
    }
  • #12431 f748ec0 Thanks @dyc3! - Added the nursery rule noSvelteInternal, which disallows importing from svelte/internal and its submodules. These modules are private to Svelte and can change or disappear in any release.

    import { get_current_component } from "svelte/internal";
  • #12270 8ae35c4 Thanks @dyc3! - Added the nursery rule noTanstackQueryRestDestructuring, which disallows rest destructuring and object spread on TanStack Query results. Both read every property of the result, so the component updates on every change to the query.

    import { useQuery } from "@tanstack/react-query";
    const { data, ...rest } = useQuery({ queryKey: ["todos"], queryFn: fetchTodos });

    The rule belongs to the new tanstackQuery domain.

  • #12308 372af2a Thanks @dyc3! - Added the new nursery rule noUnreadableForOfExpression, which reports for...of and for await...of loops that go through the result of a complex expression instead of a variable, a property, or a short call.

    for (const item of getItems(createArgument(seed))) {} // reported
  • #12422 0be8d10 Thanks @dyc3! - Added the new nursery rule noUnsafeReturn, which disallows returning a value typed as any from a function.

    function parse(text: string) {
    return JSON.parse(text); // reported
    }
  • #12311 8434c92 Thanks @dyc3! - Added the nursery rule noUselessSplice, which reports splice() calls that have a simpler alternative. For example, array.splice(0, 1) can be written as array.shift().

  • #12293 eaa4a2b Thanks @dyc3! - Added the nursery rule noVueUnusedEmitDeclarations, which reports events that a Vue component declares but never emits.

    For example, the following component never emits close:

    <script setup>
    const emit = defineEmits(["change", "close"]);
    emit("change");
    </script>
  • #12386 f01ebb0 Thanks @dyc3! - Added the nursery rule noVueVTextVHtmlOnComponent, which disallows v-text and v-html on Vue components. These directives replace everything inside the component’s root element instead of filling its slot.

    <template>
    <MyComponent v-html="html"></MyComponent>
    </template>
  • #12385 7bd38b7 Thanks @dyc3! - Added the new nursery rule noVueWatchAfterAwait, which disallows creating watchers after an await in a Vue component’s setup() function. Vue doesn’t stop these watchers when the component is removed. A watcher is allowed when the function it returns is stored, so that function can be called later to stop the watcher.

    <script>
    import { watch } from "vue";
    export default {
    async setup() {
    await fetchUser();
    watch(source, () => {});
    },
    };
    </script>
  • #12286 50d2a4e Thanks @dyc3! - Added the nursery rule noZeroLengthUnit, which disallows units on zero lengths in CSS. Biome can remove the unit.

    a {
    top: 0px;
    }
  • #12300 ab2eb9e Thanks @dyc3! - Added the nursery rule useBlockStatementOverIife, which reports functions that are called immediately when a block statement can replace them. Biome can replace these functions with a block statement.

    Invalid:

    (() => {
    const value = getValue();
    run(value);
    })();
  • #12421 1c2cac0 Thanks @dyc3! - Added the nursery rule useConsistentLightnessNotation, which enforces writing the lightness of lab(), lch(), oklab(), and oklch() colors as a percentage, or as a number with the notation option. For example, with the default options, oklch(0.85 0.17 88) is reported and can be fixed to oklch(85% 0.17 88).

  • #12224 fef7ed4 Thanks @dyc3! - Added the nursery rule useExpectToContain, which reports tests that compare the result of includes() to a boolean, and suggests using toContain() instead.

    expect(fruits.includes("apple")).toBe(true);
  • #12299 0d5025d Thanks @dyc3! - Added the new nursery rule useIteratorZip, which reports for loops that use an index only to read the same position from several arrays. Such loops can use Iterator.zip() instead.

    // reported
    for (let index = 0; index < Math.min(names.length, scores.length); index++) {
    save(names[index], scores[index]);
    }
  • #12298 a234d2f Thanks @dyc3! - Added the nursery rule useMathAbs, which reports manual absolute value calculations and range checks that can use Math.abs(). For example, value < 0 ? -value : value can be written as Math.abs(value), and value > limit || value < -limit can be written as Math.abs(value) > limit.

  • #12499 bd024cc Thanks @dyc3! - Added the nursery rule useMathTrunc, which requires Math.trunc() instead of bitwise operations or parseInt(String(x), 10) for removing the decimal part of a number. For example, const result = value | 0; and const result = ~~value; are now reported.

  • #12314 9e875a4 Thanks @dyc3! - Added the new nursery rule usePackageJsonValidCpu, which reports a cpu field in package.json that isn’t an array of known processor types. The cpu field lists the processor types that the package supports.

    For example, the rule reports the following package.json file because x86 isn’t a processor type that package managers recognize:

    {
    "name": "my-package",
    "cpu": ["x86"]
    }
  • #12315 cb30544 Thanks @dyc3! - Added the nursery rule usePackageJsonValidEngines, which reports an invalid engines field in package.json. The field must be an object, and each of its values must be a non-empty string.

    For example, the following engines field is reported because the version of node is a number:

    {
    "engines": {
    "node": 24
    }
    }
  • #12400 407604d Thanks @dyc3! - Added the nursery rule useVueComponentIs, which requires Vue <component> elements to bind the is attribute with :is or v-bind:is. Without it, Vue has no component to render.

    <template>
    <component :is="currentView" />
    </template>
  • #12337 c371520 Thanks @dyc3! - Added the nursery rule useVueToggleInsideTransition, which requires the element inside a Vue <Transition> to be shown and hidden with v-if or v-show. Without one of them, the element is always shown and the transition never plays.

    <template>
    <Transition>
    <div>Content</div>
    </Transition>
    </template>
  • #12387 64472e9 Thanks @dyc3! - Added the nursery rule useVueTypedRef, which reports ref() and shallowRef() calls in TypeScript that have no type argument and no initial value other than null or undefined. Without a type, TypeScript can’t tell which values these refs are meant to hold.

    import { ref } from "vue";
    const count = ref();
  • #12423 bf1a55a Thanks @dyc3! - Added the nursery rule useVueVOnExact, which requires the .exact modifier on a v-on listener when another listener for the same event on the element needs more modifier keys, such as .ctrl. Without .exact, both listeners run when those keys are held down. The rule accepts the following code:

    <template>
    <button @click.exact="select" @click.ctrl="open"></button>
    </template>
  • #12418 208730e Thanks @latin-1! - Fixed #12417: useSortedProperties could produce invalid CSS when sorting properties without a final semicolon. Comments attached to reordered properties are preserved.

  • #12216 f2a3c71 Thanks @dyc3! - Added the new nursery rule noDanglingUnderscore, which disallows variable names, function names, and property accesses that start or end with an underscore.

    const _count = 0; // reported
    user._id; // reported
  • #12536 438997f Thanks @vidigoat! - Fixed the formatter removing the parentheses around an instantiation expression before +, -, <, >, >=, >> and >>>. TypeScript reads make<T> + y as make < T > +y, and make<T> >> y doesn’t parse.

    x = make<T> + y;
    x = (make<T>) + y;
    x = make<T> >> y;
    x = (make<T>) >> y;
  • #12540 7d3e8a1 Thanks @vidigoat! - Fixed the formatter removing the parentheses around an instantiation expression before a non-null assertion or type arguments of a class heritage, which produced code that doesn’t parse.

    const a = make<T>!;
    const a = (make<T>)!;
    class D extends B<T><T> {}
    class D extends (B<T>)<T> {}
  • #12496 09d89b9 Thanks @vidigoat! - Fixed the formatter removing the parentheses around binary, logical, type-cast and instantiation operands of an instantiation expression. The type arguments then applied to the last operand only, and a nested instantiation expression didn’t parse.

    const x = a + b<T>;
    const x = (a + b)<T>;
    const y = a as B<T>;
    const y = (a as B)<T>;
    const z = f<A><B>;
    const z = (f<A>)<B>;
  • #12526 dbcdab1 Thanks @dyc3! - Fixed #12524: the Markdown formatter no longer removes the blank line between a paragraph and the list that follows it. Removing it could change the document, because an ordered list that doesn’t start at 1 can’t interrupt a paragraph and became part of the paragraph text.

    Steps:
    3. three
    4. four
  • #12509 470018b Thanks @dyc3! - Fixed #12507: the Markdown formatter no longer drops the > markers after an empty quote line when proseWrap is "always" or "never". Previously, the text after the empty line was moved out of the blockquote.

    > a
    >
    b
    > b
  • #12598 5699601 Thanks @vidigoat! - Fixed the formatter removing the parentheses around the callee of a new expression when it contains a dynamic import() call, which produced code that doesn’t parse.

    new import("foo").bar();
    new (import("foo").bar)();
  • #12508 87d9e6b Thanks @dyc3! - Fixed #12502: noInvalidGridAreas now counts the cells in each row of grid-template-areas instead of comparing the length of the row text. Rows such as "a" "bb" are no longer reported, and rows such as "abc" "d e" are now reported.

  • #12530 7f467b2 Thanks @dyc3! - Fixed #12529: noUselessElse no longer reports an else clause when the if block ends with a switch statement that has no default clause. If no case matches, such a switch doesn’t exit, so the else clause is needed.

  • #12511 d4ea663 Thanks @dyc3! - Fixed #12505: useDomNodeTextContent no longer reports innerText on values whose type annotation shows they aren’t DOM nodes. The following code is now valid:

    const Link = ({ innerText }: { innerText: string }) => <a>{innerText}</a>;
  • #12588 e262362 Thanks @ematipico! - Fixed noDescendingSpecificity to compare resolved nested selector targets. Biome no longer reports nested selectors that resolve to different targets, detects equivalent explicit and nested targets, and emits one diagnostic when a parent selector list expands the same nested selector multiple times.

    For example, the following selectors are no longer reported because their final targets are .column and code, respectively:

    .card {
    .column {
    :root[data-theme="dark"] & {}
    }
    code {
    :root[data-theme="dark"] & {}
    }
    }
  • #12534 e59a324 Thanks @Netail! - Improved the diagnostics of noIdenticalTestTitle. Biome now reports one diagnostic per repeated title, pointing at the first occurrence and at every later occurrence, instead of one diagnostic per duplicate.

  • #12528 a3132dc Thanks @ff1451! - Fixed #12503: noUnknownProperty now checks SCSS nested properties by the name Sass emits for them. For example, radius in border: { radius: 4px; } is checked as border-radius and is no longer reported, while color in font: { color: red; } is checked as font-color and is now reported.

  • #12113 ec4eb2d Thanks @dyc3! - Added the nursery rule useConsistentUnicodeBom, which disallows a leading Unicode byte order mark by default and can require one with bom: "always". The rule supports JavaScript, TypeScript, JSON, CSS, GraphQL, HTML, and Markdown, provides a fix, and preserves the unicode-bom option during ESLint migration.

    The following example is invalid by default because it starts with an invisible U+FEFF character:

    const value = 1;
  • #12248 afbc81e Thanks @dyc3! - Added the nursery rule useReactNativeValidPlatformColors, which requires PlatformColor() and DynamicColorIOS() calls to use values written directly in the call, so React Native can optimize them.

    import { PlatformColor } from "react-native";
    const labelColor = "labelColor";
    const color = PlatformColor(labelColor);
  • #12599 b62494a Thanks @dyc3! - Fixed #12532: checking the project root no longer applies files.includes exclusions to directories above the project.

  • #12578 6162922 Thanks @ematipico! - Fixed GraphQL parsing and formatting for executable descriptions and legacy fragment variables. Biome now formats inputs such as "Description" query { field } without panicking and removes insignificant commas consistently.

  • #12593 35c69ad Thanks @dyc3! - Fixed #12555: the default reporter now prints the command summary, the --max-diagnostics warning, and the skipped-fixes notice to stderr instead of stdout. Diagnostics already go to stderr, so the summary can no longer get mixed into the middle of a diagnostic when a tool reads the two streams separately.

  • #12415 9520907 Thanks @latin-1! - Fixed #12412: useSortedProperties now sorts properties inside @keyframes animations in CSS and SCSS.

2.6.4

Patch Changes

  • #12261 19fbfb2 Thanks @dyc3! - Added the new nursery rule noConsoleSpaces, which reports a leading or trailing space in a console.log(), console.debug(), console.info(), console.warn(), or console.error() argument that sits next to another argument. These methods already put a space between arguments, so such a space prints twice.

    console.log("abc ", "def");
  • #12469 cd716d3 Thanks @dyc3! - Added the new nursery rule noMagicArrayFlatDepth, which reports number literals other than 1 passed as the depth of Array.prototype.flat() unless a comment inside the parentheses explains them.

    const items = array.flat(2);
  • #12470 92c9e81 Thanks @dyc3! - Added the nursery rule noNull, which reports uses of the null literal and suggests undefined instead. Strict comparisons such as foo === null are allowed.

    let foo = null;
  • #12483 9bd3527 Thanks @dyc3! - Added the nursery rule noReturnArrayPush, which reports code that uses the return value of push() or unshift(). These methods return the new length of the array, not the added item or the array.

    function add(item) {
    return items.push(item);
    }
  • #12477 a384892 Thanks @dyc3! - Added the nursery rule noUnreadableIife, which reports arrow functions that are called right where they are defined and whose body is wrapped in parentheses.

    const foo = (bar => (bar ? bar.baz : baz))(getBar());
  • #12447 0a963e4 Thanks @dyc3! - Added the nursery rule noUselessRecursion, which reports functions that return a call to themselves when a loop can do the same work. Too many nested calls can crash the program with a stack overflow error.

    function findRoot(node) {
    if (node.parent) {
    return findRoot(node.parent);
    }
    return node;
    }
  • #12554 2eddda9 Thanks @dyc3! - Added the nursery rule noVueComputedPropertiesInData, which reports computed properties used inside the data function of a Vue component. Vue runs data before it sets up computed properties, so the value read there is undefined.

    <script>
    export default {
    data() {
    return { total: this.doubled };
    },
    computed: {
    doubled() {
    return 2;
    },
    },
    };
    </script>
  • #12586 824df15 Thanks @dyc3! - Added the nursery rule noVueDeprecatedDeleteSet, which reports calls to the $set and $delete functions, Vue.set and Vue.delete, and set and del imported from vue. Vue 3 removed these functions, so calling them throws an error.

    <script>
    export default {
    mounted() {
    this.$set(this.user, "name", "Alice");
    },
    };
    </script>
  • #12648 6fc1a51 Thanks @dyc3! - Added the nursery rule noVueDeprecatedRouterLinkTagProp, which disallows the tag prop on RouterLink. Vue Router 4 ignores this prop, so the link still renders as an <a> element.

    <template>
    <RouterLink tag="li" to="/">Home</RouterLink>
    </template>
  • #12631 de1188f Thanks @dyc3! - Added the new nursery rule noVueDeprecatedScopeAttribute, which reports the scope attribute on <template> elements in Vue files. Vue no longer supports this attribute, so use v-slot to receive slot props instead.

    <template>
    <ListComponent>
    <template scope="props">{{ props.title }}</template>
    </ListComponent>
    </template>
  • #12562 5d7553b Thanks @dyc3! - Added the new nursery rule noVueMultipleSlotArgs, which disallows passing more than one argument to a Vue slot from a render function. Slot content written in a template receives only the first argument.

    <script>
    export default {
    render() {
    return this.$slots.default(item, index); // reported
    },
    };
    </script>
  • #12513 2e520d8 Thanks @dyc3! - Added the nursery rule noVueMutatingProps, which reports code that changes the props of a Vue component, in the script or in the template. Props belong to the parent component, so the child should emit an event or copy the value instead.

    <script setup>
    const props = defineProps({ items: Array });
    props.items.push("new item");
    </script>
  • #12567 144b786 Thanks @dyc3! - Added the nursery rule noVueSideEffectsInComputed, which reports Vue computed properties that change state. Vue decides when to run a computed property, so changes made inside one happen at unpredictable times.

    <script setup>
    import { computed, ref } from "vue";
    const items = ref([]);
    // `reverse()` changes `items.value` in place.
    const reversedItems = computed(() => items.value.reverse());
    </script>
  • #12603 861b288 Thanks @dyc3! - Added the new nursery rule noVueUnusedRefs, which reports template refs in Vue components that nothing reads through $refs, useTemplateRef(), or a variable of the same name in <script setup>. The rule needs html.experimentalFullSupportEnabled to be true.

    <template>
    <input ref="input" />
    </template>
  • #12285 68770e0 Thanks @dyc3! - Added the new nursery rule noYamlBooleanKeys, which disallows boolean values as keys in YAML. For example, the following key is a boolean instead of text, so it is reported:

    true: enabled
  • #12338 f46411b Thanks @dyc3! - Added the nursery rule useSvelteEventDispatcherTypes, which reports createEventDispatcher() calls that don’t declare the types of their events in Svelte components written in TypeScript.

    The rule accepts a call that declares its events:

    <script lang="ts">
    import { createEventDispatcher } from "svelte";
    const dispatch = createEventDispatcher<{ save: string }>();
    </script>
  • #12615 ade9845 Thanks @dyc3! - Added the nursery rule useVueDefineOptions, which reports the default export of a plain <script> block in Vue components that also use <script setup>, and suggests setting those options with defineOptions() instead.

    <script>
    export default { name: "MyComponent" }; // reported
    </script>
    <script setup>
    const props = defineProps(["title"]);
    </script>
  • #12514 e74b4dc Thanks @dyc3! - Added the nursery rule useVueDefinePropsDestructuring, which requires destructuring the props returned by defineProps() in Vue <script setup> blocks. It also reports withDefaults(), because destructured props can set their default values directly.

    <script setup lang="ts">
    const props = defineProps<{ foo?: string }>();
    </script>
  • #12559 94985ba Thanks @dyc3! - Added the nursery rule useVueTemplateRef, which requires useTemplateRef() instead of ref() or shallowRef() to access elements of the template in <script setup>.

    <template>
    <input ref="input" />
    </template>
    <script setup>
    import { ref } from "vue";
    const input = ref(); // reported
    </script>
  • #12512 6be5078 Thanks @dyc3! - Added the nursery rule useVueTypedProps, which reports Vue props declared without a type, in the props option, defineProps(), or defineModel(). Without a type, Vue accepts any value for the prop and can’t warn when a component receives the wrong kind of value.

    <script setup>
    defineProps(["title"]);
    </script>
  • #12653 f307633 Thanks @dyc3! - Added the nursery rule useVueVModel, which reports a prop binding on a Vue component paired with an update: listener that only writes the new value back, and suggests v-model instead.

    <template>
    <MyComponent :title="title" @update:title="title = $event" />
    </template>
  • #12591 a810209 Thanks @dyc3! - Added the nursery rule useVueValidDefineEmits, which enforces valid usage of Vue’s defineEmits macro in <script setup>.

    For example, the following code is now reported, because defineEmits declares its events with both a type and an argument:

    <script setup lang="ts">
    const emit = defineEmits<(e: "notify") => void>(["submit"]);
    </script>
  • #12614 9308110 Thanks @dyc3! - Added the nursery rule useVueValidDefineProps, which reports defineProps() calls that Vue can’t compile or that declare props incorrectly. For example, it reports a component that calls defineProps() twice, or whose defineProps() argument uses a variable declared in <script setup>:

    <script setup>
    const definition = { msg: String };
    defineProps(definition);
    </script>
  • #12570 222a230 Thanks @dyc3! - Added the nursery rule useVueValidVIs, which reports v-is directives that have an argument or modifiers, have no value, or are used on a component instead of a native HTML element.

    For example, the following v-is directive has no value:

    <template>
    <tr v-is></tr>
    </template>
  • #12521 4010bb7 Thanks @dyc3! - Added the nursery rule useVueValidVMemo, which reports invalid v-memo directives in Vue templates. A v-memo directive must have an array value, can’t have an argument or modifiers, and doesn’t work inside an element with v-for.

    For example, the following value is an object instead of an array:

    <template>
    <div v-memo="{ id }"></div>
    </template>
  • #12597 aff42a7 Thanks @dyc3! - Added the nursery rule useVueValidVModel, which reports v-model directives that Vue can’t use: on unsupported elements or file inputs, with an argument or unknown modifier on a native element, without a value, or with a value that can’t be assigned to.

    For example, the following v-model directives are invalid:

    <template>
    <div v-model="foo"></div>
    <input v-model="foo + bar" />
    </template>
  • #12569 3058597 Thanks @dyc3! - Added the new nursery rule useVueValidVShow, which reports v-show directives that have an argument, a modifier, or no value, or that are placed on a <template> element.

    <template v-show="isVisible"><div></div></template>
  • #12525 e2e5a36 Thanks @dyc3! - Added the nursery rule useVueValidVSlot, which reports misplaced, duplicated, or malformed v-slot directives in Vue templates.

    For example, the rule reports two <template> elements that fill the same slot:

    <MyComponent>
    <template #header>First title</template>
    <template #header>Second title</template>
    </MyComponent>
  • #12472 efd16bd Thanks @dyc3! - Added the new nursery rule useWhileLoopCondition, which reports loops such as while (true) and for (;;) that start with an if statement containing only a break, and moves that condition into the while statement.

    while (true) {
    if (!hasMore()) {
    break;
    } // reported
    processNext();
    }
  • #12640 167bb00 Thanks @latin-1! - Updated useSortedProperties to follow stylelint-config-recess-order 7.9.0, adding sorting support for scroll-behavior, anchor positioning, multi-column layout, and other properties known to Biome.

  • #12719 40a82b0 Thanks @dyc3! - Improved the performance of the linter. Biome now spends less time setting up the enabled rules for each file it analyzes.

  • #12722 f074730 Thanks @dyc3! - Improved the performance of biome lint by about 1% to 3% on large projects, most noticeably with Biome’s default rules and with rules that track variables or unreachable code.

  • #12501 90a4d74 Thanks @ematipico! - Fixed #12466: the Biome daemon used more memory with every biome check --use-server run. The daemon now reuses the data that it stores for each file and project, and it keeps syntax trees only for the files that it read most recently.

  • #12501 90a4d74 Thanks @ematipico! - Fixed biomejs/biome-vscode#923: when a file open in the editor changed on disk, the language server replaced the editor’s text with the text on disk. Biome now keeps the editor’s text of open files until they are closed, so diagnostics, code actions and formatting stay at the right positions.

  • #12652 59ff42a Thanks @kurovskyiii! - Fixed #12651: an imported name that the other module exports as both a type and a value now resolves to the type in type annotations, so noBaseToString no longer reports slug below as an object.

    rule-slug.ts
    export type RuleSlug = string;
    export const RuleSlug = { create: (text: string): RuleSlug => text } as const;
    // main.ts
    import { RuleSlug } from "./rule-slug";
    export const label = (slug: RuleSlug): string => `rule ${slug}`;
  • #12678 301402f Thanks @nhedger! - Fixed biomejs/biome-vscode#1113: the language server now shows a warning when the configuration file can’t be parsed. Previously, Biome stopped processing files without telling the user why.

  • #12662 8c836eb Thanks @dyc3! - Fixed #12645: the Markdown formatter no longer removes the blank line between a blockquote and the list that follows it, matching Prettier.

    > A note.
    - one
    - two
  • #12662 8c836eb Thanks @dyc3! - Fixed #12663: the Markdown formatter no longer removes the blank line between a table and the list that follows it, matching Prettier.

    | Table |
    | ----- |
    | Value |
    - Hello
  • #12576 735d370 Thanks @jfmcdowell! - Fixed #12541: Markdown list items whose markers are indented 4 or more spaces now nest at the correct level. Previously the formatter could move such an item under the item before it, or join it to that item’s text.

    1. Step
    - a
    - x
    - y
    - b
    - y
    - b
  • #12575 0da9080 Thanks @jfmcdowell! - Fixed formatting of Markdown block quotes inside deeply indented list items. With proseWrap: "always", consecutive quote lines now wrap together within the same quote, while setext headings and fenced code blocks keep their structure.

    10. item
    > first line
    > second line
    > first line second line
  • #12607 896d53e Thanks @xucian! - Fixed #12542: the Markdown formatter is now idempotent when it formats tables.

    | a | b |
    | -------- | ----- |
    | x | `y` z |
    | `p` z`q` | r |
    | a | b |
    | --------- | ----- |
    | x | `y` z |
    | `p` z `q` | r |
  • #12692 8ff63f4 Thanks @NikitaCOEUR! - Fixed the linux-x64-musl binary not using jemalloc, which it already ships: it fell back to musl’s allocator, and biome check on several threads could take minutes instead of seconds, for example in Alpine-based CI images.

  • #12682 fa7cf4c Thanks @dyc3! - Fixed #12679: when markdown.parser.frontmatter and markdown.formatter.formatEmbeds are enabled, the Markdown formatter keeps the frontmatter of a fenced Markdown code block as written. Previously, it formatted the frontmatter as a thematic break and a paragraph, which removed the indentation of its YAML.

    ```markdown
    ---
    verified:
    by: human
    ---
    # Policy
    ```
  • #12649 343c8ca Thanks @JamBalaya56562! - Fixed #12643 and #12669: Biome now migrates the Prettier option bracketSpacing to formatter.bracketSpacing, both at the top level and inside overrides. JSON and GraphQL files are now formatted with the same bracket spacing as JavaScript files.

  • #12640 167bb00 Thanks @latin-1! - Fixed useSortedProperties to withhold sorting fixes that would change the effective values of overlapping declarations, physical/logical border or corner properties, or declarations followed by all. Updated noShorthandPropertyOverrides to recognize logical border, corner shape, position-try, text-box, and transition-behavior overrides.

  • #12723 b6cbec8 Thanks @dyc3! - Improved the performance of biome lint, biome check, and biome ci on files where rules report diagnostics with code fixes, by up to 12% with the default rules.

  • #12664 6021da0 Thanks @MindTooth! - Fixed Biome processing pnpm-lock.yaml files. These generated lockfiles are now protected from processing.

  • #12501 90a4d74 Thanks @ematipico! - Fixed an issue where the CLI, when it ran with --use-server alongside an editor connected to the same daemon, checked the unsaved text of the files open in the editor instead of the files on disk, and could make the editor’s text get lost. The CLI now checks the files on disk, and every editor and CLI run connected to the daemon keeps its own text of the files it opens.

  • #12519 9ae56ba Thanks @dyc3! - The rule noVueVIfWithVFor now also reports v-else-if and v-else on the same element as v-for.

    <div v-if="loading">Loading...</div>
    <TodoItem v-else v-for="todo in todos" :todo="todo" />
  • #12702 df0f7cc Thanks @dyc3! - Fixed parsing of default values in Vue v-for bindings. Biome now parses the default value as JavaScript, so it is formatted and linted like other template expressions instead of being reported as a parse error.

    <div v-for="{ value = gt('v-for default') } in rows" />
  • #12656 25a00a2 Thanks @dyc3! - Fixed non-JSON files inside the global settings directories of Zed, VS Code, and Cursor being parsed as JSON.

  • #12501 90a4d74 Thanks @ematipico! - Fixed an issue where the language server kept using the previous parser options for open files after the configuration changed. Open files are now parsed again with the new options, for example json.parser.allowComments.

  • #12656 25a00a2 Thanks @dyc3! - Improved the performance of Biome when it processes many files by up to 7%.

  • #12661 066a077 Thanks @dyc3! - Added the nursery rule noVueDeprecatedListeners. It reports references to $listeners, which Vue 3 removed, in Vue templates and component objects. For example, Biome now reports <div v-on="$listeners" /> and this.$listeners inside a Vue component.

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.

2.6.6

Patch Changes

  • #12887 da0422e Thanks @dyc3! - Added the new nursery rule noArrayMethodsOnArguments. It reports calls to array methods on the arguments object, which isn’t an array, so these calls throw a TypeError when the code runs.

    function sum() {
    return arguments.reduce((total, value) => total + value, 0);
    }
  • #12877 cd9e10f Thanks @dyc3! - Added the nursery rule noConstantComparisons, which reports && and || conditions that can never be true, are always true, or contain a check with no effect.

    if (statusCode <= 400 && statusCode > 500) {}
  • #12876 a7c9586 Thanks @dyc3! - Added the nursery rule noErasingOperation, which disallows operations with 0 that always result in zero: multiplying by 0, a bitwise AND with 0, and dividing 0 by a number. The other value in these operations has no effect on the result, which usually means the code has a mistake.

    const total = price * 0;
  • #12841 e954f55 Thanks @dyc3! - Added the nursery rule noNegatedArrayPredicate, which reports negated calls to Array#some() and Array#every() and suggests moving the negation into the callback function.

    // Invalid: use `array.every((item) => !isUnicorn(item))` instead.
    const isMissing = !array.some((item) => isUnicorn(item));
  • #12888 15039f7 Thanks @dyc3! - Added the new nursery rule noNumberArgumentOutOfRange, which reports number literal arguments of toString(), toFixed(), toExponential() and toPrecision() that are outside the range the method accepts. These calls throw a RangeError at runtime.

    value.toString(64);
  • #12889 1cd7520 Thanks @dyc3! - Added the nursery rule noSharedBranchCode, which reports code that is repeated at the start or end of every branch of an if statement. That code runs no matter which branch is taken, so it can be moved before or after the if statement.

    if (condition) {
    doSomething();
    cleanup();
    } else {
    doSomethingElse();
    cleanup();
    }
  • #12842 d47fcfd Thanks @dyc3! - Added the new nursery rule noSubtractionComparison, which reports subtracting two values only to compare the difference with 0, and suggests comparing the values directly.

    if (a - b > 0) {}
  • #12866 7c1cd5f Thanks @dyc3! - Added the nursery rule noSvelteIgnoredUnsubscribe, which reports calls to a store’s subscribe() method when the returned function is ignored. Without that function, the subscription can never be stopped, which causes a memory leak.

    <script>
    import { count } from "./stores.js";
    count.subscribe((value) => console.log(value));
    </script>
  • #12890 6b73fcf Thanks @dyc3! - Added the new nursery rule noUninvokedArrayCallback, which reports array methods such as map() and forEach() called with a callback on an array that only has empty slots. The callback never runs in this case.

    const list = new Array(5).map(() => createElement());
  • #12886 3bb18d8 Thanks @dyc3! - Added the nursery rule useNextScriptForGoogleAnalytics, which reports <script> elements that load Google Analytics or Google Tag Manager. Use the GoogleAnalytics and GoogleTagManager components from @next/third-parties/google instead, which load these scripts after the page becomes interactive.

    <script async src="https://www.googletagmanager.com/gtag/js?id=G-XYZ" />

    The rule belongs to the next domain.

  • #12309 0538e30 Thanks @dyc3! - Added the new nursery rule usePackageJsonCpu, which reports package.json files that have no cpu field. The cpu field lists the processor types that the package supports.

    The following package.json file satisfies the rule:

    {
    "name": "my-package",
    "version": "1.0.0",
    "cpu": ["x64", "arm64"]
    }
  • #12310 191111d Thanks @dyc3! - Added the nursery rule usePackageJsonEngines, which reports package.json files that have no engines field.

    A package.json passes the rule once it declares the field:

    {
    "name": "my-package",
    "engines": {
    "node": ">=20"
    }
    }
  • #12986 cc929af Thanks @dyc3! - Fixed #12954, where configuring rules in groups with more than 256 rules could enable or disable the wrong rule.

  • #12931 fe9248e Thanks @dyc3! - Improved the performance of linting. Each lint pass now spends less time stepping over syntax nodes that no enabled rule looks at.

  • #12969 22d27e8 Thanks @vibbix! - Improved the performance of CSS linting. Rules that compare selectors, such as noDescendingSpecificity and noDuplicateSelectors, now make fewer memory allocations.

  • #12973 5a06df5 Thanks @vibbix! - Fixed useGenericFontNames reporting font-family inside @font-palette-values. There, font-family names the font families the palette applies to, so it doesn’t take a generic family.

    @font-palette-values --palette {
    font-family: Bixa;
    override-colors: 0 red;
    }
  • #12930 ce71284 Thanks @dyc3! - Fixed #12073: useExhaustiveSwitchCases now reports non-exhaustive switches over values read from for...of loops over Array.prototype.entries(), Map, and Set, and over properties of array elements indexed by a number variable.

    noMisusedPromises now also reports Promise-returning callbacks passed to array methods such as find and every.

  • #12983 2987b54 Thanks @ashokram-si! - Fixed #12957: Biome now correctly parses SCSS negative interpolation list items as separate values instead of an invalid subtraction operator.

    margin: -#{$s} - #{$s} - #{$s} auto;
    margin: -#{$s} -#{$s} -#{$s} auto;

2.6.7 Latest

Patch Changes

  • #12906 b3375d2 Thanks @dyc3! - Added the nursery rule noAsyncPromiseFinally, which reports async functions passed to a promise’s .finally() method. If such a function fails, its error replaces the original result or error of the promise.

    promise.finally(async () => {
    await cleanup();
    });
  • #12894 e24da6f Thanks @dyc3! - Added the nursery rule noDuplicateTypeConstituents, which reports types listed more than once in a union or intersection type, and undefined in the type of an optional parameter.

    type T = string | number | string;
    function f(a?: string | undefined) {}
  • #12899 6c15027 Thanks @dyc3! - Added the nursery rule noExcessiveSelectorComplexity, which limits how many IDs, type selectors, attribute selectors, pseudo-classes, universal selectors, compound selectors, and combinators a CSS selector can contain. It can also disallow chosen combinators, pseudo-classes, pseudo-elements, attributes, and attribute operators. The rule does nothing until an option is set.

    For example, with "maxIds": 1, the following selector is reported:

    #main #sidebar {}
  • #12897 0b8f429 Thanks @dyc3! - Added the new nursery rule noInvalidFetchOptions, which reports a body in the options of fetch() and new Request() when the method is GET or HEAD. These calls throw a TypeError at runtime. When no method is given, the request uses GET.

    await fetch("/", { method: "GET", body: "foo=bar" });
  • #12926 9b6b9f4 Thanks @dyc3! - Added the nursery rule noNewArray, which reports new Array() calls with a single argument. Such a call creates an empty array of the given length when the argument is a number, and an array that holds the argument otherwise.

    const array = new Array(length);
  • #12895 739440f Thanks @dyc3! - Added the new nursery rule noRedundantTypeConstituents, which reports members of union and intersection types that have no effect, such as a literal type next to its primitive type, or never in a union.

    type Status = "active" | string;
  • #12810 71ab61b Thanks @dyc3! - Added the nursery rule noSvelteAsyncStore, which disallows passing async functions to the writable(), readable(), and derived() stores from svelte/store.

    import { writable } from "svelte/store";
    const user = writable(null, async (set) => {
    set(await fetchUser());
    });
  • #12917 37d9f41 Thanks @dyc3! - Added the new nursery rule noUnresolvedDefaultImport, which reports default imports from modules that have no default export. The rule is part of the project domain.

    // foo.js only contains `export function foo() {}`
    import foo from "./foo.js";
  • #12892 f16842e Thanks @dyc3! - Added the nursery rule noUselessFallbackInSpread, which reports empty object fallbacks when spreading a value into an object. Spreading null, undefined, or another falsy value into an object adds no properties, so the fallback has no effect.

    const object = { ...(options || {}) };
  • #12785 c198be2 Thanks @dyc3! - Added the new nursery rule noUselessParameterPropertyAssignment, which reports constructor assignments such as this.name = name when name is a parameter property. TypeScript already sets the property to the parameter’s value, so the assignment does nothing.

    class User {
    constructor(public name: string) {
    this.name = name;
    }
    }
  • #12900 a4d1b0f Thanks @dyc3! - Added the nursery rule noUselessSpread, which reports spread syntax that has no effect. For example, [first, ...[second]] can be written as [first, second], and new Set([...items]) can be written as new Set(items).

  • #12902 d7d755b Thanks @dyc3! - Added the nursery rule noVueExposeAfterAwait, which reports expose() and defineExpose() calls that come after an await in a Vue component’s setup code. These calls run too late, so a parent component might not receive the exposed properties.

    <script setup>
    await fetchUser();
    defineExpose({ reload });
    </script>
  • #12596 d33e56e Thanks @dyc3! - Added the nursery rule useAtomicUpdates, which reports assignments in async functions and generators that can be based on an outdated value because the function paused at an await or yield after reading it.

    let total = 0;
    async function addToTotal(getAmount) {
    total += await getAmount(); // reported
    }
  • #12901 48e3572 Thanks @dyc3! - Added the new nursery rule useConsistentBooleanName. It requires variables, parameters, and functions that hold or return a boolean to start with a prefix such as is or has, and reports names with those prefixes that don’t hold or return a boolean.

    const completed = progress === 100;
    const hasName = "Sindre";
  • #12905 5b00387 Thanks @dyc3! - Added the nursery rule useConsistentFontWeightNotation, which enforces writing font weights either as numbers or as the keywords normal and bold where possible. It checks the font-weight and font properties, and its safe fix converts between normal/bold and 400/700.

    a { font-weight: bold; }
  • #12922 8d33c85 Thanks @dyc3! - Added the nursery rule useConsistentTupleLabels, which reports tuple type elements without a label when other elements of the same tuple have one.

    type Point = [x: number, number];
  • #12925 7252cbd Thanks @dyc3! - Added the new nursery rule useGlobalRegexInMatchAll, which reports calls to matchAll() with a regular expression that doesn’t have the g flag. These calls throw a TypeError at runtime.

    text.matchAll(/pattern/);
  • #12891 e781bc3 Thanks @dyc3! - Added the nursery rule useGlobalRegexInReplaceAll, which reports regular expressions without the g flag passed to replaceAll(). These calls throw a TypeError instead of replacing text.

    withSpaces.replaceAll(/\s+/, ",");
  • #12896 a968e1a Thanks @dyc3! - Added the new nursery rule useValidCharacterComparison, which reports comparisons between a single character and a string that has more than one character. Such comparisons are always false, or always true with !== and !=.

    text.charAt(0) === "ab";
  • #13085 7a795d0 Thanks @ematipico! - Fixed withastro/compiler-rs#221 so Astro template expressions containing comment-only JSX expression children, such as <span>{<!-- x -->}</span>, parse without diagnostics.

  • #12621 79ce388 Thanks @latin-1! - Fixed #12413 and #12414: useSortedProperties now sorts consecutive groups of properties independently, preserving the positions of nested rules, at-rules, and SCSS variable declarations.

  • #13065 bd9faae Thanks @ematipico! - Fixed #5848: running useSortedKeys or useSortedSelectionSet as an editor source action no longer corrupts nested objects or selection sets.

  • #13056 98f4d53 Thanks @ematipico! - Fixed #10607: noUndeclaredDependencies no longer reports imports resolved through TypeScript’s compilerOptions.paths mappings.

  • #13033 7638393 Thanks @GBra-4-669! - Fixed #12980: the CSS parser no longer panics on a composes declaration whose value contains a non-identifier token, such as composes: 1px;. It reports a diagnostic instead.

  • #12917 37d9f41 Thanks @dyc3! - Fixed noUnresolvedImports: it now reports default imports from modules that only forward exports with export * from "...". export * never re-exports a default export, so import foo from "./barrel.js" fails when ./barrel.js contains only export * from "./foo.js".

  • #12596 d33e56e Thanks @dyc3! - Fixed noUnreachableSuper ignoring the default values of constructor parameters. Using this in a default value is now reported, because it runs before super(), and calling super() in a default value is now recognized.

    class Child extends Parent {
    constructor(options = this.defaults()) { // reported
    super(options);
    }
    }
  • #12596 d33e56e Thanks @dyc3! - Fixed noUselessAssignment ignoring variables that are used in the iterated value of a for...of or for...in loop, in the default values of a destructuring declaration or of parameters, or in the body of an arrow function written as a single expression. These variables are now checked too.

    function process(first, second) {
    let list = first; // reported: this value is never read
    list = second;
    for (const item of list) {
    handle(item);
    }
    }
  • #12805 2468384 Thanks @vibbix! - Fixed #12332: noUnknownUnit no longer reports hex colors that start with a digit in SCSS custom properties or in unquoted legacy IE filter values. The rule now accepts --accent: #4566a8; instead of reporting the unknown unit a8.

  • #12549 7fdb28f Thanks @pkallos! - Fixed #10464: useNullishCoalescing no longer reports a ternary or if statement that checks only null or only undefined when the type can also be the other, because ?? would change its behavior.

  • #12952 d1896a0 Thanks @arendjr! - Added grit() queries to JavaScript plugins. A rule can now use a GritQL pattern to select the nodes passed to run() instead of listing syntax kinds with ast().

    For example:

    export const noConsole = defineRule({
    query: grit("`console.log($args)`"),
    run(element) {
    if (element.kind !== "JS_CALL_EXPRESSION") return;
    registerDiagnostic(element, "warning", "Unexpected console.log.");
    },
    });

    Usage of Grit patterns can be particularly useful when it would take several checks to verify the shape of a snippet that involves multiple AST nodes.

    Grit sequence patterns call run() for each matched node. Matching on leaf tokens is also supported for patterns, while patterns containing rewrites are rejected. Plugins using GritQL patterns should report diagnostics from run() as usual.

    Plugins using Grit queries can still request the semantic model as well:

    export const rule = defineRule({
    query: grit("function $fn($args) { $body }", { semantic: true }),
    run(node, { model }) {
    // You can use `model` here similar to a query specified using `ast(..., { semantic: true })`.
    },
    });
  • #13022 81d0187 Thanks @arendjr! - Fixed an issue where GritQL patterns wouldn’t match snippets if they contain a trailing list separator.

    For example, the pattern `a, b` wouldn’t match the arguments in function(a, b,), whereas now they do.

  • #12999 ace98cf Thanks @deepsingh132! - Fixed #12953: the Markdown formatter no longer removes the blank line between a blockquote that ends a list item and the block that follows it, matching Prettier. Removing that line could also move a following paragraph into the blockquote. The same applies to a list item that ends with a hard line break.

    - a
    > b
    #### Heading
  • #13067 45c8c4d Thanks @ematipico! - Added the nursery rule noDisabledAttribute, which warns when buttons and other form controls use the native disabled attribute. A disabled control can’t be reached with the Tab key, so the rule suggests aria-disabled or readonly instead.

    <button disabled>Save</button>
    <input type="email" disabled />
  • #12923 0668c8f Thanks @dyc3! - Added the new nursery rule noScssNullComparison. It reports comparisons to null in Sass @if and @else if conditions, because null already counts as false in a condition.

    a {
    @if $value == null {}
    }
  • #12955 e1ef913 Thanks @ematipico! - Fixed an issue where Biome could silently skip configured plugins. Biome now reports an error when those plugins are unavailable during analysis.

  • #12997 419aa5d Thanks @Riccardo-bit-cpu! - Fixed #12475: noSwitchDeclarations no longer reports var declarations inside switch clauses, matching ESLint’s no-case-declarations.

  • #12867 6a25d72 Thanks @dyc3! - Added the nursery rule noUselessQualifier, which reports namespace and enum names that are repeated before a member inside that same namespace or enum. Biome provides a fix that removes the repeated name.

    namespace Shapes {
    export type Point = { x: number; y: number };
    const origin: Shapes.Point = { x: 0, y: 0 };
    }
  • #12050 60f4695 Thanks @dor-sr! - Fixed #11933: useUnicodeRegex no longer offers to add the u flag to patterns that become invalid or change meaning in Unicode mode, such as /{/, /\-/ or /[\d-z]/. The rule still reports them.

  • #13035 478e056 Thanks @dyc3! - Fixed #13026: the Markdown formatter no longer indents the rows of a table inside a blockquote when the table follows a paragraph of two or more lines. Previously, every run of the formatter indented the rows further until they were joined onto the header line.

    > First line of a paragraph,
    > second line of it.
    >
    > | A | B |
    > | --- | --- |
    > | x | y |
    > | --- | --- |
    > | x | y |
  • #13066 f6cf28e Thanks @arendjr! - Removed the semantic() query function from the JavaScript plugin API. Pass { semantic: true } to ast() instead to provide the semantic model to a rule.

    export const rule = defineRule({
    query: semantic("JS_REFERENCE_IDENTIFIER"),
    run(node, { model }) {
    // Use `model` here.
    },
    });

    Becomes:

    export const rule = defineRule({
    query: ast("JS_REFERENCE_IDENTIFIER", { semantic: true }),
    run(node, { model }) {
    // Use `model` here.
    },
    });

    This behaviour matches the grit() query function, which also accepts the { semantic: true } option.

  • #12951 014b976 Thanks @ematipico! - Fixed #10782: noUndeclaredClasses no longer appears to hang on projects with long component import chains.

  • #13073 827e610 Thanks @vibbix! - Fixed #13072: a comment before a SCSS map entry whose value is a parenthesized group no longer indents that group one level too deep. This matches Prettier 3.10 behavior now.

    $map: (
    /* comment */
    key: (
    a: 1,
    b: 2,
    ),
    a: 1,
    b: 2,
    ),
    );
  • #12928 ae0e186 Thanks @dyc3! - Improved noUselessStringConcat. The rule now reports literals joined after another value, such as foo + "a" + "b", and fixes template literals with placeholders, so `Hello, ${name}` + "!" becomes `Hello, ${name}!`.

    The rule no longer reports strings that would join into text that looks like a placeholder, such as "$" + "{name}", or into a directive such as "use strict". It also no longer reports obj.foo * "a" + "b", which its fix used to change to obj.foo * "ab".

    The fix no longer changes the value of the string in two cases. It used to change 1 + 2 + "b" + "c" to "12bc" instead of 1 + 2 + "bc". It used to change "\1" + "2" to "\12", which is a different escape sequence.

    The fix no longer joins literals that are on different lines when the concatenation ends with two literals on the same line. It also no longer puts a line break from a template literal into a string literal, which made the code invalid.

  • #13048 24734a8 Thanks @ematipico! - Fixed #13028: Biome now keeps a paragraph in its outer block quote when a quote-only blank line closes a nested block quote.

    > > b
    >
    > > c
    > c
  • #12967 bd0988e Thanks @siketyan! - Fixed #12827: noDuplicateProperties, noDuplicateCustomProperties, and noMissingVarFunction now check declarations at the top level of embedded CSS templates, such as styled.div`...`.

  • #13048 24734a8 Thanks @ematipico! - Fixed #13029: the Markdown formatter now normalizes spaces inside inline and reference link text without removing whitespace-only text.

    something [ text ]( destination)
    something [ ]( destination)
    something [ text ](destination)
    something [ ](destination)
  • #13021 05a1409 Thanks @dyc3! - Fixed #12993: Svelte {@const} tags with TypeScript type annotations, such as {@const doubled: number = item * 2}, now parse and format in components with <script lang="ts">.

  • #12968 ec0142b Thanks @siketyan! - Fixed #12826: Biome now detects CSS in styled-components templates that use .attrs(), such as styled.button.attrs({ type: "button" })`...` and styled(Component).attrs(() => ({}))`...`, so they are formatted and linted like styled.button`...`.

  • #13048 24734a8 Thanks @ematipico! - Fixed #13027: the Markdown formatter now preserves spaces around text after a code span that crosses block quote lines.

    > `a
    > b`c`d`
    > b` c `d`
  • #13055 78c744a Thanks @ematipico! - Fixed #13053: Biome now reports missing CLI paths as file-system errors without the INTERNAL tag or advice that the path was ignored by configuration. File-system diagnostics now use specific fs/* categories, with underlying I/O errors categorized as fs/io.

  • #12927 c6feec1 Thanks @dyc3! - Added the nursery rule useCatchErrorName, which requires a specific name for caught errors in try...catch statements and in the error handlers of promise.catch() and promise.then(). The name defaults to error and can be changed with the name option.

    try {} catch (err) {} // `err` should be named `error`
  • #12788 7f971ed Thanks @dyc3! - Extended useWhile to report for (;;) loops and to fix them to while (true).

  • #12967 bd0988e Thanks @siketyan! - Fixed noMissingVarFunction so it also checks declarations inside at-rules such as @page and @font-face. For example, @page { margin: --page-margin; } is now reported when --page-margin is declared in :root.

  • #13057 d9267a5 Thanks @ematipico! - Fixed #10896 so Svelte <script generics> attributes containing object type constraints parse and format as TypeScript type parameters.

  • #13048 24734a8 Thanks @ematipico! - Fixed #13038: Biome now aligns wrapped task-list paragraphs with the text following the checkbox.

    - [ ] Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc varius
    malesuada eros, faucibus dapibus odio rhoncus in.
    malesuada eros, faucibus dapibus odio rhoncus in.