Skip to content

Conversation

@tylerbutler
Copy link
Member

Description

Biome 2.x changed configuration format from separate include/ignore fields to a unified includes field with negation patterns (e.g., ["**", "!node_modules/**"]). This adds support for the new format so fluid-build can correctly determine file scope for caching.

New files:

  • biome2ConfigTypes.d.ts - Type definitions for Biome 2.x config format (including root field)
  • biome2Config.ts - Reader that parses unified includes field with negation support
  • biomeVersion.ts - Version detection from package.json or CLI
  • biomeConfigUtils.ts - Shared utilities for config loading and extends resolution

Changes to biomeConfig.ts:

  • BiomeConfigReaderInterface - Common interface for both readers
  • createBiomeConfigReader() - Factory with auto-detection
  • Refactored to use shared utilities from biomeConfigUtils.ts

Key features:

  • Supports the root field for automatic parent config discovery (walks up directory tree until root: true is found)
  • Handles both explicit extends declarations and automatic parent config merging
  • Parses unified includes field and separates include/ignore patterns
  • Supports combined extends + find-up: root config can extend another config, and child configs inherit everything through find-up
// Auto-detects Biome version and uses appropriate reader
const reader = await createBiomeConfigReader(packageDir, gitRepo);
const files = reader.formattedFiles;

// Or force a specific version
const reader2x = await createBiomeConfigReader(packageDir, gitRepo, 2);

Usage:
Import directly from source modules:

import { Biome2ConfigReader, loadBiome2Config } from "./biome2Config";
import { detectBiomeVersion, BiomeMajorVersion } from "./biomeVersion";

Reviewer Guidance

  • Version detection tries package.json first (faster), falls back to CLI
  • Both readers share BiomeConfigReaderInterface for interoperability
  • Shared utilities in biomeConfigUtils.ts reduce code duplication between 1.x and 2.x implementations:
    • loadRawBiomeConfigFile<T>() - Generic JSON5 config loading
    • resolveExtendsChainGeneric<T>() - Shared extends chain resolution with optional includeConfigPath parameter
  • Test data uses .jsonc extension (not biome.jsonc) to avoid Biome 1.x schema validation errors during checks
  • Tests include multi-level extends scenarios (e.g., pkg-b/config.jsoncpkg-a/config.jsoncbaseconfig.jsonc) to verify config inheritance chains work correctly
  • Tests include nested configs WITHOUT extends (root: true/root: false) to verify automatic parent config discovery and merging
  • Tests cover combined extends AND find-up: root config extends baseconfig, child config uses find-up and inherits settings from both root and base

Copilot AI and others added 8 commits December 3, 2025 00:09
… interface

Co-authored-by: tylerbutler <19589+tylerbutler@users.noreply.github.com>
… remove package-lock.json

Co-authored-by: tylerbutler <19589+tylerbutler@users.noreply.github.com>
…dd nested extends tests

Co-authored-by: tylerbutler <19589+tylerbutler@users.noreply.github.com>
…igs without extends

Co-authored-by: tylerbutler <19589+tylerbutler@users.noreply.github.com>
Co-authored-by: tylerbutler <19589+tylerbutler@users.noreply.github.com>
… + find-up

Co-authored-by: tylerbutler <19589+tylerbutler@users.noreply.github.com>
…hift performance

Co-authored-by: tylerbutler <19589+tylerbutler@users.noreply.github.com>
@tylerbutler tylerbutler changed the title Copilot/update biomeconfigreader for 2 x feat(build-tools): add Biome 2.x configuration reader Dec 3, 2025
tylerbutler and others added 15 commits December 3, 2025 12:42
…ing logic

Co-authored-by: tylerbutler <19589+tylerbutler@users.noreply.github.com>
Co-authored-by: tylerbutler <19589+tylerbutler@users.noreply.github.com>
…consolidate getClosestBiomeConfigPath

Co-authored-by: tylerbutler <19589+tylerbutler@users.noreply.github.com>
Co-authored-by: tylerbutler <19589+tylerbutler@users.noreply.github.com>
Co-authored-by: tylerbutler <19589+tylerbutler@users.noreply.github.com>
… in Biome 2.x

Co-authored-by: tylerbutler <19589+tylerbutler@users.noreply.github.com>
…patterns

Co-authored-by: tylerbutler <19589+tylerbutler@users.noreply.github.com>
"eslint:fix": "eslint --format stylish src --fix --fix-type problem,suggestion,layout",
"format": "npm run format:biome",
"format:biome": "biome check --write .",
"json-schema-to-typescript:biome2ConfigTypes": "json2ts --input node_modules/biome2/configuration_schema.json --output src/common/biome2ConfigTypes.d.ts",
Copy link
Member Author

Choose a reason for hiding this comment

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

This won't work until we update to biome 2. I tried adding it with an npm alias but that cause v2 to get triggered when running format.

@tylerbutler tylerbutler marked this pull request as ready for review December 4, 2025 00:33
@tylerbutler tylerbutler requested review from a team and Copilot December 4, 2025 00:51
Copilot finished reviewing on behalf of tylerbutler December 4, 2025 00:56
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds support for Biome 2.x configuration format to the build tools, enabling fluid-build to correctly determine file scope for caching when Biome 2.x is used. The implementation introduces version detection, a new config reader for the unified includes field syntax with negation patterns, and shared utilities to reduce code duplication between Biome 1.x and 2.x implementations.

Key changes:

  • Automatic version detection from package.json or CLI with fallback to Biome 1.x
  • Support for Biome 2.x's unified includes field with negation patterns and re-inclusion support
  • Automatic parent config discovery via root field and directory tree walking
  • Refactored shared utilities for config loading and extends resolution

Reviewed changes

Copilot reviewed 21 out of 22 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/common/biomeVersion.ts New file implementing Biome version detection from package.json and CLI
src/common/biomeConfigUtils.ts New file with shared utilities for config loading, extends resolution, and file filtering
src/common/biome2Config.ts New file implementing Biome 2.x config reader with unified includes field support
src/common/biome2ConfigTypes.d.ts Auto-generated TypeScript definitions for Biome 2.x configuration schema
src/common/biomeConfig.ts Refactored to use shared utilities, added BiomeConfigReader interface and createBiomeConfigReader factory
src/fluidBuild/tasks/leaf/biomeTasks.ts Updated to use createBiomeConfigReader for automatic version detection
src/test/biomeConfig.test.ts Updated to use renamed BiomeConfigReaderV1 class
src/test/biome2Config.test.ts New comprehensive test suite for Biome 2.x functionality
src/test/data/biome2/* New test data files for Biome 2.x config scenarios
package.json Added script for generating biome2ConfigTypes (references non-existent package)


/**
* Loads a Biome 2.x configuration file _without_ following any 'extends' values. You probably want to use
* {@link loadBiome2Configs} instead of this function.
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

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

The docstring references {@link loadBiome2Configs} (with an 's'), but the actual function is named loadBiome2Config (without the 's'). This should be corrected to {@link loadBiome2Config}.

Suggested change
* {@link loadBiome2Configs} instead of this function.
* {@link getAllBiome2ConfigPaths} instead of this function.

Copilot uses AI. Check for mistakes.
Comment on lines +36 to +123
export function detectBiomeVersionFromCli(cwd?: string): BiomeVersionInfo | undefined {
try {
const output = execSync("npx biome --version", {
cwd,
encoding: "utf8",
stdio: ["pipe", "pipe", "pipe"],
});

// Output format is "Version: X.Y.Z" or just "X.Y.Z"
const versionMatch = output.match(/(\d+\.\d+\.\d+)/);
if (versionMatch) {
const version = versionMatch[1];
const major = semver.major(version);
if (major === 1 || major === 2) {
return {
version,
majorVersion: major as BiomeMajorVersion,
};
}
}
} catch {
// Biome CLI not available or failed
}
return undefined;
}

/**
* Detects the Biome version by reading the package.json of the @biomejs/biome package.
*
* @param startDir - The directory to start searching from. Will look for node_modules/@biomejs/biome/package.json.
* @returns The Biome version information, or undefined if the package is not found.
*/
export async function detectBiomeVersionFromPackage(
startDir: string,
): Promise<BiomeVersionInfo | undefined> {
// Try to find the biome package.json by walking up the directory tree
let currentDir = startDir;
const root = path.parse(currentDir).root;

while (currentDir !== root) {
const biomePkgPath = path.join(
currentDir,
"node_modules",
"@biomejs",
"biome",
"package.json",
);
try {
const content = await readFile(biomePkgPath, "utf8");
const pkg = JSON.parse(content) as { version?: string };
if (pkg.version) {
const major = semver.major(pkg.version);
if (major === 1 || major === 2) {
return {
version: pkg.version,
majorVersion: major as BiomeMajorVersion,
};
}
}
} catch {
// Package not found at this level, continue searching
}
currentDir = path.dirname(currentDir);
}

return undefined;
}

/**
* Detects the Biome version, trying multiple methods:
* 1. First, try to read the version from the installed @biomejs/biome package
* 2. Fall back to running the Biome CLI
*
* @param startDir - The directory to start searching from.
* @returns The Biome version information, or undefined if Biome cannot be detected.
*/
export async function detectBiomeVersion(
startDir: string,
): Promise<BiomeVersionInfo | undefined> {
// Try package.json first (faster and more reliable)
const fromPackage = await detectBiomeVersionFromPackage(startDir);
if (fromPackage) {
return fromPackage;
}

// Fall back to CLI detection
return detectBiomeVersionFromCli(startDir);
}
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

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

The version detection functions (detectBiomeVersion, detectBiomeVersionFromPackage, detectBiomeVersionFromCli) lack test coverage. These functions contain logic that could fail in various ways (e.g., package.json not found, CLI not available, invalid version format) and would benefit from unit tests.

Consider adding tests that cover:

  • Successful version detection from package.json
  • Successful version detection from CLI
  • Fallback behavior when package.json method fails
  • Handling of invalid version strings
  • Behavior when Biome is not installed

Copilot uses AI. Check for mistakes.
Comment on lines +255 to 276
export async function createBiomeConfigReader(
directoryOrConfigFile: string,
gitRepo: GitRepo,
forceVersion?: BiomeMajorVersion,
): Promise<BiomeConfigReader> {
let majorVersion: BiomeMajorVersion;

if (forceVersion !== undefined) {
majorVersion = forceVersion;
} else {
// Auto-detect the Biome version
const versionInfo = await detectBiomeVersion(directoryOrConfigFile);
majorVersion = versionInfo?.majorVersion ?? 1; // Default to 1.x if detection fails
}

if (majorVersion === 2) {
return Biome2ConfigReader.create(directoryOrConfigFile, gitRepo);
}

// Default to Biome 1.x reader
return BiomeConfigReaderV1.create(directoryOrConfigFile, gitRepo);
}
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

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

The createBiomeConfigReader factory function lacks test coverage. This is a key new API that automatically detects the Biome version and returns the appropriate reader. Tests should verify:

  • Correct reader selection based on detected version (1.x vs 2.x)
  • Behavior when version detection fails (should default to 1.x)
  • Force version parameter override functionality
  • Integration with both BiomeConfigReaderV1 and Biome2ConfigReader

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant