Skip to content

Enforce function length, nullish coalescing and no-console with Biome - #1585

Merged
cristianrgreco merged 5 commits into
mainfrom
claude/enforce-code-style-with-biome-d40615
Oct 13, 2026
Merged

cristianrgreco merged 5 commits into
mainfrom
claude/enforce-code-style-with-biome-d40615

Conversation

@cristianrgreco

@cristianrgreco cristianrgreco commented Oct 12, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Enables three Biome rules at error, so conventions that were only written down (#1517) are checked by npm run lint and the Lint job. Every existing violation is fixed rather than suppressed: there is no biome-ignore and no per-file exemption for these rules.

Rule Hits before After
complexity/noExcessiveLinesPerFunction (maxLines: 50) 75 (68 in *.test.ts, 7 in source) 0: off for *.test.ts, 7 refactored
nursery/useNullishCoalescing 6 0: 2 fixed here, 4 in Couchbase removed by #1514
suspicious/noConsole 4 0: 2 fixed, 2 outside the rule's scope

Function length

The rule is off for **/*.test.ts. 64 of the 68 hits there are describe callbacks, which wrap a whole suite and cannot be shortened, and the rule has no option to skip callbacks. The other 4 are two it bodies, one it.each body and one mock factory. The seven long functions are split by extracting phases into private helpers placed below their caller. The statements are moved, not rewritten.

Function Lines before After Extracted helpers
CouchbaseContainer.createBuckets 157 24 createBucket, waitUntilBucketHasEnabledServices, waitUntilBucketIsHealthy, waitUntilKeyspaceIsPresent, createPrimaryIndex, waitUntilPrimaryIndexIsOnline
DockerComposeEnvironment.up 112 39 createCommandOptions, createComposeOptions, waitForStartedContainers, toStartedGenericContainer
AzuriteContainer.start 68 20 createCommand, configureSsl
GenericContainer.startContainer 67 46 connectContainerToNetworks, copyToCreatedContainer, consumeContainerLogs
DockerContainerClient.exec 61 43 createExecOptions, waitForExecStreamToEnd
initStrategy in container-runtime/clients/client.ts 59 40 createInfo
HttpWaitStrategy.waitUntilReady 58 45 sendRequest, matchesPredicates

Three statements moved relative to code with no side effects, which cannot be observed:

  • DockerComposeEnvironment.up calls pullPolicy.shouldPull() before building the command options array, not between two pushes to it.
  • initStrategy built the nodeInfo literal (process.version, arch, platform) before looking up host IPs. createInfo builds it afterwards, together with the runtime info.
  • CouchbaseContainer.createBuckets reads remainingStartupMs() for the two HTTP waits when it calls the helper, not part-way through building the wait strategy. Nothing is awaited in between.

createBuckets was 137 lines when this PR was opened and 157 after #1514.

Nullish coalescing

Both sites behave the same with ??:

  • ValkeyContainer.importInitialData: this.password || "". The left side is string | undefined, and an empty string yields "" either way.
  • StartedGenericContainer.getContainerCommitChangeCommands: options.changes || []. The left side is string[] | undefined, and an array is never falsy.

Console

  • StartedCloudStorageEmulatorContainer.processServerConfigChange and StartedPostgreSqlContainer.execCommandsSQL now use log from testcontainers, at the same level (warn, error) with the same message. PostgreSQL appends the error to the message, because log.error takes one string.
  • Scope: the rule is not on globally. One overrides entry enables it for packages/**/src/**, excluding packages/testcontainers/src/common/logger.ts. That file is the logger and binds console.log as its sink. Files outside package source are not covered, such as packages/testcontainers/smoke-test.js, which prints its failure before exiting non-zero.

Couchbase

The first revision of this PR left packages/modules/couchbase/src/couchbase-container.ts alone, because #1514 was rewriting it, and carried a temporary overrides entry for that file. #1514 has merged, so main is merged in, the entry is gone and the file is fixed like the others.

Left out: style/useConsistentMemberAccessibility

With accessibility: "explicit" it reports 237 members in 88 files. 128 of them are constructors, and the rule has no option to exempt constructors, so it would force public constructor(...) everywhere.

Follow-up

#1517 has not merged, so .agents/skills/write-code/SKILL.md is not edited here. Once it is on main, its bullets on function length, ?? and console should say Biome enforces them. In AGENTS.md, the bullets that listed Biome rules (import boundaries, import cycles) are replaced by one line: fix a lint violation rather than suppressing it. The rules themselves live in biome.json.

Verification

  • The four checks below were rerun after each merge of main. The second merge (Replace hand-rolled stream handling with Node stream built-ins #1566) conflicted on one import line in docker-container-client.ts.
  • npm run format: no changes.
  • npm run lint and npm run lint:ci: pass.
  • npm run knip: pass.
  • npm run check-compiles: pass.
  • Temporary probe files (deleted before committing) with a function over 50 lines, a console.log and a || default, checked with biome ci --error-on-warnings:
    • under packages/testcontainers/src/ and packages/modules/redis/src/: 3 errors, one per rule
    • as *.test.ts: 2 errors (function length is off)
    • under .github/scripts/ and as packages/testcontainers/smoke-test.*: 2 errors (noConsole does not apply)
  • Tests covering the refactored functions: 7 files, 110 passed and 1 skipped (an existing it.skip).
    npx vitest run \
      packages/testcontainers/src/generic-container/generic-container.test.ts \
      packages/testcontainers/src/generic-container/generic-container-network.test.ts \
      packages/testcontainers/src/docker-compose-environment/docker-compose-environment.test.ts \
      packages/testcontainers/src/wait-strategies/http-wait-strategy.test.ts \
      packages/testcontainers/src/wait-strategies/http-wait-strategy.agent-lifecycle.test.ts \
      packages/testcontainers/src/container-runtime/clients/container/docker-container-client.test.ts \
      packages/modules/azurite/src/azurite-container.test.ts
    
  • npx vitest run packages/modules/couchbase/src/couchbase-container.test.ts, after merging main and splitting createBuckets: 2 of 11 passed locally. The 9 failures are startup timeouts (180 s test timeouts, URL /pools not accessible after 60000ms, URL /admin/ping not accessible after 60000ms), all in waits that run before createBuckets. The run shared a Docker host with other sessions' Couchbase containers at a load average of about 70, and it was not compared with unmodified main under the same load, so it shows neither a pass nor a regression. The Tests (couchbase, ...) jobs on this PR are the evidence for this file. They passed on the first commit, which already had the HttpWaitStrategy refactor those waits go through.
  • Tests for the console and ?? changes:
    • cloudstorage-emulator-container.test.ts, postgresql-container-snapshot.test.ts and generic-container-commit.test.ts together: 12 of 12 pass.
    • postgresql-container.test.ts and valkey-container.test.ts together: 15 of 15 pass.
  • Those five files in one vitest run fail two restart tests, PostgreSqlContainer > should work with restarted container (read ECONNRESET) and ValkeyContainer > should reconnect with volume and persistence data (Socket closed unexpectedly). The same command on unmodified main fails the same two tests with the same errors, so this PR does not cause them.

Not breaking

No public API, export or default changes. The refactors only move statements into private helpers, and the two ?? changes are equivalent for the types involved.

Two things a consumer could notice:

  • The Cloud Storage emulator warning and the PostgreSQL snapshot error were printed to stderr unconditionally. They are now written through the testcontainers debug logger, so they appear with DEBUG=testcontainers*. PostgreSQL still rethrows the error, and the emulator did not throw before either.
  • GenericContainer, AzuriteContainer, CouchbaseContainer, DockerComposeEnvironment and HttpWaitStrategy gain the private methods listed above. A subclass that already declares a member with one of those names would clash. No module in this repository does.

@cristianrgreco cristianrgreco added maintenance Improvements that do not change functionality patch Backward compatible bug fix labels Oct 12, 2026
…tyle-with-biome-d40615

# Conflicts:
#	packages/testcontainers/src/container-runtime/clients/container/docker-container-client.ts
@cristianrgreco
cristianrgreco marked this pull request as ready for review October 12, 2026 18:35
The rules live in biome.json. AGENTS.md keeps only the guidance that config can't express: fix a violation rather than suppressing it.
@cristianrgreco
cristianrgreco merged commit 777015c into main Oct 13, 2026
191 checks passed
@cristianrgreco
cristianrgreco deleted the claude/enforce-code-style-with-biome-d40615 branch October 13, 2026 09:57
cristianrgreco added a commit that referenced this pull request Oct 13, 2026
Resolve conflicts with the Biome rule changes in #1585 and #1590: thread the signal through the extracted exec and HTTP helpers, and move the extracted Couchbase waits to poll.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintenance Improvements that do not change functionality patch Backward compatible bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant