github biomejs/biome @biomejs/biome@2.6.7
Biome CLI v2.6.7

46 minutes ago

2.6.7

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.

What's Changed

  • chore: remove graphite from sponsors by @dyc3 in #12988
  • fix(graph): memoize upward traversal by @ematipico in #12951
  • fix(plugins): emit error on missing plugin by @ematipico in #12955
  • fix(lint/useUnicodeRegex): don't add the u flag to patterns invalid in unicode mode by @dor-sr in #12050
  • fix(lint/css): resolve root declarations in embedded snippets by @siketyan in #12967
  • feat(embeds/css): parse styled.a.attrs() as embedded CSS snippets by @siketyan in #12968
  • feat: support GritQL queries in JS plugins by @arendjr in #12952
  • fix(lint): don't report var in noSwitchDeclarations by @Riccardo-bit-cpu in #12997
  • fix(svelte): parse type annotations in const tags by @dyc3 in #13021
  • fix(grit): allow matching trailing list separator by @arendjr in #13022
  • feat(lint): add NoReactDirectStateMutation by @jelly in #13034
  • fix(useWhile): detect and fix infinite for loops by @dyc3 in #12788
  • docs: remove duplicated word in HTML formatter debug comment by @ninglinLiu in #13039
  • feat(lint): add noSvelteAsyncStore by @dyc3 in #12810
  • feat(lint): add noUselessParameterPropertyAssignment by @dyc3 in #12785
  • feat(lint): add noUselessQualifier by @dyc3 in #12867
  • feat(lint): add useGlobalRegexInReplaceAll by @dyc3 in #12891
  • feat(lint): add noUselessFallbackInSpread by @dyc3 in #12892
  • feat(lint): add useValidCharacterComparison by @dyc3 in #12896
  • feat(lint): add noExcessiveSelectorComplexity by @dyc3 in #12899
  • feat(lint): add useGlobalRegexInMatchAll by @dyc3 in #12925
  • feat(lint): add noScssNullComparison by @dyc3 in #12923
  • feat(lint): add noUnresolvedDefaultImport by @dyc3 in #12917
  • feat(lint): add useConsistentTupleLabels by @dyc3 in #12922
  • feat(lint): add useConsistentFontWeightNotation by @dyc3 in #12905
  • feat(lint): add noAsyncPromiseFinally by @dyc3 in #12906
  • feat(lint): add noUselessSpread by @dyc3 in #12900
  • feat(lint): add useConsistentBooleanName by @dyc3 in #12901
  • feat(lint): add noInvalidFetchOptions by @dyc3 in #12897
  • feat(lint): add noVueExposeAfterAwait by @dyc3 in #12902
  • feat(lint): add noNewArray by @dyc3 in #12926
  • feat(lint): add useCatchErrorName by @dyc3 in #12927
  • feat(lint): add noRedundantTypeConstituents by @dyc3 in #12895
  • feat(lint): add noDuplicateTypeConstituents by @dyc3 in #12894
  • feat(lint): expand noUselessStringConcat by @dyc3 in #12928
  • feat(lint): add useAtomicUpdates and some fixes in the control flow graph by @dyc3 in #12596
  • fix(css): sort consecutive property groups independently by @latin-1 in #12621
  • chore(deps): update rust crate jiff to 0.2.41 by @renovate[bot] in #13040
  • chore(deps): update rust crate smallvec to 1.16.5 by @renovate[bot] in #13043
  • chore(deps): update rust crate notify to 8.2.2 by @renovate[bot] in #13042
  • fix(markdown_formatter): keep blank line after a blockquote ending a list item by @deepsingh132 in #12999
  • fix(css_parser): don't panic on non-identifier composes value by @GBra-4-669 in #13033
  • feat(rowan): port upstream navigation APIs by @ematipico in #13050
  • refactor: adopt Rowan navigation APIs by @ematipico in #13051
  • refactor(vue): allow easier lookup of syntax nodes from vue semantic model objects by @dyc3 in #12916
  • chore(deps): update rust to v1.99.1 by @renovate[bot] in #13047
  • fix(md/fmt): various bugs by @ematipico in #13048
  • fix(format/md): keep table rows in blockquotes aligned by @dyc3 in #13035
  • fix(cli): os error by @ematipico in #13055
  • fix(core): parse and visit generics by @ematipico in #13057
  • fix(analyzer): skip subtree for sort rules by @ematipico in #13065
  • feat(lint): noDisabledButton rule by @ematipico in #13067
  • fix(lint/css): add fixed SCSS map comment indentation by @vibbix in #13073
  • chore: remove semantic() query function from JS plugin API by @arendjr in #13066
  • fix(lint): don't report partial nullish checks in useNullishCoalescing by @pkallos in #12549
  • fix(parse/astro): html comments in expressions by @ematipico in #13085
  • chore(deps): fix advisories by @dyc3 in #13090
  • fix(css_parser): lex digit-led hash names in raw custom property values by @vibbix in #12805
  • fix(noUndeclaredDependencies): typescript paths by @ematipico in #13056
  • feat(lint): cover all form controls in noDisabledAttribute by @dyc3 in #13096
  • ci: release by @github-actions[bot] in #12989

New Contributors

Full Changelog: https://github.com/biomejs/biome/compare/@biomejs/biome@2.6.6...@biomejs/biome@2.6.7

Don't miss a new biome release

NewReleases is sending notifications on new releases.