Compare commits

...

3 Commits

Author SHA1 Message Date
Claude Bot
aaa42ab56b fix(types): allow test.todo and describe.todo to accept single string argument
The documentation shows test.todo("description") with a single argument,
but the type definitions required a callback function as the second argument.
This caused TypeScript error TS2554 when following the documentation.

This fix adds TestTodo and DescribeTodo interfaces that support both:
- Single argument: test.todo("unimplemented feature")
- With callback: test.todo("feature", () => { ... })

Fixes #25959

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 09:59:33 +00:00
Alex Miller
beccd01647 fix(FileSink): add Promise<number> to FileSink.write() return type (#25962)
Co-authored-by: Alistair Smith <hi@alistair.sh>
2026-01-11 12:51:16 -08:00
github-actions[bot]
35eb53994a deps: update sqlite to 3.51.200 (#25957)
## What does this PR do?

Updates SQLite to version 3.51.200

Compare: https://sqlite.org/src/vdiff?from=3.51.1&to=3.51.200

Auto-updated by [this
workflow](https://github.com/oven-sh/bun/actions/workflows/update-sqlite3.yml)

Co-authored-by: Jarred-Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2026-01-10 22:46:17 -08:00
5 changed files with 206 additions and 71 deletions

View File

@@ -11,9 +11,9 @@ declare module "bun" {
* If the file descriptor is not writable yet, the data is buffered.
*
* @param chunk The data to write
* @returns Number of bytes written
* @returns Number of bytes written or, if the write is pending, a Promise resolving to the number of bytes
*/
write(chunk: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer): number;
write(chunk: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer): number | Promise<number>;
/**
* Flush the internal buffer, committing the data to disk or the pipe.
*
@@ -78,9 +78,9 @@ declare module "bun" {
* If the network is not writable yet, the data is buffered.
*
* @param chunk The data to write
* @returns Number of bytes written
* @returns Number of bytes written or, if the write is pending, a Promise resolving to the number of bytes
*/
write(chunk: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer): number;
write(chunk: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer): number | Promise<number>;
/**
* Flush the internal buffer, committing the data to the network.
*

View File

@@ -206,6 +206,32 @@ declare module "bun:test" {
type DescribeLabel = number | string | Function | FunctionLike;
/**
* Marks a group of tests as to be written or to be fixed.
*
* When called with only a label, creates a placeholder test group that will be
* shown in test results as "todo". When called with both a label and a function,
* the tests will not be executed unless the `--todo` flag is passed.
*
* @example
* // Placeholder test group - just a label
* describe.todo("unimplemented feature group");
*
* // Test group with implementation that won't run by default
* describe.todo("feature group to fix", () => {
* test("broken test", () => {
* expect(broken()).toBe(true);
* });
* });
*
* @param label the label for the tests
* @param fn optional function that defines the tests
*/
export interface DescribeTodo<T extends Readonly<any[]>> {
(label: DescribeLabel): void;
(label: DescribeLabel, fn: (...args: T) => void): void;
}
/**
* Describes a group of related tests.
*
@@ -238,8 +264,12 @@ declare module "bun:test" {
skip: Describe<T>;
/**
* Marks this group of tests as to be written or to be fixed.
*
* When called with only a label, creates a placeholder test group that will be
* shown in test results as "todo". When called with both a label and a function,
* the tests will not be executed unless the `--todo` flag is passed.
*/
todo: Describe<T>;
todo: DescribeTodo<T>;
/**
* Marks this group of tests to be executed concurrently.
*/
@@ -442,6 +472,39 @@ declare module "bun:test" {
type Flatten<T, Copy extends T = T> = { [Key in keyof T]: Copy[Key] };
}
/**
* Marks a test as to be written or to be fixed.
*
* When called with only a test name, creates a placeholder test that will be
* shown in test results as "todo". When called with both a name and a function,
* the test will not be executed unless the `--todo` flag is passed.
*
* @example
* // Placeholder test - just a name
* test.todo("unimplemented feature");
*
* // Test with implementation that won't run by default
* test.todo("feature to fix", () => {
* expect(broken()).toBe(true);
* });
*
* @param label the label for the test
* @param fn optional test function
* @param options optional test timeout or options
*/
export interface TestTodo<T extends ReadonlyArray<unknown>> {
(label: string): void;
(
label: string,
fn: (
...args: __internal.IsTuple<T> extends true
? [...table: __internal.Flatten<T>, done: (err?: unknown) => void]
: T
) => void | Promise<unknown>,
options?: number | TestOptions,
): void;
}
/**
* Runs a test.
*
@@ -495,12 +558,13 @@ declare module "bun:test" {
/**
* Marks this test as to be written or to be fixed.
*
* These tests will not be executed unless the `--todo` flag is passed. With the flag,
* When called with only a test name, creates a placeholder test that will be
* shown in test results as "todo". When called with both a name and a function,
* the test will not be executed unless the `--todo` flag is passed. With the flag,
* if the test passes, the test will be marked as `fail` in the results; you will have to
* remove the `.todo` or check that your test
* is implemented correctly.
* remove the `.todo` or check that your test is implemented correctly.
*/
todo: Test<T>;
todo: TestTodo<T>;
/**
* Marks this test as failing.
*

View File

@@ -1,7 +1,7 @@
// clang-format off
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
** version 3.51.1. By combining all the individual C code files into this
** version 3.51.2. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements
@@ -19,7 +19,7 @@
** separate file. This file contains only code for the core SQLite library.
**
** The content in this amalgamation comes from Fossil check-in
** 281fc0e9afc38674b9b0991943b9e9d1e64c with changes in files:
** b270f8339eb13b504d0b2ba154ebca966b7d with changes in files:
**
**
*/
@@ -469,12 +469,12 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.51.1"
#define SQLITE_VERSION_NUMBER 3051001
#define SQLITE_SOURCE_ID "2025-11-28 17:28:25 281fc0e9afc38674b9b0991943b9e9d1e64c6cbdb133d35f6f5c87ff6af38a88"
#define SQLITE_VERSION "3.51.2"
#define SQLITE_VERSION_NUMBER 3051002
#define SQLITE_SOURCE_ID "2026-01-09 17:27:48 b270f8339eb13b504d0b2ba154ebca966b7dde08e40c3ed7d559749818cb2075"
#define SQLITE_SCM_BRANCH "branch-3.51"
#define SQLITE_SCM_TAGS "release version-3.51.1"
#define SQLITE_SCM_DATETIME "2025-11-28T17:28:25.933Z"
#define SQLITE_SCM_TAGS "release version-3.51.2"
#define SQLITE_SCM_DATETIME "2026-01-09T17:27:48.405Z"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -41230,12 +41230,18 @@ static int unixLock(sqlite3_file *id, int eFileLock){
pInode->nLock++;
pInode->nShared = 1;
}
}else if( (eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1)
|| unixIsSharingShmNode(pFile)
){
}else if( eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1 ){
/* We are trying for an exclusive lock but another thread in this
** same process is still holding a shared lock. */
rc = SQLITE_BUSY;
}else if( unixIsSharingShmNode(pFile) ){
/* We are in WAL mode and attempting to delete the SHM and WAL
** files due to closing the connection or changing out of WAL mode,
** but another process still holds locks on the SHM file, thus
** indicating that database locks have been broken, perhaps due
** to a rogue close(open(dbFile)) or similar.
*/
rc = SQLITE_BUSY;
}else{
/* The request was for a RESERVED or EXCLUSIVE lock. It is
** assumed that there is a SHARED or greater lock on the file
@@ -43874,26 +43880,21 @@ static int unixFcntlExternalReader(unixFile *pFile, int *piOut){
** still not a disaster.
*/
static int unixIsSharingShmNode(unixFile *pFile){
int rc;
unixShmNode *pShmNode;
struct flock lock;
if( pFile->pShm==0 ) return 0;
if( pFile->ctrlFlags & UNIXFILE_EXCL ) return 0;
pShmNode = pFile->pShm->pShmNode;
rc = 1;
unixEnterMutex();
if( ALWAYS(pShmNode->nRef==1) ){
struct flock lock;
lock.l_whence = SEEK_SET;
lock.l_start = UNIX_SHM_DMS;
lock.l_len = 1;
lock.l_type = F_WRLCK;
osFcntl(pShmNode->hShm, F_GETLK, &lock);
if( lock.l_type==F_UNLCK ){
rc = 0;
}
}
unixLeaveMutex();
return rc;
#if SQLITE_ATOMIC_INTRINSICS
assert( AtomicLoad(&pShmNode->nRef)==1 );
#endif
memset(&lock, 0, sizeof(lock));
lock.l_whence = SEEK_SET;
lock.l_start = UNIX_SHM_DMS;
lock.l_len = 1;
lock.l_type = F_WRLCK;
osFcntl(pShmNode->hShm, F_GETLK, &lock);
return (lock.l_type!=F_UNLCK);
}
/*
@@ -115318,9 +115319,22 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
pParse->nMem += nReg;
if( pExpr->op==TK_SELECT ){
dest.eDest = SRT_Mem;
dest.iSdst = dest.iSDParm;
if( (pSel->selFlags&SF_Distinct) && pSel->pLimit && pSel->pLimit->pRight ){
/* If there is both a DISTINCT and an OFFSET clause, then allocate
** a separate dest.iSdst array for sqlite3Select() and other
** routines to populate. In this case results will be copied over
** into the dest.iSDParm array only after OFFSET processing. This
** ensures that in the case where OFFSET excludes all rows, the
** dest.iSDParm array is not left populated with the contents of the
** last row visited - it should be all NULLs if all rows were
** excluded by OFFSET. */
dest.iSdst = pParse->nMem+1;
pParse->nMem += nReg;
}else{
dest.iSdst = dest.iSDParm;
}
dest.nSdst = nReg;
sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, dest.iSDParm+nReg-1);
sqlite3VdbeAddOp3(v, OP_Null, 0, dest.iSDParm, pParse->nMem);
VdbeComment((v, "Init subquery result"));
}else{
dest.eDest = SRT_Exists;
@@ -148188,9 +148202,14 @@ static void selectInnerLoop(
assert( nResultCol<=pDest->nSdst );
pushOntoSorter(
pParse, pSort, p, regResult, regOrig, nResultCol, nPrefixReg);
pDest->iSDParm = regResult;
}else{
assert( nResultCol==pDest->nSdst );
assert( regResult==iParm );
if( regResult!=iParm ){
/* This occurs in cases where the SELECT had both a DISTINCT and
** an OFFSET clause. */
sqlite3VdbeAddOp3(v, OP_Copy, regResult, iParm, nResultCol-1);
}
/* The LIMIT clause will jump out of the loop for us */
}
break;
@@ -154205,12 +154224,24 @@ static SQLITE_NOINLINE void existsToJoin(
&& (pSub->selFlags & SF_Aggregate)==0
&& !pSub->pSrc->a[0].fg.isSubquery
&& pSub->pLimit==0
&& pSub->pPrior==0
){
/* Before combining the sub-select with the parent, renumber the
** cursor used by the subselect. This is because the EXISTS expression
** might be a copy of another EXISTS expression from somewhere
** else in the tree, and in this case it is important that it use
** a unique cursor number. */
sqlite3 *db = pParse->db;
int *aCsrMap = sqlite3DbMallocZero(db, (pParse->nTab+2)*sizeof(int));
if( aCsrMap==0 ) return;
aCsrMap[0] = (pParse->nTab+1);
renumberCursors(pParse, pSub, -1, aCsrMap);
sqlite3DbFree(db, aCsrMap);
memset(pWhere, 0, sizeof(*pWhere));
pWhere->op = TK_INTEGER;
pWhere->u.iValue = 1;
ExprSetProperty(pWhere, EP_IntValue);
assert( p->pWhere!=0 );
pSub->pSrc->a[0].fg.fromExists = 1;
pSub->pSrc->a[0].fg.jointype |= JT_CROSS;
@@ -174003,6 +174034,9 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
sqlite3 *db = pParse->db;
int iEnd = sqlite3VdbeCurrentAddr(v);
int nRJ = 0;
#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
int addrSeek = 0;
#endif
/* Generate loop termination code.
*/
@@ -174015,7 +174049,10 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
** the RIGHT JOIN table */
WhereRightJoin *pRJ = pLevel->pRJ;
sqlite3VdbeResolveLabel(v, pLevel->addrCont);
pLevel->addrCont = 0;
/* Replace addrCont with a new label that will never be used, just so
** the subsequent call to resolve pLevel->addrCont will have something
** to resolve. */
pLevel->addrCont = sqlite3VdbeMakeLabel(pParse);
pRJ->endSubrtn = sqlite3VdbeCurrentAddr(v);
sqlite3VdbeAddOp3(v, OP_Return, pRJ->regReturn, pRJ->addrSubrtn, 1);
VdbeCoverage(v);
@@ -174024,7 +174061,6 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
pLoop = pLevel->pWLoop;
if( pLevel->op!=OP_Noop ){
#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
int addrSeek = 0;
Index *pIdx;
int n;
if( pWInfo->eDistinct==WHERE_DISTINCT_ORDERED
@@ -174047,25 +174083,26 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
sqlite3VdbeAddOp2(v, OP_Goto, 1, pLevel->p2);
}
#endif /* SQLITE_DISABLE_SKIPAHEAD_DISTINCT */
if( pTabList->a[pLevel->iFrom].fg.fromExists && i==pWInfo->nLevel-1 ){
/* If the EXISTS-to-JOIN optimization was applied, then the EXISTS
** loop(s) will be the inner-most loops of the join. There might be
** multiple EXISTS loops, but they will all be nested, and the join
** order will not have been changed by the query planner. If the
** inner-most EXISTS loop sees a single successful row, it should
** break out of *all* EXISTS loops. But only the inner-most of the
** nested EXISTS loops should do this breakout. */
int nOuter = 0; /* Nr of outer EXISTS that this one is nested within */
while( nOuter<i ){
if( !pTabList->a[pLevel[-nOuter-1].iFrom].fg.fromExists ) break;
nOuter++;
}
testcase( nOuter>0 );
sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel[-nOuter].addrBrk);
VdbeComment((v, "EXISTS break"));
}
if( pTabList->a[pLevel->iFrom].fg.fromExists && i==pWInfo->nLevel-1 ){
/* If the EXISTS-to-JOIN optimization was applied, then the EXISTS
** loop(s) will be the inner-most loops of the join. There might be
** multiple EXISTS loops, but they will all be nested, and the join
** order will not have been changed by the query planner. If the
** inner-most EXISTS loop sees a single successful row, it should
** break out of *all* EXISTS loops. But only the inner-most of the
** nested EXISTS loops should do this breakout. */
int nOuter = 0; /* Nr of outer EXISTS that this one is nested within */
while( nOuter<i ){
if( !pTabList->a[pLevel[-nOuter-1].iFrom].fg.fromExists ) break;
nOuter++;
}
/* The common case: Advance to the next row */
if( pLevel->addrCont ) sqlite3VdbeResolveLabel(v, pLevel->addrCont);
testcase( nOuter>0 );
sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel[-nOuter].addrBrk);
VdbeComment((v, "EXISTS break"));
}
sqlite3VdbeResolveLabel(v, pLevel->addrCont);
if( pLevel->op!=OP_Noop ){
sqlite3VdbeAddOp3(v, pLevel->op, pLevel->p1, pLevel->p2, pLevel->p3);
sqlite3VdbeChangeP5(v, pLevel->p5);
VdbeCoverage(v);
@@ -174078,10 +174115,11 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
VdbeCoverage(v);
}
#ifndef SQLITE_DISABLE_SKIPAHEAD_DISTINCT
if( addrSeek ) sqlite3VdbeJumpHere(v, addrSeek);
if( addrSeek ){
sqlite3VdbeJumpHere(v, addrSeek);
addrSeek = 0;
}
#endif
}else if( pLevel->addrCont ){
sqlite3VdbeResolveLabel(v, pLevel->addrCont);
}
if( (pLoop->wsFlags & WHERE_IN_ABLE)!=0 && pLevel->u.in.nIn>0 ){
struct InLoop *pIn;
@@ -219471,7 +219509,7 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
if( node.zData==0 ) return;
nData = sqlite3_value_bytes(apArg[1]);
if( nData<4 ) return;
if( nData<NCELL(&node)*tree.nBytesPerCell ) return;
if( nData<4+NCELL(&node)*tree.nBytesPerCell ) return;
pOut = sqlite3_str_new(0);
for(ii=0; ii<NCELL(&node); ii++){
@@ -238552,7 +238590,13 @@ typedef sqlite3_uint64 u64;
# define FLEXARRAY 1
#endif
#endif
#endif /* SQLITE_AMALGAMATION */
/*
** Constants for the largest and smallest possible 32-bit signed integers.
*/
# define LARGEST_INT32 ((int)(0x7fffffff))
# define SMALLEST_INT32 ((int)((-1) - LARGEST_INT32))
/* Truncate very long tokens to this many bytes. Hard limit is
** (65536-1-1-4-9)==65521 bytes. The limiting factor is the 16-bit offset
@@ -253115,7 +253159,7 @@ static int sqlite3Fts5IndexMerge(Fts5Index *p, int nMerge){
fts5StructureRelease(pStruct);
pStruct = pNew;
nMin = 1;
nMerge = nMerge*-1;
nMerge = (nMerge==SMALLEST_INT32 ? LARGEST_INT32 : (nMerge*-1));
}
if( pStruct && pStruct->nLevel ){
if( fts5IndexMerge(p, &pStruct, nMerge, nMin) ){
@@ -260322,7 +260366,7 @@ static void fts5SourceIdFunc(
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
sqlite3_result_text(pCtx, "fts5: 2025-11-28 17:28:25 281fc0e9afc38674b9b0991943b9e9d1e64c6cbdb133d35f6f5c87ff6af38a88", -1, SQLITE_TRANSIENT);
sqlite3_result_text(pCtx, "fts5: 2026-01-09 17:27:48 b270f8339eb13b504d0b2ba154ebca966b7dde08e40c3ed7d559749818cb2075", -1, SQLITE_TRANSIENT);
}
/*

View File

@@ -147,12 +147,12 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.51.1"
#define SQLITE_VERSION_NUMBER 3051001
#define SQLITE_SOURCE_ID "2025-11-28 17:28:25 281fc0e9afc38674b9b0991943b9e9d1e64c6cbdb133d35f6f5c87ff6af38a88"
#define SQLITE_VERSION "3.51.2"
#define SQLITE_VERSION_NUMBER 3051002
#define SQLITE_SOURCE_ID "2026-01-09 17:27:48 b270f8339eb13b504d0b2ba154ebca966b7dde08e40c3ed7d559749818cb2075"
#define SQLITE_SCM_BRANCH "branch-3.51"
#define SQLITE_SCM_TAGS "release version-3.51.1"
#define SQLITE_SCM_DATETIME "2025-11-28T17:28:25.933Z"
#define SQLITE_SCM_TAGS "release version-3.51.2"
#define SQLITE_SCM_DATETIME "2026-01-09T17:27:48.405Z"
/*
** CAPI3REF: Run-Time Library Version Numbers

View File

@@ -0,0 +1,27 @@
import { describe, expect, test } from "bun:test";
// https://github.com/oven-sh/bun/issues/25959
// test.todo and describe.todo should accept a single string argument
// Test.todo with single argument - the reported issue
test.todo("unimplemented feature");
// Test.todo with callback - should still work
test.todo("feature with callback that would fail", () => {
expect(1).toBe(2);
});
// describe.todo with single argument
describe.todo("unimplemented feature group");
// describe.todo with callback - should still work
describe.todo("feature group with callback", () => {
test("nested test that would fail", () => {
expect(1).toBe(2);
});
});
// Regular test to make the file run
test("this test passes", () => {
expect(true).toBe(true);
});